VB60调用DLL161210.docx

上传人:b****5 文档编号:11846656 上传时间:2023-04-06 格式:DOCX 页数:33 大小:30.73KB
下载 相关 举报
VB60调用DLL161210.docx_第1页
第1页 / 共33页
VB60调用DLL161210.docx_第2页
第2页 / 共33页
VB60调用DLL161210.docx_第3页
第3页 / 共33页
VB60调用DLL161210.docx_第4页
第4页 / 共33页
VB60调用DLL161210.docx_第5页
第5页 / 共33页
点击查看更多>>
下载资源
资源描述

VB60调用DLL161210.docx

《VB60调用DLL161210.docx》由会员分享,可在线阅读,更多相关《VB60调用DLL161210.docx(33页珍藏版)》请在冰豆网上搜索。

VB60调用DLL161210.docx

VB60调用DLL161210

VB6.0调用DLL

Hanford

2016年12月10日

目录

第1章VB6.0调用DLL1

1VC++编写DLL1

1.1使用__stdcall1

1.2使用.DEF文件1

2简单数据类型2

2.1传值(ByVal)2

2.2传址(ByRef)3

2.3传址(VarPtr)4

2.4转换为Variant4

3String6

3.1BSTR内存布局6

3.2StrPtr、VarPtr7

3.3示例代码7

3.4转换为Variant12

3.5小结13

4结构14

4.1定义14

4.2示例代码14

5数组17

5.1简单数据类型数组17

5.2转换为Variant18

5.3结构数组19

6Object21

7函数21

第1章VB6.0调用DLL

1VC++编写DLL

VB6.0或VBA可以调用DLL里的导出函数。

可以使用VC++编写DLL,供VB6.0调用。

VC++编写DLL时,需要注意以下几点:

1.1使用__stdcall

C函数在默认情况下,其调用约定为__cdecl。

为了让VB6.0调用此函数,需要特别设置调用约定为__stdcall(或WINAPI)。

如下面的C代码:

void__stdcallTest()

{

}

1.2使用.DEF文件

使用VC++编写DLL,可以使用__declspec(dllexport)导出一个函数。

如:

__declspec(dllexport)void__stdcallTest()

{

}

使用VC++6.0的C编译器编译上述代码,则导出函数名为_Test@0。

此时,VB6.0声明Test函数的代码如下:

PrivateDeclareSubTestLib"Test.dll"Alias"_Test@0"()

“Alias"_Test@0"”明确说明了导出函数的名称。

为了简化VB6.0里Test函数的声明,可使用DEF文件,具体如下:

1、使用DEF文件。

下面是DEF文件的内容,它表示导出Test函数:

EXPORTS

Test

2、VC代码里不使用__declspec(dllexport),如下面的代码

void__stdcallTest()

{

}

3、VB6.0声明Test函数时无需Alias,如下面的声明

PrivateDeclareSubTestLib"Test.dll"()

2简单数据类型

VB6.0中,常见的数据类型请见下表

VB6.0

C

说明

Boolean

VARIANT_BOOL

就是short

VARIANT_TRUE等于-1表示TRUE

VARIANT_FALSE等于0表示FALSE

Byte

BYTE

就是unsignedchar

Currency

CY

CURRENCY

就是__int64

如:

1234567表示货币值123.4567@

Date

DATE

就是double

表示1899年12月30日到当前时刻的天数,对应于MFC的COleDateTime

Decimal

DECIMAL

VB6.0里Decimal用Variant表示

Double

double

Integer

short

Long

long

Single

float

String

BSTR

Unicode字符串

Variant

VARIANT

上表中,除了Decimal、String、Variant之外其它均为简单数据类型。

VB6.0传递简单数据类型给DLL时,分为传值和传址两种方式:

2.1传值(ByVal)

VC++代码:

longWINAPITestSimpleV(VARIANT_BOOLb,BYTEbt,__int64c

DATEdt,doubled,shorti,longl,floats)

{

b=VARIANT_TRUE;//改变形参,不会影响VB6.0里的实参

return0;

}

VB6.0声明代码:

PublicDeclareFunctionTestSimpleVLib"Test.dll"_

(ByValbAsBoolean,ByValbtAsByte,ByValcAsCurrency,_

ByValdtAsDate,ByValdAsDouble,ByValiAsInteger,_

ByVallAsLong,ByValsAsSingle)AsLong

VB6.0调用代码:

DimbAsBoolean,btAsByte,cAsCurrency,dtAsDate

DimdAsDouble,iAsInteger,lAsLong,sAsSingle

DimnRetAsLong

nRet=TestSimpleV(b,bt,c,dt,d,i,l,s)

说明:

1、VB6.0声明函数时,必须使用ByVal,表示把实参的数值传递给形参;

2、因为传递的是数值,所以VC函数里改变形参的数值不会影响到实参。

2.2传址(ByRef)

VC++代码:

longWINAPITestSimpleR(VARIANT_BOOL*b,BYTE*bt,__int64*c

DATE*dt,double*d,short*i,long*l,float*s)

{

if(b){*b=VARIANT_TRUE;}

if(bt){*bt=2;}

if(c){*c=654321;}//货币值65.4321@

if(d){*d=3.4;}

if(i){*i=5;}

if(l){*l=6;}

if(s){*s=7.8f;}

if(dt)

{

SYSTEMTIMEtmSys;

GetLocalTime(&tmSys);

SystemTimeToVariantTime(&tmSys,dt);

}

return1;

}

VB6.0声明代码:

PublicDeclareFunctionTestSimpleRLib"Test.dll"_

(ByRefbAsBoolean,ByRefbtAsByte,ByRefcAsCurrency,_

ByRefdtAsDate,ByRefdAsDouble,ByRefiAsInteger,_

ByReflAsLong,ByRefsAsSingle)AsLong

VB6.0调用代码:

DimbAsBoolean,btAsByte,cAsCurrency,dtAsDate

DimdAsDouble,iAsInteger,lAsLong,sAsSingle

DimnRetAsLong

nRet=TestSimpleR(b,bt,c,dt,d,i,l,s)

说明:

1、VB6.0声明函数时,应使用ByRef,表示把实参的地址传递给形参;

2、因为传递的是地址,所以VC函数里改变形参的数值将影响到实参。

2.3传址(VarPtr)

使用ByRef无法将NULL指针传递给DLL,为此可使用函数VarPtr。

示例代码如下:

VB6.0声明代码:

PublicDeclareFunctionTestSimplePLib"Test.dll"Alias"TestSimpleR"_

(ByValbAsLong,ByValbtAsLong,ByValcAsLong,_

ByValdtAsLong,ByValdAsLong,ByValiAsLong,_

ByVallAsLong,ByValsAsLong)AsLong

VB6.0调用代码:

DimbAsBoolean,btAsByte,cAsCurrency,dtAsDate

DimdAsDouble,iAsInteger,lAsLong,sAsSingle

DimnRetAsLong

nRet=TestSimpleP(VarPtr(b),VarPtr(bt),VarPtr(c),VarPtr(dt),_

VarPtr(d),VarPtr(i),VarPtr(l),VarPtr(s))

VarPtr(b)将返回变量b的地址,被VB6.0当做long传递给DLL。

若要传递NULL指针,可修改VarPtr(...)为0。

VB.NET不支持VarPtr函数,下面是从网上找到的代码,不知是否稳定。

PublicFunctionVarPtr(ByValeAsObject)AsInteger

DimGCAsGCHandle=GCHandle.Alloc(e,GCHandleType.Pinned)

DimGC2AsInteger=GC.AddrOfPinnedObject.ToInt32

GC.Free()

ReturnGC2

EndFunction

2.4转换为Variant

VB6.0里可以将简单数据类型转换为Variant,然后再传递给DLL。

下面是示例代码:

VC++代码:

voidWINAPITestSimpleVariant(VARIANTv,VARIANT*r)

{

if(v.vt==VT_R8)

{

v.dblVal=-1.2;//不会影响实参

}

if(r&&r->vt==(VT_R4|VT_BYREF))

{

*r->pfltVal=-3.4f;//会影响实参

}

}

VB6.0声明代码:

PublicDeclareSubTestSimpleVariantLib"Test.dll"_

(ByValvAsVariant,ByRefrAsVariant)

VB6.0调用代码:

DimdAsDouble,sAsSingle

d=1.2

s=3.4!

MsgBoxHex$(VarPtr(d))&"="&d&vbCrLf&_

Hex$(VarPtr(s))&"="&s

CallTestSimpleVariant(d,s)

MsgBoxHex$(VarPtr(d))&"="&d&vbCrLf&_

Hex$(VarPtr(s))&"="&s

运行VB6.0代码,将依次出现:

1、首先显示如下界面

说明:

变量d的首地址为0x18F374,数值为1.2;变量s的首地址为0x18F370,数值为3.4;

2、VB6.0将d、s转换为Variant,然后传递给VC函数TestSimpleVariant。

注意:

r->pfltVal就是实参s的首地址;

3、VB6.0中CallTestSimpleVariant(d,s)执行完毕后,d的数值未变,s的数值被改变,d、s的地址均未改变,如下图所示:

3String

可以认为VB6.0的String就是C语言的BSTR。

BSTR可以表示宽字符串(Unicode),也可以表示窄字符串(ANSI)。

在VB6.0或EVB3.0里,String对应的BSTR是一个宽字符串。

3.1BSTR内存布局

BSTRs表示了一个字符串。

s是一个指针,指向了一个ANSI或UNICODE字符串。

此外,BSTR还包含了字符串的长度信息。

具体结构如下:

字符串所占字节数

共4字节

字符串

首地址就是s

结束符

如:

字符串”123”以ANSI的BSTR表示(假定s的值为0x1000)

地址

内容

说明

0x0FFC

03H

字符串所占字节数,这里为3

0x0FFD

00H

0x0FFE

00H

0x0FFF

00H

0x1000

31H

字符串123

0x1001

32H

0x1002

33H

0x1003

00H

结束符

字符串”123”以UNICODE的BSTR表示(假定s的值为0x1000)

地址

内容

说明

0x0FFC

06H

字符串所占字节数,这里为6

0x0FFD

00H

0x0FFE

00H

0x0FFF

00H

0x1000

31H

字符串123

0x1001

00H

0x1002

32H

0x1003

00H

0x1004

33H

0x1005

00H

0x1006

00H

结束符

0x1007

00H

所以,当BSTRs表示ANSI字符串时,可以把s当作char*;当BSTRs表示UNICODE字符串时,可以把s当作wchar_t*

3.2StrPtr、VarPtr

StrPtr返回的是字符串首字符的地址(可看做wchar_t*),VarPtr返回的是字符串变量的地址(可看做wchar_t**)。

参考下表,可以更好的理解:

VB6.0代码

C代码

DimsAsString

BSTRs;

DimnAsLong

n=StrPtr(s)

wchar_t*n=(wchar_t*)s;

n=VarPtr(s)

wchar_t**n=(wchar_t**)&s;

3.3示例代码

VB6.0里将String变量传递给DLL的示例代码如下:

VC++代码:

BSTRWINAPITestString(BSTRv,BSTR*r,BSTRsp,BSTR*vp)

{

if(v)

{//VB6.0传过来vbNullString,则v为NULL

char*p=(char*)v;//ANSI字符串首地址

UINT&nLen=((UINT*)p)[-1];//ANSI字符串长度

if(nLen>0)

{

p[0]='v';//允许修改字符串

nLen=1;//允许将字符串长度变小

p[nLen]='\0';//修改字符串长度后,这句是必需的

}

}

{

char*p=*(char**)r;//ANSI字符串首地址

if(p)

{//VB6.0传过来vbNullString,则r不为NULL,p为NULL

UINT&nLen=((UINT*)p)[-1];//ANSI字符串长度

if(nLen>0)

{

p[0]='r';//允许修改字符串

nLen=1;//允许将字符串长度变小

p[nLen]='\0';//修改字符串长度后,这句是必需的

}

}

else

{//重新定义字符串

char*szStr="C函数生成的字符串";

SysFreeString(*r);//释放以前的字符串

*r=SysAllocStringByteLen(szStr,strlen(szStr));//修改字符串

}

}

{

wchar_t*p=(wchar_t*)sp;//Unicode字符串首地址

if(p)

{//VB6.0传过来vbNullString,则sp不为NULL,p为NULL

UINT&nLen2=((UINT*)p)[-1];//Unicode字符串字节数

if(nLen2>=2)

{

p[0]=L's';//允许修改字符串

nLen2=2;//允许将字符串长度变小

p[nLen2>>1]=L'\0';//修改字符串长度后,这句是必需的

}

}

}

{

wchar_t*p=*(wchar_t**)vp;//Unicode字符串首地址

if(p)

{//VB6.0传过来vbNullString,则vp不为NULL,p为NULL

UINT&nLen2=((UINT*)p)[-1];//Unicode字符串字节数

if(nLen2>=2)

{

p[0]=L'v';//允许修改字符串

nLen2=2;//允许将字符串长度变小

p[nLen2>>1]=L'\0';//修改字符串长度后,这句是必需的

}

}

}

{//返回值,允许返回NULL

char*szStr="C函数返回的字符串";

returnSysAllocStringByteLen(szStr,strlen(szStr));

}

}

VB6.0声明代码:

PublicDeclareFunctionTestStringLib"Test.dll"_

(ByValvAsString,ByRefrAsString,_

ByValspAsLong,ByValvpAsLong)AsString

VB6.0调用代码:

DimvAsString

DimrAsString

DimspAsString

DimvpAsString

v=txtV.Text

r=txtR.Text

sp=txtSP.Text

vp=txtVP.Text

txtReturn.Text=TestString(v,r,StrPtr(sp),VarPtr(vp))

txtV.Text=v

txtR.Text=r

txtSP.Text=sp

txtVP.Text=vp

下面是对上述代码的详细说明:

3.3.1ByValvAsString

VB6.0里的变量v是一个String,其实就是一个Unicode的BSTR。

调用TestString之前,VB6.0会将v转换为Ansi的BSTR,并将这个BSTR传递给DLL。

DLL的处理代码如下:

if(v)

{//VB6.0传过来vbNullString,则v为NULL

char*p=(char*)v;//ANSI字符串首地址

UINT&nLen=((UINT*)p)[-1];//ANSI字符串长度

if(nLen>0)

{

p[0]='v';//允许修改字符串

nLen=1;//允许将字符串长度变小

p[nLen]='\0';//修改字符串长度后,这句是必需的

}

}

首先要判断v是否为NULL,因为VB6.0传递字符串vbNullString时,该参数将为NULL。

接下来获得ANSI字符串的首地址p和长度nLen。

允许修改ANSI字符串的内容和长度,但是不能加长字符串。

VC++的TestString函数返回后,VB6.0会将ANSI字符串转换为Unicode字符串,并由此改变实参v。

3.3.2ByRefrAsString

VB6.0里的变量r是一个String,其实就是一个Unicode的BSTR。

调用TestString之前,VB6.0会将r转换为Ansi的BSTR,并将这个BSTR传递给DLL。

DLL的处理代码如下:

{

char*p=*(char**)r;//ANSI字符串首地址

if(p)

{//VB6.0传过来vbNullString,则r不为NULL,p为NULL

UINT&nLen=((UINT*)p)[-1];//ANSI字符串长度

if(nLen>0)

{

p[0]='r';//允许修改字符串

nLen=1;//允许将字符串长度变小

p[nLen]='\0';//修改字符串长度后,这句是必需的

}

}

else

{//重新定义字符串

char*szStr="C函数生成的字符串";

SysFreeString(*r);//释放以前的字符串

*r=SysAllocStringByteLen(szStr,strlen(szStr));//修改字符串

}

}

即:

可以修改ANSI字符串内容和长度,也可以重新生成字符串。

VC++的TestString函数返回后,VB6.0会将ANSI字符串转换为Unicode字符串,并由此改变实参r。

3.3.3ByValspAsLong

VB6.0里的变量sp是一个String,其实就是一个Unicode的BSTR。

调用TestString时使用StrPtr(sp)将字符串的首地址传递给了DLL,DLL的处理代码如下:

{

wchar_t*p=(wchar_t*)sp;//Unicode字符串首地址

if(p)

{//VB6.0传过来vbNullString,则sp不为NULL,p为NULL

UINT&nLen2=((UINT*)p)[-1];//Unicode字符串字节数

if(nLen2>=2)

{

p[0]=L's';//允许修改字符串

nLen2=2;//允许将字符串长度变小

p[nLen2>>1]=L'\0';//修改字符串长度后,这句是必需的

}

}

}

上述代码处理的不再是ANSI字符串,而是Unicode字符串。

不过,修改字符串时只能减小长度,不能增大长度。

3.3.4ByValvpAsLong

VB6.0里的变量vp是一个String,其实就是一个Unicode的BSTR。

调用TestString时使用VarPtr(vp)将字符串变量的地址传递给了DLL,DLL的处理代码如下:

{

wchar_t*p=*(wchar_t**)vp;//Unicode字符串首地址

if(p)

{//VB6.0传过来vbNullString,则vp不为NULL,p为NULL

UINT&nLen2=((UINT*)p)[-1];//Unicode字符串字节数

if(nLen2>=2)

{

p[0]=L'v';//允许修改字符串

nLen2=2;//允许将字符串长度变小

p[nLen2>>1]=L'\0';//修改字符串长度后,这句是必需的

}

}

}

与“ByValspAsLong”一样:

修改字符串时只能减小长度,不能增大。

3.3.5返回值

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 高等教育 > 文学

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1