首页 > 其他分享 >Golang调用Dll案例

Golang调用Dll案例

时间:2023-05-11 22:56:09浏览次数:43  
标签:调用 lc int dll Golang playParam PlayParam Dll struct

Golang调用Dll案例

前言

在家办公已经两个多星期了,目前最大的困难就是网络很差。独自一个人用golang开发调用dll的驱动程序。本来就是半桶水的我,还在为等待打开一个页面而磨平了耐心。本想依葫芦画瓢把这个驱动做了。可网上找到的案例都是一些简单的调用dll。对于各种传参、获取返回值和一些常见错误的文章太少(可能因为网络不好一些优质文章还没有点开就被关掉了)。今天ITDragon就做一个简单的葫,以广播驱动作为案例。

1.The specified module could not be found.

2.%1 is not a valid Win32 application.

3.The operation completed successfully.

4.error: unknown type name 'HWND'、'DWORD'.

5.获取dll返回的结构体

6.dll传参unsigned char* argName, struct _PlayParam* pParam

调用LCAudioThrDll 案例

ITDragon龙 先画一个葫芦。这个dll是在做广播驱动时用到,列举了其中几个有代表性的方法介绍。

package main

/*
#include <stdlib.h>
typedef struct _PlayParam
{
	long hWnd;						//主窗口的句柄,如果不为0,则线程有事件会向该窗口发送消息
	int Priority;					//优先级
	int MultiGroup;					//多播组号
	int	CastMode;					//传输模式,单播,多播,广播
	long IP;						//ip,如果是广播和多播,此参数是源网卡的IP,如果此地址为0,则由系统决定使用哪个网卡,如果是单播,这是个目标设备的ip地址。
	int   Volume;					//播放音量取值0~100
	int	  Tone;						//音调
	int   Treble;					//高音频率
	int   Bass;						//低音频率
	int   Treble_En;				//高音增益
	int   Bass_En;					//低音增益
	unsigned short   SourceType;	//输入源,0为文件,1为声卡
	unsigned short   OptionByte;	//选项字,默认为0;bit0=1 禁止重采样,bit1=1,启动监听,bit2=1,禁用解码功能(仅播放符合要求的音频文件)
	int DeviceID;					//音频输入ID号 1~N
	int MaxBitrate;					//允许最大的比特率组合,如果源文件高于此比特率,将被重压缩至此比特率。
	unsigned int Option[15];		//选项
	int nChannels;					//采样的通道 1~2 CodecType
	int nSamplesPerSec;				//采样频率 8K,11.025K,22.05K,44.1K
	int AudioBufferLength;			//Audio数据的长度
	unsigned char* AudioBuf;		//Audio数据的指针
	unsigned int PrivateData[128];	//私有信息,lc_init初始化后,用户不能修改里面的内容。
}PlayParam;
*/
import "C"
import (
	"fmt"
	"os"
	"strconv"
	"strings"
	"syscall"
	"unicode"
	"unsafe"
)

/*
struct _PlayParam* __stdcall lc_play_getmem (void);
int __stdcall lc_init(unsigned char* pFileName, struct _PlayParam* pParam);
int __stdcall lc_play(struct _PlayParam* pParam);
int __stdcall lc_set_volume(struct _PlayParam* pParam, char volume);
int __stdcall lc_addip (struct _PlayParam* pParam,DWORD ip);
*/

var (
	lcAudioSdk, _               = syscall.LoadDLL("LCAudioThrDll.dll")
	lcAudioSdkPlayGetMemFunc, _ = lcAudioSdk.FindProc("lc_play_getmem")
	lcAudioSdkInitFunc, _       = lcAudioSdk.FindProc("lc_init")
	lcAudioSdkPlayFunc, _       = lcAudioSdk.FindProc("lc_play")
	lcAudioSdkSetVolumeFunc, _  = lcAudioSdk.FindProc("lc_set_volume")
	lcAudioSdkAddIPFunc, _      = lcAudioSdk.FindProc("lc_addip")
)

func main() {
	filePath := `D:\upload\attachment\20200217115847582_-581698856.mp3`
	if IsIllegalFile(filePath) {
		return
	}

	audioSource := C.CString(filePath)
	defer C.free(unsafe.Pointer(audioSource))
	var playParam *C.PlayParam
	/**
	step1 	申请PlayParam内存
			1. 无参
			2. 获取并转换dll 返回结构体指针
	*/
	playParamMem, _, _ := lcAudioSdkPlayGetMemFunc.Call()
	playParam = (*C.PlayParam)(unsafe.Pointer(playParamMem))
	playParam.Volume = 80
	playParam.SourceType = 0
	playParam.CastMode = 0
	playParam.IP = C.long(ipAddrToInt("127.0.0.1"))

	/**
	step2 	初始化客户端
			1. 入参是unsigned char* 和 struct _PlayParam*
			2. 获取并转换dll 返回int类型
	*/
	initResult, _, _ := lcAudioSdkInitFunc.Call(uintptr(unsafe.Pointer(audioSource)), uintptr(unsafe.Pointer(playParam)))
	fmt.Println("lcaudio init result : ", int32(initResult))

	/**
	step3 	播放音频
			1. 入参是struct _PlayParam*
			2. 获取并转换dll 返回int类型
	*/
	playResult, _, _ := lcAudioSdkPlayFunc.Call(uintptr(unsafe.Pointer(playParam)))
	fmt.Println("lcaudio play result : ", int32(playResult))

	/**
	step4 	调整音量
			1. 入参是struct _PlayParam* 和 char (疑惑)
			2. 获取并转换dll 返回int类型
	*/
	volumeResult, _, _ := lcAudioSdkSetVolumeFunc.Call(uintptr(unsafe.Pointer(playParam)), uintptr(90))
	fmt.Println("lcaudio set volume result : ", int32(volumeResult))

	/**
	step5 	单播模式添加IP设备
			1. 入参是struct _PlayParam* 和 DWORD
			2. 获取并转换dll 返回int类型
	*/
	addIpResult, _, _ := lcAudioSdkAddIPFunc.Call(uintptr(unsafe.Pointer(playParam)), uintptr(C.long(ipAddrToInt("192.168.0.5"))))
	fmt.Println("lcaudio add ip result : ", int32(addIpResult))

}

// ip地址转16进制
func ipAddrToInt(ipAddr string) int {
	bits := strings.Split(ipAddr, ".")
	b0, _ := strconv.Atoi(bits[0])
	b1, _ := strconv.Atoi(bits[1])
	b2, _ := strconv.Atoi(bits[2])
	b3, _ := strconv.Atoi(bits[3])
	var sum int
	sum += int(b0) << 24
	sum += int(b1) << 16
	sum += int(b2) << 8
	sum += int(b3)

	return sum
}

// 文件校验
func IsIllegalFile(filePath string) bool {
	if IsChineseChar(filePath) {
		return true
	}
	if !PathExists(filePath) {
		return true
	}

	return false
}

func IsChineseChar(str string) bool {
	for _, r := range str {
		if unicode.Is(unicode.Scripts["Han"], r) {
			return true
		}
	}
	return false
}

func PathExists(path string) bool {
	_, err := os.Stat(path)
	if err == nil {
		return true
	}
	if os.IsNotExist(err) {
		return false
	}
	return false
}

填坑

1. The specified module could not be found.

在执行syscall.LoadDLL时报错。如果报这个错,可以考虑从两个方面找问题:

第一:有可能是dll路径不对。

第二:有可能是当前dll所需要的其他dll丢失。

第一种情况很好解决,换一个全英文路径试一试。第二种情况需要借助DependenciesGui工具查找dll的依赖项。不推荐用depends22这个工具。将缺失的dll下载并放在当前dll同一层目录即可(或者放在系统目录),只要黄色感叹号消失即可。

2. %1 is not a valid Win32 application.

一般是在64位下执行32位的dll会出现这种情况,配置编译环境即可。GOARCH=386;CGO_ENABLED=1

3. The operation completed successfully.

在执行.Call()方法会返回三个参数。其中第三个参数就是error。并且这个error始终不为nil,打印的错误信息是操作已完成???

标签:调用,lc,int,dll,Golang,playParam,PlayParam,Dll,struct
From: https://www.cnblogs.com/jiftle/p/17392491.html

相关文章

  • golang调用dll,windows
    使用syscall.LoadLibrary(dllPath)函数加载dll,syscall.Syscall(...)函数调用具体的函数接口funcGoCallDll1(a,bint)uintptr{ dllFile:=syscall.NewLazyDLL(dllFileName) fmt.Println("dll:",dllFile.Name) add:=dllFile.NewProc("add") fmt.Println("......
  • web调用PC摄像头进行视频录制
    在项目中我们很多时候都会遇到使用浏览器调用电脑设备的需求,记录一下实现思路及方法,共享一下技术点,同时也方便日后查看和整理web浏览器在设计的时候为我们提供了很多的API接口实现功能,我们这次使用web调用PC摄像头和录音设备,主要思路是:获取到设备的媒体流,再将媒体流进行转存。......
  • vue3 setup 父页面调用子组件及子组件调用父页面方法的DEMO
    父页面调用子组件中方法父页面<template><div><!--第四步:页面使用子组件,并添加ref属性,注意ref属性不能和子组件重名--><role-cardref="roleRef"></role-card></div></template><scriptlang="ts"setup>import{ref......
  • R语言中调用调用python
       ......
  • c# 调用webapi的几种方式
     HttpHelper帮助类publicstaticclassHttphelper{//Post请求publicstaticstringPostResponse(stringurl,stringpostData,outstringstatusCode){stringresult=string.Empty;//设置Http的正文......
  • 移相全桥控制算法的C代码+仿真模型,电压单闭环,电压外环电流内环双闭环,采用S函数调用的
    移相全桥控制算法的C代码+仿真模型,电压单闭环,电压外环电流内环双闭环,采用S函数调用的方式直接在simulnik环境下对C代码进行仿真。已经在样机上验证过,波形非常好!ID:2560680754811245......
  • Golang for循环遍历小坑
    一、for循环循环:让程序多次执行相同的代码块for循环是Go语言中唯一一个循环结构for循环经典语法先执行表达式1执行表达式2判断是否成立,如果成立执行循环体循环体执行完成后,执行表达式3再次执行表达式2,判断是否成立.for循环用的最多的地方就是遍历数组或切片等for表达式1......
  • Go语言(Golang)数据库编程
    Go数据库编程一、连接数据库准备连接到数据库要想连接到SQL数据库,首先需要加载目标数据库的驱动,驱动里面包含着于该数据库交互的逻辑。sql.Open()数据库驱动的名称数据源名称得到一个指向sql.DB这个struct的指针sql.DB是用来操作数据库的,它代表了0个或者多个......
  • golang在编译测试时使用ldflags动态设置包中变量的值
    Example: mkdir$GOPATH/src/gotest/touchgo_test.go packagegotestimport"testing"vartimestringvarversionstringfuncTestBuild(t*testing.T){t.Log(time)t.Log(version)} ReadMe.txtgotest-ldflags="-X'gotest......
  • Golang刷题日志--岛屿问题
    1.给你一个由'1'(陆地)和'0'(水)组成的的二维网格,请你计算网格中岛屿的数量。岛屿总是被水包围,并且每座岛屿只能由水平方向和/或竖直方向上相邻的陆地连接形成。此外,你可以假设该网格的四条边均被水包围。示例代码:import"fmt"funcnumIsIands(grid[][]byte)int{ //记录岛......