首页 诗词 字典 板报 句子 名言 友答 励志 学校 网站地图
当前位置: 首页 > 教程频道 > 开发语言 > VB >

VB调用dll,结果vb开发环境直接忽然关闭了

2014-01-12 
VB调用dll,结果vb开发环境直接突然关闭了VB调用dll,结果vb开发环境直接突然关闭了dll函数原型://开票命令/

VB调用dll,结果vb开发环境直接突然关闭了
VB调用dll,结果vb开发环境直接突然关闭了

dll函数原型:

//开票命令
//输入:*InvData 开票数据,DataLen数据长度
//输出:*RecData接收到的数据,*RecLenth实际接收到的数据长度
//返回值:0成功,其它错误代码
extern  __declspec(dllexport) __stdcall DWORD FiscalMakeInvoice(BYTE *InvData,DWORD DataLen,DWORD *RecLenth,BYTE *RecData)


封装:

Public Declare Function FiscalMakeInvoice Lib "FiscalReader.DLL" (ByRef InvData As Byte, DataLen As Long, ByRef RecLenth As Long, ByRef RecData As Byte) As Long


调用:

'InvData和RecData都是byte数组
MakeInvoice = FiscalMakeInvoice(InvData(0), DataLen, reclength, RecData(0))

[解决办法]
处理使用字符串的 Windows API 过程
如果调用的 Windows API 过程要使用字符串,那么声明语句中必须增加一个 Alias 子句,以指定正确的字符集。包含字符串的 Windows API 函数实际有两种格式:ANSI 和 Unicode。因此,在 Windows 头文件中,每个包含字符串的函数都同时有 ANSI 版本和 Unicode 版本。

例如,下面是 SetWindowText 函数的两种 C 语言描述。可以看到,第一个描述将函数定义为 SetWindowTextA,尾部的“A”表明它是一个 ANSI 函数:

WINUSERAPI
BOOL
WINAPI
SetWindowTextA(
   HWND hWnd,
   LPCSTR lpString);

第二个描述将它定义为 SetWindowTextW,尾部的“W”表明它是一个 Unicode 函数:

WINUSERAPI
BOOL
WINAPI
SetWindowTextW(
   HWND hWnd,
   LPCWSTR lpString);

因为两个函数实际的名称都不是“SetWindowText”,要引用正确的函数就必须增加一个 Alias 子句:

Private Declare Function SetWindowText Lib "user32" _
Alias "SetWindowTextA" (ByVal hwnd As Long, ByVal _
lpString As String) As Long

请注意,Alias 子句后面的字符串必须是过程的真正名称,而且必须是区分大小写的。

重点   对于 Visual Basic 中使用的 API 函数,应该指定函数的 ANSI 版本,因为只有 Windows NT 才支持 Unicode 版本,而 Windows 95 不支持这个版本。仅当应用程序只运行在 Windows NT 平台上的时候才可以使用 Unicode 版本。

使用值或引用传递
在缺省的情况下,Visual Basic 以引用方式传递所有参数。这意味着并没有传递实际的参数值,Visual Basic 只传递了数据的 32 位地址。在 Declare 语句中不要求包含 ByRef 关键字,但是如果包含该关键字,就能够清楚地看出数据是以何种方式传递的。

许多 DLL 过程要求参数以值方式传递。这意味着它们需要实际的数据,而不是数据的内存地址。如果过程需要一个传值参数,而传递给它的参数是一个指针,那么由于得到了错误的数据,该过程将不能正确地工作。

要使参数以使用值方式传递,在 Declare 语句中需要在参数声明的前面加上 ByVal 关键字。例如,InvertRect 过程要求第一个参数使用值,而第二个使用引用:

Declare Function InvertRect Lib "user32" Alias _
"InvertRectA" (ByVal hdc As Long, _
lpRect As RECT) As Long

也可以在调用过程时使用 ByVal 关键字。

注意   在查看使用 C 语言语法的 DLL 过程文档时,请记住 C 以传值方式传递数组以外的参数。

字符串参数是一个特例。如果以使用值方式传递字符串,那么传递的将是该字符串中第一个数据字节的地址;如果以使用引用方式传递字符串,那么实际传递的将是用来保存另一个地址的内存单元的地址;后面的“地址”实际是字符串的第一个数据字节的内存地址。本章后面的帮助主题“将字符串传递到 DLL 过程”将解释如何确定字符串参数传递的正确方式。

修改字符串参数的过程
DLL 过程能够修改作为参数输入的字符串变量的数据。不过,如果修改后的数据超过了原来的长度,过程的修改将越界(越过字符串的结尾),这可能会毁坏其它的数据。

要避免这个问题,一种办法是使字符串参数足够长,从而使 DLL 过程无法超出字符串的尾部。例如,GetWindowsDirectory 过程在第一个参数中返回了 Windows 目录的路径:

Declare Function GetWindowsDirectory Lib "kernel32" _
Alias "GetWindowsDirectoryA" (ByVal lpBuffer As _
String, ByVal nSize As Long) As Long

在调用该过程时,为了安全起见,先使用 String 函数在字符串中填充 255 个空字符(二进制的 0),只要返回的路径少于 255 个字符,就不会出问题:

Path = String(255, vbNullChar)
ReturnLength = GetWindowsDirectory(Path, Len(Path))
Path = Left(Path, ReturnLength)

另一个办法是将字符串定义为定长的:

Dim Path As String * 255
ReturnLength = GetWindowsDirectory(Path, Len(Path))

上述方法的目的只有一个:创建一个固定长度的字符串,使之能够包含过程可能产生的最长的字符串。

注意   Windows API 的 DLL 过程通常不需要超过 255 个字符的字符串缓冲区。尽管这对于其它的许多库也是成立的,为了保险起见,最好参考相应过程的文档。

当 DLL 过程需要内存缓冲区时,既可以使用适合的数据类型,也可以使用字节数据类型的数组。

[解决办法]
Public Declare Function FiscalMakeInvoice Lib "FiscalReader.DLL" (ByVal InvData As Long,ByVal DataLen As Long, ByRef RecLenth As Long, ByRef RecData As Long) As Long

MakeInvoice = FiscalMakeInvoice(VarPtr(InvData(0)), DataLen, reclength, VarPtr(RecData(0)))
[解决办法]
你在VB中的API声明,第2个参数:DataLen As Long


 应该为 ByVal DataLen As Long

[解决办法]
zhao4zhong1老师在2#、3#楼讲解的好详细呀,认真学习了。

热点排行