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






4.60/5 (9投票s)
2001年11月4日
4分钟阅读

192299

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 基准的好处是:
- 它很紧凑。
- 没有 CRT 负担。
- ATL 提供了自己的入口点,因此很方便。
- 如果我们不使用 ATL DLL,那么一个普通的 DLL 会大两到三倍。
那么如何创建 ATL DLL 呢?这很简单。
请遵循以下步骤
- 从文件菜单中选择“新建项目”。
- 选择“ATL COM 向导”。
- 我不推荐使用 CRT 函数,所以这里是我们看到的内容:
-
要使用 CRT,请勾选“支持 MFC”复选框,如下图所示。
- 选择“允许合并代理/存根代码”。
ATL 有多种配置类型,但我们主要关注的是“Win32 MIN dependency”或“Win32 unicode min dependency”。注意:Unicode 仅适用于 Windows NT/2000/XP,不支持 Win 95/98/Me。
通过使用最小依赖项,可以实现对其他 DLL 的依赖性为零或最小。
如果您选择了“使用 MFC”,则在属性中选择“静态库”使用 MFC。这将消除对 MFC DLL 的任何依赖。
现在,关于用 C++ 编写供 VB 使用的函数的一些小技巧。
- VB 使用
__stdcall
,所以我们也使用 std 调用约定。 - VB 不像 C++ 那样进行名称修饰,所以我们必须使用 extern "C"。
- 我们必须导出函数名。`__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 变量使用一个函数。
- 首先,在我们的项目中插入一个 C++ 文件,然后添加以下代码:
- 保存文件。
- 然后,在工作区中选择“文件”选项卡。从那里,在项目名称下选择“源文件”。然后选择一个扩展名为 .def 的文件,其名称与项目相同,并在其中添加以下内容到末尾:
ReverseString MakeTripByte MakeTripDouble MakeTripInteger MakeTripLong MakeTripSingle MakeTripCurrency
- 然后选择 **构建** - > **设置活动配置** 为 Win32 release min size。编译 DLL。关闭 VC。
- 现在启动 vb。
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 ); }
在复制粘贴代码之前,让我们看看如何在 VB 中声明我们的 DLL 函数。
[Public | Private] Declare Function_name Lib "libname" [([arglist])] [As type]
Public
或 Private
定义了函数的范围。在窗体中是 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.
请访问 **我的网站** 获取更多教程、技巧和参考资料。