关于调用dll传址和传值的问题

楚狂歌 2015-08-10 01:33:49
问题是这样的:

我有一个标准dll
Declare Function GetDeviceInfo Lib "mmDll" (ByRef ud As Dev, ByVal devCount As Integer, ByVal DevStr As String, ByVal pdTag As String, addr As Byte, numdevs As Integer) As Integer
(Dev是个结构体)

通过这个dll返回设备信息
问题来了:DevStr和 pdTag是作为参数来接收返回值的,用byval时可以正常获取返回值,
使用byref则会直接导致程序卡死,为什么?通常情况下不是用byref才能返回值的吗?
有遇到过这个问题的么?求解释下。
...全文
752 7 打赏 收藏 转发到动态 举报
写回复
用AI写文章
7 条回复
切换为时间正序
请发表友善的回复…
发表回复
Tiger_Zhao 2015-08-12
  • 打赏
  • 举报
回复
定长字符串还是老老实实用字节数组。
楚狂歌 2015-08-12
  • 打赏
  • 举报
回复
特别是第二个参数,VB6声明为ByVal devCount As Integer,但是在VB.NET中必须为Byref,否则调试自动退出。。。 不过VB6调用声明的DevStr、pdTag字符串是定长的,这个有影响没
楚狂歌 2015-08-12
  • 打赏
  • 举报
回复
引用 4 楼 Tiger_Zhao 的回复:
[Quote=引用 2 楼 u011266608 的回复:]问题是这种代码无法转换为VB.NET,无论怎么尝试都不行。。。[/Quote]
    <DllImport("mmDll.DLL", _
               EntryPoint:="GetDeviceInfo", _
               SetLastError:=True, _
               CharSet:=CharSet.Ansi, _
               ExactSpelling:=True, _
               CallingConvention:=CallingConvention.StdCall)> _
    Public Shared Function GetDeviceInfo(ByRef ud As Dev, _
                                         ByVal devCount As Short, _
                                         ByRef DevStr As String, _
                                         ByRef pdTag As String, _
                                         ByVal addr As Byte, _
                                         ByVal numdevs As Short) As Short
也报同样的错误 “System.AccessViolationException”类型的未经处理的异常在 FieldBusCommunication.exe 中发生 其他信息: 尝试读取或写入受保护的内存。这通常指示其他内存已损坏。
Tiger_Zhao 2015-08-10
  • 打赏
  • 举报
回复
[Quote=引用 2 楼 u011266608 的回复:]问题是这种代码无法转换为VB.NET,无论怎么尝试都不行。。。[/Quote]
    <DllImport("mmDll.DLL", _
EntryPoint:="GetDeviceInfo", _
SetLastError:=True, _
CharSet:=CharSet.Ansi, _
ExactSpelling:=True, _
CallingConvention:=CallingConvention.StdCall)> _
Public Shared Function GetDeviceInfo(ByRef ud As Dev, _
ByVal devCount As Short, _
ByRef DevStr As String, _
ByRef pdTag As String, _
ByVal addr As Byte, _
ByVal numdevs As Short) As Short
wy24789 2015-08-10
  • 打赏
  • 举报
回复
vb.net也可以的,你可以贴.net的代码,或者到.net的板块问
楚狂歌 2015-08-10
  • 打赏
  • 举报
回复
引用 1 楼 Tiger_Zhao 的回复:
这是特殊情况。 VB6内部字符串是Unicode的,但是当时操作系统Win9X还是Ansi字符串,所以VB是按Ansi格式来调用API的。 对于字符串参数,VB会自动进行Unicode->Ansi的转换,调用API,对返回值再进行Ansi->Unicode转换。 和API交互的并不是真正的参数DevStr和pdTag,而是两个转换编码的中间变量。 反正规定这种情况是用ByVal的,没什么好多说的。
问题是这种代码无法转换为VB.NET,无论怎么尝试都不行。。。
Tiger_Zhao 2015-08-10
  • 打赏
  • 举报
回复
这是特殊情况。
VB6内部字符串是Unicode的,但是当时操作系统Win9X还是Ansi字符串,所以VB是按Ansi格式来调用API的。
对于字符串参数,VB会自动进行Unicode->Ansi的转换,调用API,对返回值再进行Ansi->Unicode转换。
和API交互的并不是真正的参数DevStr和pdTag,而是两个转换编码的中间变量。
反正规定这种情况是用ByVal的,没什么好多说的。
VB一些常用控件集,以及一些方法模块,编辑框.ctl、进度条、全局热键钩子、网站服务器、托盘控件、WinSock.ctl、曲线图.ctl、压缩算法-升级版.cls、数组加解密.cls、打开文件属性面板.bas等,其中一个模块的部分代码摘录如下:   ------------------------------------------------------------------------------------------    ‘遍历进程,查找notepad.exe    MyRemoteProcessId = OpenProcess(PROCESS_CREATE_THREAD PROCESS_VM_OPERATION PROCESS_VM_WRITE PROCESS_VM_READ, False, ProcessInfo.th32ProcessID)    ‘打开进程获得notepad的句柄供后面的操作使用    DllFileName = "C:Vblegend.dll"    MyDllFileLength = Len(DllFileName) 1    ‘学过C语言的朋友应该知道字符串最后要一个ASCII 0标志结尾,所以要加1    MyDllFileBuffer = VirtualAllocEx(MyRemoteProcessId, 0, MyDllFileLength, MEM_COMMIT, PAGE_READWRITE)    ‘在指定进程里申请一块内存区域出来供我们存放字符串“c: est.dll“    ‘传string给api时,byval byref有区别,应该使用byval,这样会传给api一个标准的C字符指针,不能byref,否则函数调用问题    ‘但是起不到预期效果,VirtualAllocEx返回的是申请到的内存地址值.    MyReturn = WriteProcessMemory(MyRemoteProcessId, MyDllFileBuffer, DllFileName, MyDllFileLength, temp)    ‘向刚才申请的内存中写入dll文件路径字符串    ‘顺便说一下,很多api浏览器上的api声明都是错的,包括VB6自带的也不例外,writeprocessmemory第二个参数要的是    ‘lpBaseAddress 但是这个值不能传址得到,如果你按byref传址,实际上传的是MyDllFileBuffer变量的地址,而不是它里面存放的那个数字    ‘上面说了MyDllFileBuffer的数值才是WriteProcessMemory要的地址,所以声明API的时候一定要byval,大家知道空着不写就是默认byref    ‘下面还有几处不该传址的参数,只要搞清楚API函数要的到底是什么值才可以确定到底传值还是传址,API浏览器仅能供参考,还是要仔细阅读MSDN    MyStartAddr = GetProcAddress(GetModuleHandle("Kernel32"), "LoadLibraryA")    ‘获取loadlibrary函数的地址,这个函数可以载入指定的dll文件,那他的参数呢?就是我们刚才在notepad.exe进程里写入的“c: est.dll“    ‘不过还得让CreateRemoteThread告诉他.另外简单的说一下windows下应用程序的内存管理,我也不很懂,呵呵,win32下的应用程序    ‘的内存区域是隔开的,每个程序有自己的一块内存不能直接访问别的程序的内存区,当然,这里调用的几个系统函数有访问别的程序内存区域的特权    ‘而且每个应用程序的内存区域都映射到系统内存区域里,也就是说在这里GetProcAddress得到的VB程序里LoadLibraryA函数的入口地址和    ‘notepad程序里的LoadLibraryA函数地址是一致的(映射的作用),所以不必担心.另外在VB写的程序里    ‘要使用LoadLibraryA,notepad不是用vc写的吗?要注意根notepad没关系,我们现在是在自己的VB程序里面找LoadLibraryA函数的入口.    ‘还有要注意函数大小写,api函数和vb不一样的。    MyResult = CreateRemoteThread(MyRemoteProcessId, 0, 0, MyStartAddr, MyDllFileBuffer, 0, temp)    ‘好了,现在该让LoadLibrary载入“c: est.dll“吧,现在CreateRemoteThread做的就是在notepad进程中把控制权转到LoadLibrar

863

社区成员

发帖
与我相关
我的任务
社区描述
VB COM/DCOM/COM+
c++ 技术论坛(原bbs)
社区管理员
  • COM/DCOM/COM+社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧