曾经回答过几个相似的问题,那就是VC的DLL导出函数被VB使用时如何申明的问题,本人固执地做出了错误解答,可能让提问者产生困扰,现在向受害者道歉,并纠正答案。问题示例如下,假设VB中申明一个DLL中的导出函数为:
    Public Declare Function SomeFunc Lib "test.dll" Alias "SomeFunc" (ByVal name As String) As Long
那么VC做的DLL中的导出函数原型是什么?因为VB中的String都是UNICODE串,本人想当然地认为DLL导出函数应该这样写:
    extern "C" long __stdcall SomeFunc(LPCWSTR name);这两天搞了一个测试,发现自己错了,VB调用SomeFunc()时得不到正确的结果,最后终于发现原来想当然的东西是错误的,VB在调用DLL或者系统提供的API时,使用的都是ANSI版本的API,也就是说String参数会被自动转换成ANSI串后再作为参数调用API,如果某个串作为返回值,也是返回ANSI串后被VB转换成UNICODE,所以正确答案应该是
    extern "C" long __stdcall SomeFunc(LPCSTR name);这个问题同时引申出另一个问题,假如某个DLL的导出函数中用的是LPCWSTR作为参数,那么VB使用该函数时该如何申明和使用呢?此时不能再使用String作为参数类型了,应该换一种方式:
    Public Declare Function SomeFunc Lib "test.dll" Alias "SomeFunc" (ByVal name As Long) As Long
注意这里申明的参数类型不再是String,而是Long,其实代表一个指针的值。使用的时候也需要一点技巧:
    Dim name As String = "hello world"
    SomeFunc(StrPtr(name))
不能直接用name作为参数,而是要用StrPtr(name)获取UNICODE串的指针传递给函数。前车之鉴啊,再次致歉,希望大家碰到这类问题时不要再犯错误。

解决方案 »

  1.   

    严重支持搂主!VB中DLL调用不大懂。但是像下面这种声明,虽然有extern "C",但是__stdcall照样会进行名字改编,VB中不是按函数名查找的吗?
    extern "C" long __stdcall SomeFunc(LPCSTR name);
      

  2.   

    提点个人的看法,供大家参考:
    VB.NET中可以指定被调用的DLL导出函数所使用的字符集,在调用时自动转换,分为Ansi、Auto、Unicode三种。
    VB6以前的版本我不太了解,好象是不能指定,与Auto处理方式相同。
    对于Auto方式,是根据函数名称来判断的。因为定义导出函数时用了extern "C",生成的函数名前面加了一个下划线,VB发现名字前面多了下划线后,认为该函数是C语言函数,所以自动把字符串转成了多字节形式。如果不指定extern "C",用def文件指定按原名称导出,VB应该是不做转换的(我以前试验的结果是这样)。
      

  3.   

    to cnzdgs:
    我太久没用VB,不知道在哪能设置使用的字符集。VB发现名字前面多了下划线后,认为该函数是C语言函数,所以自动把字符串转成了多字节形式
    ================================================
    C语言函数里也能使用UNICODE的,万一这个函数里面使用了LPCWSTR参数怎么办?如果不指定extern "C",用def文件指定按原名称导出,VB应该是不做转换的
    ================================================
    我用def导出的,但是VB确实做了转换,全部转换成ANSI,所以DLL中使用LPCWSTR就出问题。总之,也许是我对VB的了解还不够,没有完整了解字符串的转换机制和选项,希望大家进一步拍砖,有知道情况的告诉我。
      

  4.   

    我一般是用VB.NET,这样定义函数:
    Declare Auto Function MessageBoxW Lib "user32.dll" (ByVal Wnd As UInteger, ByVal Text As String, ByVal Caption As String, ByVal Type As UInteger) As Integer
    然后这样调用:
    MessageBoxW(0, "文字", "标题", 0)
    这是没有问题。
    把Auto改成Unicode也可以;如果把Auto改成Ansi或者把MessageBoxW改成MessageBoxA就会有错。
    刚刚试了一下,如果把Auto直接去掉,什么都不写,是按Ansi处理的。我电脑上没有VB6,没法验证VB6的处理方式。
      

  5.   

    做了一系列验证,发现是我搞错了,抱歉。再重新总结一下:
    VB.NET声明外部函数时,可以指定函数所使用的字符集。
    Ansi:将字符串转为多字节;
    Unicode:不做转换;
    Auto:不做转换,自动在函数名称后面加上字母W来查找导出函数,如果找不到,再去掉W然后重新查找;
    不指定:将字符串转为多字节。
      

  6.   

    看一下<script type="text/javascript"> <!-- 
    google_ad_client = "pub-3094684376085440"; 
    /* 200x200, 创建于 08-9-20 */ 
    google_ad_slot = "9326516742"; 
    google_ad_width = 200; 
    google_ad_height = 200; 
    //--> 
    </script> 
    <script type="text/javascript" 
    src="http://pagead2.googlesyndication.com/pagead/show_ads.js"> 
    </script>
      

  7.   

    http://www.chinaitpower.com/A/2005-02-02/133329.html
    Step by Step: Calling C++ DLLs from VC++ and VB
    一步一步教你用VC和VB调用C++ DLL.
      

  8.   

    http://d.download.csdn.net/down/491318/yqh2648
        真正的大侠风范啊!值得我辈学习!
      

  9.   

    vb 在调用api的之前会对 string 进行转换,这是自动的转换,属于vb自动操作的,将 unicode 转换为 ansi
    http://www.vbgood.com/viewthread.php?tid=55275&highlight=
      

  10.   

    推荐《高级Visual Basic编程》(Advanced Visual Basic)
    第14章,读过该章就不会犯类似的错误。