为何AutoIT调用WTSVirtualChannelOpenEx失败,而C++调用成功?
AutoIT调用WTSVirtualChannelOpenEx失败的原因分析
我尝试使用AutoIT从动态链接库调用WTSVirtualChannelOpenEx函数,但始终遇到错误。经测试,以下C++代码调用该函数可成功获得非空的有效句柄hnd:
LPSTR fname = (char*)"BPAuto"; HMODULE mod = LoadLibraryA("wtsapi32.dll"); channelopen = (channelopenFunc) GetProcAddress(mod, "WTSVirtualChannelOpenEx"); HANDLE hnd = channelopen(WTS_CURRENT_SESSION, fname, 0);
但使用AutoIT执行相同操作时却失败:
$dll_handle = DllOpen($path) ; 句柄有效,@error为0 $handle=DllCall($dll_handle, "handle", "WTSVirtualChannelOpenEx", "dword", 0xffffffff, "lpstr", "BPAuto", "dword", 0) ; handle为0,@error为1
核心差异与失败原因
- API函数名的实际导出版本问题
Windows系统中,带字符串参数的API通常会提供ANSI(A后缀)和Unicode(W后缀)两个版本,WTSVirtualChannelOpenEx只是一个宏定义:
- 在ANSI编译的C++代码中,该宏会自动展开为
WTSVirtualChannelOpenExA,因此GetProcAddress能正确找到对应的导出函数。 - 而AutoIT中直接使用
WTSVirtualChannelOpenEx作为函数名时,DLL中并没有这个导出项,导致DllCall无法定位函数,触发@error=1。
AutoIT的DllCall返回值处理错误
AutoIT的DllCall返回的是一个数组,数组的第一个元素才是函数的返回值。你直接将整个数组赋值给$handle并判断是否为0,这是错误的用法,正确的做法是提取数组的第一个元素来获取句柄。调用约定的隐性匹配
C++中使用WINAPI(即stdcall)定义函数指针,而AutoIT的DllCall默认使用stdcall调用约定,这一点是匹配的,但如果函数名错误,这一点就无从谈起。
修复后的AutoIT代码示例
$path = "wtsapi32.dll" $dll_handle = DllOpen($path) If $dll_handle = -1 Then MsgBox(0, "错误", "无法打开DLL") Exit EndIf ; 使用正确的ANSI版本函数名 $ret = DllCall($dll_handle, "handle", "WTSVirtualChannelOpenExA", "dword", 0xFFFFFFFF, "lpstr", "BPAuto", "dword", 0) If @error = 0 Then $handle = $ret[0] If $handle <> 0 Then MsgBox(0, "成功", "获取到有效句柄: " & $handle) Else MsgBox(0, "失败", "获取句柄为空") EndIf Else MsgBox(0, "错误", "DllCall执行失败,错误码: " & @error) EndIf DllClose($dll_handle)
内容的提问来源于stack exchange,提问作者viraptor
相关产品推荐
相关产品推荐

