vb的string c语言的,从VC++ 编辑的DLL过程(或函数)向VB 传递字符串的方法(简单实用版)...

1. MSDN 中的介绍:

1.1 将字符串传递到 DLL 过程

通常,字符串应该使用 ByVal 方式传递到 APIs。Visual Basic 使用被称为 BSTR 的 String 数据类型,它是由自动化(以前被称为 OLE自动化)定义的数据类型。一个 BSTR 由头部和字符串组成,头部包含了字符串的长度信息,字符串中可以包含嵌入的 null 值。BSTR 是以指针的形式进行传递的,因而 DLL 过程能够修改字符串。(指针是一个变量,包含另外一个变量的内存地址,而不是数据。) BSTR 是 Unicode 的,即每个字符需要两个字节。BSTR 通常以两字节的 null 字符结束。

DLL 中的大部分过程(以及 Window API 中的所有过程)能够识别 LPSTR 类型,这是指向标准的以 null 结束的 C 语言字符串的指针,它也被称为 ASCIIZ 字符串。LPSTR 没有前缀。下图显示了一个指向 ASCIIZ 字符串的 LPSTR。

如果 DLL 过程需要一个 LPSTR(指向以 null 结束的字符串的指针)作为参数,可以将 BSTR 以使用值方式传递给它。因为指向 BSTR 的指针实际指向以 null 值结束的字符串的第一个数据字节,对于 DLL 过程来说,它就是一个 LPSTR。

例如,sndPlaySound 函数接受一个数字声音 (.wav) 文件名,然后演奏该文件。

Private Declare Function sndPlaySound Lib "winmm.dll" _

Alias "sndPlaySoundA" (ByVal lpszSoundName As String, _

ByVal uFlags As Long) As Long

因为该过程的字符串参数被声明为 ByVal,Visual Basic 将传递一个 BSTR,该 BSTR 指向第一个数据字节:

Dim SoundFile As String, ReturnLength As Long

SoundFile = Dir("c:\Windows\System\" & "*.wav")

Result = sndPlaySound(SoundFile, 1)

通常,如果 DLL 过程需要 LPSTR 参数,那么使用 ByVal 关键字。如果 DLL 需要得到指向 LPSTR 的指针,则使用引用方式传递 Visual Basic 字符串。

如果要将二进制数据传递到 DLL 过程,可以将变量作为 Byte 数据类型的数组传递,不要将其作为 String 变量。字符串是假定用来包含字符的,如果将二进制数据作为 String 变量传递,外部程序可能无法正确读入数据。

假设声明了一个字符串变量,但没有初始化它,如果将其以使用值方式传递到 DLL,该字符串变量将作为 NULL 传递,而不是作为空字符串 ("")。为了消除代码中的混淆,如果要将 NULL 传递到 LPSTR 参数,请使用 vbNullString 常数。

1.2 将字符串传递到使用自动化的 DLL

某些 DLL 是专门使用 BSTR 等自动化数据类型的,它们利用了自动化提供的若干过程。

因为 Visual Basic 使用自动化数据类型作为自己的数据类型,所以能够使用引用方式将 Visual Basic 参数传递到需要自动化数据类型的任何 DLL。因此,如果 DLL 过程需要以 Visual Basic 字符串作为参数,就不必用 ByVal 关键字来声明参数,除非该过程确实需要以使用值方式传递字符串。

某些 DLL 过程可以返回字符串到调用它的过程。除非 DLL 函数是专门为自动化数据类型而编写的,否则它将不能返回字符串。如果确实能够返回字符串,该 DLL 可能会提供对过程进行描述的类型库。请参考该 DLL 的有关文档。

1.3 修改字符串参数的过程(本人注:不好用)

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 过程需要内存缓冲区时,既可以使用适合的数据类型,也可以使用字节数据类型的数组。

2.本人的实现方法:

微软的将VB 中的字符串参数传递到DLL中方法是可行的。但是将DLL中的字符串传递到VB 中用下面的方法更加简易。

2.1 VC++  代码如下(比较完整的一个处理硬件的DLL ,关于字符串传递请看加粗部分的代码):

#include "stdafx.h"

#include "clock2008dll.h"

#include 

#include "clocktestioctl.h"

#ifdef _DEBUG

#define new DEBUG_NEW

#undef THIS_FILE

static char THIS_FILE[] = __FILE__;

#endif

//

// Note!

//

// If this DLL is dynamically linked against the MFC

// DLLs, any functions exported from this DLL which

// call into MFC must have the AFX_MANAGE_STATE macro

// added at the very beginning of the function.

//

// For example:

//

// extern "C" BOOL PASCAL EXPORT ExportedFunction()

// {

// AFX_MANAGE_STATE(AfxGetStaticModuleState());

// // normal function body here

// }

//

// It is very important that this macro appear in each

// function, prior to any calls into MFC.  This means that

// it must appear as the first statement within the

// function, even before any object variable declarations

// as their constructors may generate calls into the MFC

// DLL.

//

// Please see MFC Technical Notes 33 and 58 for additional

// details.

//

/

// CClock2008dllApp

BEGIN_MESSAGE_MAP(CClock2008dllApp, CWinApp)

//{{AFX_MSG_MAP(CClock2008dllApp)

// NOTE - the ClassWizard will add and remove mapping macros here.

//    DO NOT EDIT what you see in these blocks of generated code!

//}}AFX_MSG_MAP

END_MESSAGE_MAP()

/

// CClock2008dllApp construction

CClock2008dllApp::CClock2008dllApp()

{

// TODO: add construction code here,

// Place all significant initialization in InitInstance

}

/

// The one and only CClock2008dllApp object

CClock2008dllApp theApp;

BOOL __stdcall Create()

{

char *sLinkName = "\\\\.\\Clock00device0";

hDevice=CreateFile(sLinkName,

GENERIC_READ | GENERIC_WRITE,

FILE_SHARE_READ| FILE_SHARE_WRITE,

NULL,

OPEN_EXISTING,

0,

NULL);

if (hDevice == INVALID_HANDLE_VALUE)

{

AfxMessageBox(_T("没有安装时钟卡!"));

return false;

}

unsigned long nOutput;

hEventR0=::CreateEvent(NULL,TRUE, FALSE,"CLOCKEVENT"); //reponse 20c/s interrupt signal

unsigned long bufInput=unsigned long(hEventR0);

if (!DeviceIoControl(hDevice,CLOCKTEST_IOCTL_R0EVENT,&bufInput,4,NULL,0,&nOutput,NULL))

{

::AfxMessageBox(_T("传递事件不成功!"));

return false;

}

// Create receive/send threads

::AfxBeginThread(__ThreadR0,NULL,THREAD_PRIORITY_HIGHEST);

return true;

}

int __stdcall CloseClock()

{  if(hDevice)

return CloseHandle(hDevice);

else return 0;

}

UINT __ThreadR0(LPVOID pData)

{

ThreadR0();

return 0;

}

UINT ThreadR0()

{

int n;

unsigned long nRead;

UINT hour,min,sec,msec;

BYTE b1,b2,b3,b4,b5;

while(1)

{

if(::WaitForSingleObject(hEventR0,INFINITE)==WAIT_OBJECT_0)

{

::ResetEvent(hEventR0);

//To Do ,Send clock;

n=5;

//Read channel0

myMutex.Lock();

if (!DeviceIoControl(hDevice,CLOCKTEST_IOCTL_GETTIME,NULL,0,buf,n,&nRead,NULL))

{

::AfxMessageBox(_T("应用程序无法读出时间信息!"));

}

b1=buf[0];

if(b1==0x03)  strStatus.Format(_T("BDC有效,GPS有效"));

if(b1==0x02)  strStatus.Format(_T("GPS有效,BDC无效"));

if(b1==0x01)  strStatus.Format(_T("BDC有效,GPS无效"));

if(b1==0x0)   strStatus.Format(_T("BDC无效,GPS无效"));

//::AfxMessageBox(strStatus);//

b2=buf[4];

hour=(b2/64)*10+(b2&0x3c)/4;

b3=buf[3];

min=((b2&0x03)*2+b3/128)*10+(b3&0x78)/8;

b4=buf[2];

sec=(b3&0x07)*10+b4/16;

b5=buf[1];

msec=(UINT)(b4&0x0f)*100;

msec+=(b5/16)*10;

msec+=b5&0x0f;

strOutputTime.Format ("%02u:%02u:%02u.%03u",hour,min,sec,msec);

//::AfxMessageBox(strOutputTime);//

myMutex.Unlock ();

}

}

return 0;

}

BOOL __stdcall SetParameters(BYTE byteCommand, int  iInputHour, int iInputMin, int iInputSec)

{

BYTE bufwrite[6];

unsigned long nOutput;

bufwrite[0]=(BYTE)byteCommand;

unsigned int  high_4_bit[3],low_4_bit[3],uWriteTime;

high_4_bit[0]=iInputHour/10;

low_4_bit[0]=iInputHour%10;

high_4_bit[1]=iInputMin/10;

low_4_bit[1]=iInputMin%10;

high_4_bit[2]=iInputSec/10;

low_4_bit[2]=iInputSec%10;

uWriteTime=low_4_bit[2]+high_4_bit[2]*16+low_4_bit[1]*256+high_4_bit[1]*256*16+low_4_bit[0]*256*256+high_4_bit[0]*256*256*16;

memcpy(bufwrite+1,&uWriteTime,4);

if (!DeviceIoControl(hDevice,CLOCKTEST_IOCTL_SETTIME,&bufwrite,5,NULL,0,&nOutput,NULL))

{

::AfxMessageBox(_T("设置命令失败!"));

return false;

}

return true;

}

int __stdcall GetTimeAndStatus( LPSTR *strTime , int * strTimeLength,LPSTR *strState,int * strStateLength)

{

int itemp;

myMutex.Lock ();

*strTime=LPSTR(strOutputTime.GetBuffer(strOutputTime.GetLength()));

*strTimeLength=strOutputTime.GetLength();

*strState=LPSTR(strStatus.GetBuffer(strStatus.GetLength()));

*strStateLength=strStatus.GetLength();

itemp=*((int *)(&buf[1]));

myMutex.Unlock ();

return itemp;

}

2.2头文件如下:

// MyCFuncs.h

#ifdef __cplusplus

extern "C" {  // only need to export C interface if

// used by C++ source code

#endif

__declspec( dllexport ) int __stdcall GetTimeAndStatus( LPSTR *strTime , int * strTimeLength,LPSTR *strState,int * strStateLength);

__declspec( dllexport ) BOOL __stdcall SetParameters(BYTE byteCommand,int  iInputHour,int iInputMin,int iInputSec);

__declspec( dllexport ) BOOL __stdcall Create();

__declspec( dllexport ) int  __stdcall CloseClock();

#ifdef __cplusplus

}

#endif

unsigned char buf[10];

CString strStatus;

CString strOutputTime;

CMutex myMutex;

HANDLE hDevice,hEventR0; //20C/s中断事件

//中断事件处理线程工作函数

static UINT __ThreadR0(LPVOID pData); //中断事件处理线程

UINT ThreadR0(void);

/

// CClock2008dllApp

// See clock2008dll.cpp for the implementation of this class

//

class  CClock2008dllApp : public CWinApp

{

public:

// UINT GetTimeAndStatus(CString strTime,CString strState);

// BOOL SetParameters(unsigned char byteCommand,UINT  uiInputHour,UINT uiInputMin,UINT uiInputSec);

// BOOL Create();

CClock2008dllApp();

// Overrides

// ClassWizard generated virtual function overrides

//{{AFX_VIRTUAL(CClock2008dllApp)

//}}AFX_VIRTUAL

//{{AFX_MSG(CClock2008dllApp)

// NOTE - the ClassWizard will add and remove member functions here.

//    DO NOT EDIT what you see in these blocks of generated code !

//}}AFX_MSG

DECLARE_MESSAGE_MAP()

};

/

//{{AFX_INSERT_LOCATION}}

// Microsoft Visual C++ will insert additional declarations immediately before the previous line.

#endif // !defined(AFX_CLOCK2008DLL_H__3C2A1A6F_9820_4FFF_8D68_1463D6FD88FC__INCLUDED_)

2.3 VB 中的代码如下:

Private Declare Function Create Lib "clock2008dll.dll" Alias "_Create@0" () As Boolean

Private Declare Function CloseClock Lib "clock2008dll.dll" Alias "_CloseClock@0" () As Long

Private Declare Function GetTimeAndStatus Lib "clock2008dll.dll" Alias "_GetTimeAndStatus@16" (strTime As String, strTimeLength As Long, strState As String, strStateLength As Long) As Long

Private Declare Function SetParameters Lib "clock2008dll.dll" Alias "_SetParameters@16" (ByVal byteCommand As Byte, ByVal iInputHour As Long, ByVal iInputMin As Long, ByVal iInputSec As Long) As Boolean

Dim str1 As String * 255

Dim str2 As String * 255

Dim str1Length, str2Length As Long

Dim p1, p2 As Long

Dim bufRece(9) As Byte

Dim setOK As Boolean

Private Sub Form_Load()

Create

'setOK = SetParameters(1, 2, 3, 4)

GetTimeAndStatus str1, str1Length, str2, str2Length

Text1.Text = str1

Text2.Text = str2

Timer1.Interval = 50

Timer1.Enabled = True

End Sub

Private Sub Form_Unload(Cancel As Integer)

Timer1.Enabled = False

CloseClock

End Sub

Private Sub Timer1_Timer()

GetTimeAndStatus str1, str1Length, str2, str2Length

Text1.Text = str1

Text2.Text = str2

End Sub

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值