65.9K
CodeProject 正在变化。 阅读更多。
Home

如何为 Visual Basic 编写一个超级紧凑、超级快的 C++ DLL

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.60/5 (9投票s)

2001年11月4日

4分钟阅读

viewsIcon

192299

downloadIcon

1508

使用 ATL 从 VC++ DLL 导出函数供 VB 使用

引言

在本项目中,我们将学习如何从 VB 调用 VC DLL。我们将学习如何使用各种 VB 变量,例如 byte、integer、long、single、double、string、currency。我们还将探讨为什么要在 VB 是原生代码编译器的情况下使用 VC 编写。当然,有时当我们只需要调用小型快速例程时,C++ 是最佳选择。但 C++ 也有其固有的开销。一个典型的 Visual C++ DLL(不使用 MFC)大约需要 40KB(不包含 msvcrt 和 mfc DLL)。对于一个小函数来说,这是一个非常大的开销。至少 75% 的空间被 CRT(C 运行时)占用。

我假设读者对 C++ 和 VB 有扎实的了解。不需要 ATL/MFC 知识。

现在我们来讨论这个问题:如何为 VB 编写超级紧凑、超级快速的 DLL。我们将从 ATL 开始。不!不是 COM!

为什么选择 ATL?

ATL 提供了自己的 DLL 入口点。ATL 入口点快速且紧凑。这正是我们想要的。其次,我们将从不调用任何 CRT 函数。我们将始终调用 Windows API 函数,以最大限度地减小尺寸和提高速度。请参阅 KB 文章:Q99456 或查看下面的列表。

例如,看看下面的字符串长度。在 c 中是 strlen,但我们可以调用 lstrlen API 函数。参见此处。

	void __stdcall ReverseString( BSTR a )
	{
		int i, iLen;
		BSTR b;
		LPSTR pA, pB;

	#ifdef _UNICODE		
		iLen = lstrlen( (LPCTSTR) a );
	#else
		iLen = lstrlen( (LPCSTR) a ); // wait for this
	#endif

// to use crt in place of api just call
//	_tcslen( (LPCTSTR) a);
	
	wow its so easy .

使用 ATL 作为 DLL 基准的好处是:

  1. 它很紧凑。
  2. 没有 CRT 负担。
  3. ATL 提供了自己的入口点,因此很方便。
  4. 如果我们不使用 ATL DLL,那么一个普通的 DLL 会大两到三倍。

那么如何创建 ATL DLL 呢?这很简单。

请遵循以下步骤

  1. 从文件菜单中选择“新建项目”。
  2. 选择“ATL COM 向导”。
  3. 我不推荐使用 CRT 函数,所以这里是我们看到的内容:



  4. 要使用 CRT,请勾选“支持 MFC”复选框,如下图所示。


  5. 选择“允许合并代理/存根代码”。

ATL 有多种配置类型,但我们主要关注的是“Win32 MIN dependency”或“Win32 unicode min dependency”。注意:Unicode 仅适用于 Windows NT/2000/XP,不支持 Win 95/98/Me。

通过使用最小依赖项,可以实现对其他 DLL 的依赖性为零或最小。

如果您选择了“使用 MFC”,则在属性中选择“静态库”使用 MFC。这将消除对 MFC DLL 的任何依赖。

现在,关于用 C++ 编写供 VB 使用的函数的一些小技巧。

  1. VB 使用 __stdcall,所以我们也使用 std 调用约定。
  2. VB 不像 C++ 那样进行名称修饰,所以我们必须使用 extern "C"。
  3. 我们必须导出函数名。`__declspec(dllexport)` 对于 VB 来说很笨拙。因为它还会用下划线修饰函数名。我们将使用 .def 文件。DEF 文件很简单。我们只需要输入函数名即可。例如,如果一个函数如下所示:
    extern "C" int __stdcall HelloVB( int a) {...}

    在 .def 文件中,我们只需写:

    HelloVB

    VB 将识别我们的函数。如果我们使用了 declspec,它可能是 _HelloVb

这是 VB 类型及其在 VC 中的对应类型:

在VB中

在 VC 中:

字节型

unsigned char

Integer 

signed short

long

signed long

single

float

double 

double

currency

signed __int64

字符串

BSTR

所以在这里我们将开始创建 DLL。我们将为每个 VB 变量使用一个函数。

  1. 首先,在我们的项目中插入一个 C++ 文件,然后添加以下代码:
  2. 	
    extern "c" BYTE __stdcall MakeTripByte( BYTE a, LPBYTE b )
    
    	{
    		*b = a + a;
    		return( *b + a );
    	}
    	
    extern "c" short __stdcall MakeTripInteger( short a, short  *b )
    	{
    		*b = a + a;
    		return( *b + a );
    	}
    	
    extern "c" LONG __stdcall MakeTripLong( long a, long *b )
    	{
    		*b = a + a;
    		return( *b + a );
    	}
    
    extern "c" float __stdcall MakeTripSingle( float a, float far * b )
    	{
    		*b = a + a;
    		return( *b + a );
    	}
    	
    extern "c" double __stdcall MakeTripDouble( double a, double far * b )
    	{
    		*b = a + a;
    		return( *b + a );
    	}
    extern "c" __int64 __stdcall MakeTripCurrency(__int64 a, __int64 *b)
    	{
    		*b = (a  + a) ;
    		return (*b + a);
    	}
    
    extern "c" void __stdcall ReverseString( BSTR a )
    	{
    		int i, iLen;
    		BSTR b;
    		LPSTR pA, pB;
    
    #ifdef _UNICODE		
    		iLen = lstrlen( (LPCTSTR) a );
    #else
    		iLen = lstrlen( (LPCSTR) a );
    #endif
    
    		b = SysAllocStringLen( NULL, iLen );
    		
    		pA = (LPSTR)a;
    		pB = (LPSTR)b + iLen -1;
    		
    		for ( i = 0; i < iLen; i++ )
    			*pB-- = *pA++;
    		
    		pA = (LPSTR)a;
    		pB = (LPSTR)b;
    		
    		for ( i = 0; i < iLen; i++ )
    			*pA++ = *pB++;
    		
    		SysFreeString( b );
    	}
    
    
  3. 保存文件。

  4. 然后,在工作区中选择“文件”选项卡。从那里,在项目名称下选择“源文件”。然后选择一个扩展名为 .def 的文件,其名称与项目相同,并在其中添加以下内容到末尾:
    ReverseString		
    MakeTripByte			
    MakeTripDouble		
    MakeTripInteger		
    MakeTripLong		
    MakeTripSingle			
    MakeTripCurrency	
  5. 然后选择 **构建** - > **设置活动配置** 为 Win32 release min size。编译 DLL。关闭 VC。

  6. 现在启动 vb。

在复制粘贴代码之前,让我们看看如何在 VB 中声明我们的 DLL 函数。

[Public | Private] Declare Function_name Lib "libname"  [([arglist])] [As type]

PublicPrivate 定义了函数的范围。在窗体中是 private,但在模块中通常是 public。我们将使用 private。

Declare 用于告知 vb 我们正在从 DLL 导入函数。

然后是函数名。这是我们在 DLL 中键入的内容。然后是 lib 关键字,后面跟着用引号括起来的 lib name。我们必须指定 DLL 的名称(用引号括起来)。指定完整路径始终是更好的选择。例如:c:\project\dll.dll。

然后是参数列表。默认情况下,VB 始终按引用传递参数。所以对于指针参数,我们需要 byref,对于普通参数,我们需要 byval

最后一部分决定了函数将返回什么。请参阅上表。

现在,对于我们上面的 C DLL 函数,在 VB 中的声明将如下所示:

'enter path for tlb .dll. IF no path given then it is assumed to be in the same folder

Private Declare Function MakeTripByte _
Lib "tvb.dll" ( _
    ByVal a As Byte, _
    ByRef b As Byte _
) As Byte

Private Declare Function MakeTripInteger _
Lib "tvb.dll" ( _
    ByVal a As Integer, _
    ByRef b As Integer _
) As Integer

Private Declare Function MakeTripCurrency _
Lib "tvb.dll" ( _
    ByVal a As Currency, _
    ByRef b As Currency _
) As Currency

Private Declare Function MakeTripLong _
Lib "tvb.dll" ( _
    ByVal a As Long, _
    ByRef b As Long _
) As Long

Private Declare Function MakeTripSingle _
Lib "tvb.dll" ( _
    ByVal a As Single, _
    ByRef b As Single _
) As Single

Private Declare Function MakeTripDouble _
Lib "tvb.dll" ( _
    ByVal a As Double, _
    ByRef b As Double _
) As Double

Private Declare Sub ReverseString _
Lib "tvb.dll" ( _
    ByVal a As String _
)

我们做到了。所有这些函数都来自一个 20K 的 VC DLL,没有依赖项,也没有令人困惑的 COM。有关更多详细信息,请参阅项目。

API 函数与 CRT 的对比列表

以下是 API 函数与 CRT Win32 等效函数(Q99456)的对比列表:

-------------------------------------------------------------
The information in this article applies to:

Microsoft Win32 Application Programming Interface (API), included with:
the operating system: Microsoft Windows NT, versions 3.1, 3.5, 3.51 
Microsoft Windows 95

-------------------------------------------------------------


SUMMARY
Many of the C Run-time functions have direct equivalents in the Win32 application
programming interface (API). This article lists the C Run-time functions by category
with their Win32 equivalents or the word "none" if no equivalent exists. 



MORE INFORMATION
NOTE: the functions that are followed by an asterisk (*) are part of the 16-bit C
Run-time only. Functions that are unique to the 32-bit C Run-time are listed separately
in the last section. All other functions are common to both C Run-times. 

Buffer Manipulation

   _memccpy                  none
    memchr                   none
    memcmp                   none
    memcpy                   CopyMemory
   _memicmp                  none
    memmove                  MoveMemory
    memset                   FillMemory, ZeroMemory
   _swab                     none 
Character Classification

     isalnum                 IsCharAlphaNumeric
     isalpha                 IsCharAlpha, GetStringTypeW (Unicode)
   __isascii                 none
     iscntrl                 none, GetStringTypeW (Unicode)
   __iscsym                  none
   __iscsymf                 none
     isdigit                 none, GetStringTypeW (Unicode)
     isgraph                 none
     islower                 IsCharLower, GetStringTypeW (Unicode)
     isprint                 none
     ispunct                 none, GetStringTypeW (Unicode)
     isspace                 none, GetStringTypeW (Unicode)
     isupper                 IsCharUpper, GetStringTypeW (Unicode)
     isxdigit                none, GetStringTypeW (Unicode)
   __toascii                 none
     tolower                 CharLower
    _tolower                 none
     toupper                 CharUpper
    _toupper                 none 
Directory Control

   _chdir                    SetCurrentDirectory
   _chdrive                  SetCurrentDirectory
   _getcwd                   GetCurrentDirectory
   _getdrive                 GetCurrentDirectory
   _mkdir                    CreateDirectory
   _rmdir                    RemoveDirectory
   _searchenv                SearchPath 
File Handling

   _access                   none
   _chmod                    SetFileAttributes
   _chsize                   SetEndOfFile
   _filelength               GetFileSize
   _fstat                    See Note 5
   _fullpath                 GetFullPathName
   _get_osfhandle            none
   _isatty                   GetFileType
   _locking                  LockFileEx
   _makepath                 none
   _mktemp                   GetTempFileName
   _open_osfhandle           none
    remove                   DeleteFile
    rename                   MoveFile
   _setmode                  none
   _splitpath                none
   _stat                     none
   _umask                    none
   _unlink                   DeleteFile 
Creating Text Output Routines

   _displaycursor*           SetConsoleCursorInfo
   _gettextcolor*            GetConsoleScreenBufferInfo
   _gettextcursor*           GetConsoleCursorInfo
   _gettextposition*         GetConsoleScreenBufferInfo
   _gettextwindow*           GetConsoleWindowInfo
   _outtext*                 WriteConsole
   _scrolltextwindow*        ScrollConsoleScreenBuffer
   _settextcolor*            SetConsoleTextAttribute
   _settextcursor*           SetConsoleCursorInfo
   _settextposition*         SetConsoleCursorPosition
   _settextwindow*           SetConsoleWindowInfo
   _wrapon*                  SetConsoleMode 
Stream Routines

    clearerr                 none
    fclose                   CloseHandle
   _fcloseall                none
   _fdopen                   none
    feof                     none
    ferror                   none
    fflush                   FlushFileBuffers
    fgetc                    none
   _fgetchar                 none
    fgetpos                  none
    fgets                    none
   _fileno                   none
   _flushall                 none
    fopen                    CreateFile
    fprintf                  none
    fputc                    none
   _fputchar                 none
    fputs                    none
    fread                    ReadFile
    freopen (std handles)    SetStdHandle
    fscanf                   none
    fseek                    SetFilePointer
    fsetpos                  SetFilePointer
   _fsopen                   CreateFile
    ftell                    SetFilePointer (check return value)
    fwrite                   WriteFile
    getc                     none
    getchar                  none
    gets                     none
   _getw                     none
    printf                   none
    putc                     none
    putchar                  none
    puts                     none
   _putw                     none
    rewind                   SetFilePointer
   _rmtmp                    none
    scanf                    none
    setbuf                   none
    setvbuf                  none
   _snprintf                 none
    sprintf                  wsprintf
    sscanf                   none
   _tempnam                  GetTempFileName
    tmpfile                  none
    tmpnam                   GetTempFileName
    ungetc                   none
    vfprintf                 none
    vprintf                  none
   _vsnprintf                none
    vsprintf                 wvsprintf 
Low-Level I/O

   _close                   _lclose, CloseHandle
   _commit                   FlushFileBuffers
   _creat                   _lcreat, CreateFile
   _dup                      DuplicateHandle
   _dup2                     none
   _eof                      none
   _lseek                   _llseek, SetFilePointer
   _open                    _lopen, CreateFile
   _read                    _lread, ReadFile
   _sopen                    CreateFile
   _tell                     SetFilePointer (check return value)
   _write                   _lread 
Console and Port I/O Routines

   _cgets                    none
   _cprintf                  none
   _cputs                    none
   _cscanf                   none
   _getch                    ReadConsoleInput
   _getche                   ReadConsoleInput
   _inp                      none
   _inpw                     none
   _kbhit                    PeekConsoleInput
   _outp                     none
   _outpw                    none
   _putch                    WriteConsoleInput
   _ungetch                  none 
Memory Allocation

   _alloca                   none
   _bfreeseg*                none
   _bheapseg*                none
    calloc                   GlobalAlloc
   _expand                   none
    free                     GlobalFree
   _freect*                  GlobalMemoryStatus
   _halloc*                  GlobalAlloc
   _heapadd                  none
   _heapchk                  none
   _heapmin                  none
   _heapset                  none
   _heapwalk                 none
   _hfree*                   GlobalFree
    malloc                   GlobalAlloc
   _memavl                   GlobalMemoryStatus
   _memmax                   GlobalMemoryStatus
   _msize*                   GlobalSize
    realloc                  GlobalReAlloc
   _set_new_handler          none
   _set_hnew_handler*        none
   _stackavail*              none 
Process and Environment Control Routines

    abort                    none
    assert                   none
    atexit                   none
   _cexit                    none
   _c_exit                   none
   _exec functions           none
    exit                     ExitProcess
   _exit                     ExitProcess
    getenv                   GetEnvironmentVariable
   _getpid                   GetCurrentProcessId
    longjmp                  none
   _onexit                   none
    perror                   FormatMessage
   _putenv                   SetEnvironmentVariable
    raise                    RaiseException
    setjmp                   none
    signal (ctrl-c only)     SetConsoleCtrlHandler
   _spawn functions          CreateProcess
    system                   CreateProcess 
String Manipulation

   strcat, wcscat            lstrcat
   strchr, wcschr            none
   strcmp, wcscmp            lstrcmp
   strcpy, wcscpy            lstrcpy
   strcspn, wcscspn          none
  _strdup, _wcsdup           none
   strerror                  FormatMessage
  _strerror                  FormatMessage
  _stricmp, _wcsicmp         lstrcmpi
   strlen, wcslen            lstrlen
  _strlwr, _wcslwr           CharLower, CharLowerBuffer
   strncat, wcsncat          none
   strncmp, wcsncmp          none
   strncpy, wcsncpy          none
  _strnicmp, _wcsnicmp       none
  _strnset, _wcsnset         FillMemory, ZeroMemory
   strpbrk, wcspbrk          none
   strrchr, wcsrchr          none
  _strrev, _wcsrev           none
  _strset, _wcsset           FillMemory, ZeroMemory
   strspn, wcsspn            none
   strstr, wcsstr            none
   strtok, wcstok            none
  _strupr, _wcsupr           CharUpper, CharUpperBuffer 
MS-DOS Interface

  _bdos*                     none
  _chain_intr*               none
  _disable*                  none
  _dos_allocmem*             GlobalAlloc
  _dos_close*                CloseHandle
  _dos_commit*               FlushFileBuffers
  _dos_creat*                CreateFile
  _dos_creatnew*             CreateFile
  _dos_findfirst*            FindFirstFile
  _dos_findnext*             FindNextFile
  _dos_freemem*              GlobalFree
  _dos_getdate*              GetSystemTime
  _dos_getdiskfree*          GetDiskFreeSpace
  _dos_getdrive*             GetCurrentDirectory
  _dos_getfileattr*          GetFileAttributes
  _dos_getftime*             GetFileTime
  _dos_gettime*              GetSystemTime
  _dos_getvect*              none
  _dos_keep*                 none
  _dos_open*                 OpenFile
  _dos_read*                 ReadFile
  _dos_setblock*             GlobalReAlloc
  _dos_setdate*              SetSystemTime
  _dos_setdrive*             SetCurrentDirectory
  _dos_setfileattr*          SetFileAttributes
  _dos_setftime*             SetFileTime
  _dos_settime*              SetSystemTime
  _dos_setvect*              none
  _dos_write*                WriteFile
  _dosexterr*                GetLastError
  _enable*                   none
  _FP_OFF*                   none
  _FP_SEG*                   none
  _harderr*                  See Note 1
  _hardresume*               See Note 1
  _hardretn*                 See Note 1
  _int86*                    none
  _int86x*                   none
  _intdos*                   none
  _intdosx*                  none
  _segread*                  none 
Time

   asctime                   See Note 2
   clock                     See Note 2
   ctime                     See Note 2
   difftime                  See Note 2
   _ftime                    See Note 2
   _getsystime               GetLocalTime
   gmtime                    See Note 2
   localtime                 See Note 2
   mktime                    See Note 2
   _strdate                  See Note 2
   _strtime                  See Note 2
   time                      See Note 2
   _tzset                    See Note 2
   _utime                    SetFileTime 
Virtual Memory Allocation

   _vfree*                   See Note 3
   _vheapinit*               See Note 3
   _vheapterm*               See Note 3
   _vload*                   See Note 3
   _vlock*                   See Note 3
   _vlockcnt*                See Note 3
   _vmalloc*                 See Note 3
   _vmsize*                  See Note 3
   _vrealloc*                See Note 3
   _vunlock*                 See Note 3 
32-Bit C Run Time

   _beginthread              CreateThread
   _cwait                    WaitForSingleObject w/ GetExitCodeProcess
   _endthread                ExitThread
   _findclose                FindClose
   _findfirst                FindFirstFile
   _findnext                 FindNextFile
   _futime                   SetFileTime
   _get_osfhandle            none
   _open_osfhandle           none
   _pclose                   See Note 4
   _pipe                     CreatePipe
   _popen                    See Note 4 


NOTE 1: The _harderr functions do not exist in the Win32 API. However, much of
their functionality is available through structured exception handling. 

NOTE 2: The time functions are based on a format that is not used in Win32. There
are specific Win32 time functions that are documented in the Help file. 

NOTE 3: The virtual memory functions listed in this document are specific to the
MS-DOS environment and were written to access memory beyond the 640K of RAM available
in MS-DOS. Because this limitation does not exist in Win32, the standard memory 
allocation functions should be used. 

NOTE 4: While _pclose() and _popen() do not have direct Win32 equivalents, you can 
(with some work) simulate them with the following calls: 

   _popen                     CreatePipe
                              CreateProcess

   _pclose                    WaitForSingleObject
                              CloseHandle 

NOTE 5: GetFileInformationByHandle() is the Win32 equivalent for the _fstat() 
C Run-time function. However, GetFileInformationByHandle() is not supported by 
Win32s version 1.1. It is supported in Win32s 1.2. GetFileSize(), 
GetFileAttributes(), GetFileTime(), and GetFileTitle() are supported by
Win32s 1.1 and 1.2. 

Additional query words: 3.10 3.50 4.00 

Keywords : kbOSWinNT310 kbOSWinNT350 kbOSWinNT351 kbOSWin95 
Issue type : 
Technology : kbOSWinNT kbOSWinSearch 


Last Reviewed: December 14, 2000
© 2001 Microsoft Corporation. All rights reserved. Terms of Use.

请访问 **我的网站** 获取更多教程、技巧和参考资料。

© . All rights reserved.