在介绍入口函数之前,先介绍一下几种运行时的库(Runtime Library)以及他们对应的链接选项:
1.Multi-threaded Debug (/MTd)
这个是debug版本的多线程库,静态链接的。
2.Multi-threaded (/MT)
这是release版本的多线程库,静态链接的。
3.Multi-threaded Debug DLL (/MDd)
这是debug版本的多线程库,动态链接的。
4.Multi-threaded DLL (/MD)
这是release版本的多线程库,动态链接的。
debug版本的运行库增加了一些错误检查的代码,如:堆栈的溢出检查,基于cookie的安全检查,基于CheckStackVar的检查。这些额外的代码可以帮助检测编码中的非安全错误。因此debug版本的运行效率没有release版本高。后面的章节将详细介绍debug运行时的安全检查策略。
静态链接运行时与动态链接运行时的区别在于,静态链接会将整个运行时的代码链接到模块中(也就是说每个模块都有一份运行时的代码),而动态链接会以共享的方式被模块使用(也就是说每个模块都会共享一份运行时的代码)。这样会导致在不同的链接方式下,它们有自己需要注意的地方。
1.采用/MD选项
a.由于是动态链接运行时,那么最终生成的模块体积会很小
b.每个模块都共享一份运行时代码,那么堆的申请与释放很自由,A模块申请堆,B模块释放堆,这样是可以得。
2.采用/MT选项
a.由于是静态链接的,那么每个模块都会包含一份运行时代码,自然会增加其体积。但是这样可以在缺少运行时的系统中稳定的运行。
b.每个模块都会包含一份运行时代码,那么只能在自己的模块中释放自己申请的堆,否则会出现错误。
注意:多个模块的情况下,必须选择相同的选项,不可以混用。
以下是测试方案:
在A DLL中添加申请堆和释放堆得代码,在B DLL中添加同样的代码,并将它们以不同的链接方式生成(/MD,/MT)。
在主程序中加载这两个DLL,并分别获取它们的导出函数。
A DLL代码如下:
-
-
-
- #include "stdafx.h"
-
- char* MallocHeap( int n )
- {
- if ( n <= 0 )
- {
- return NULL;
- }
-
- char* pHeap = new char( n );
-
- if ( pHeap )
- {
- return pHeap;
- }
- else
- {
- return NULL;
- }
-
- return NULL;
- }
-
-
- BOOL FreeHeap( char* pHeap )
- {
- if ( pHeap )
- {
- delete pHeap;
- pHeap = NULL;
-
- return TRUE;
- }
- else
- {
- return FALSE;
- }
-
- return FALSE;
- }
B DLL代码如下:
-
-
-
- #include "stdafx.h"
-
-
- char* MallocHeap( int n )
- {
- if ( n <= 0 )
- {
- return NULL;
- }
-
- char* pHeap = new char( n );
-
- if ( pHeap )
- {
- return pHeap;
- }
- else
- {
- return NULL;
- }
-
- return NULL;
- }
-
-
- BOOL FreeHeap( char* pHeap )
- {
- if ( pHeap )
- {
- delete pHeap;
- pHeap = NULL;
-
- return TRUE;
- }
- else
- {
- return FALSE;
- }
-
- return FALSE;
- }
主程序代码如下:
-
-
-
- #include "stdafx.h"
- #include <windows.h>
- #include <string.h>
-
- typedef char* ( *FunMallocHeap ) ( int );
- typedef BOOL ( *FunFreeHeap ) ( char* );
-
- int _tmain(int argc, _TCHAR* argv[])
- {
- HMODULE hDllA = ::LoadLibrary( L"A_DLL.dll" );
- HMODULE hDllB = ::LoadLibrary( L"B_DLL.dll" );
-
- if ( !hDllA || !hDllB )
- {
- return 1;
- }
-
-
- FunMallocHeap pMallocHeapA = NULL;
- pMallocHeapA = ( FunMallocHeap )::GetProcAddress( hDllA, "MallocHeap" );
-
-
- FunMallocHeap pMallocHeapB = NULL;
- pMallocHeapB = ( FunMallocHeap )::GetProcAddress( hDllB, "MallocHeap" );
-
- if ( !pMallocHeapA || !pMallocHeapB )
- {
- return 1;
- }
-
-
-
- FunFreeHeap pFreeHeapA = NULL;
- pFreeHeapA = ( FunFreeHeap )::GetProcAddress( hDllA, "FreeHeap" );
-
-
- FunFreeHeap pFreeHeapB = NULL;
- pFreeHeapB = ( FunFreeHeap )::GetProcAddress( hDllB, "FreeHeap" );
-
- if ( !pFreeHeapA || !pFreeHeapA )
- {
- return 1;
- }
-
- if ( argc < 3 )
- {
- printf( "请输入参数:(A B)(A A)前者为申请模块,后者为释放模块\r\n" );
-
- return 3;
- }
-
- wchar_t szMallocObj[10];
- wcscpy( szMallocObj, argv[1] );
-
- wchar_t szFreeObj[10];
- wcscpy( szFreeObj, argv[2] );
-
- if ( wcscmp( szMallocObj, L"A") == 0 )
- {
-
- char*p = NULL;
- p = pMallocHeapA( 10 );
-
- if ( wcscmp( szFreeObj, L"A") == 0 )
- {
-
- BOOL bRet = pFreeHeapA( p );
- if ( bRet )
- {
- ::MessageBox( NULL, L"A DLL FreeHeap OK", L"Tips", MB_OK );
- }
- else
- {
- ::MessageBox( NULL, L"A DLL FreeHeap Fail", L"Tips", MB_OK );
- }
-
- }
-
- if ( wcscmp( szFreeObj, L"B") == 0 )
- {
-
- BOOL bRet = pFreeHeapB( p );
- if ( bRet )
- {
- ::MessageBox( NULL, L"B DLL FreeHeap OK", L"Tips", MB_OK );
- }
- else
- {
- ::MessageBox( NULL, L"B DLL FreeHeap Fail", L"Tips", MB_OK );
- }
- }
- }
-
-
-
- if ( wcscmp( szMallocObj, L"B") == 0 )
- {
-
- char*p = NULL;
- p = pMallocHeapB( 10 );
-
- if ( wcscmp( szFreeObj, L"A") == 0 )
- {
-
- BOOL bRet = pFreeHeapA( p );
- if ( bRet )
- {
- ::MessageBox( NULL, L"A DLL FreeHeap OK", L"Tips", MB_OK );
- }
- else
- {
- ::MessageBox( NULL, L"A DLL FreeHeap Fail", L"Tips", MB_OK );
- }
-
- }
-
- if ( wcscmp( szFreeObj, L"B") == 0 )
- {
-
- BOOL bRet = pFreeHeapB( p );
- if ( bRet )
- {
- ::MessageBox( NULL, L"B DLL FreeHeap OK", L"Tips", MB_OK );
- }
- else
- {
- ::MessageBox( NULL, L"B DLL FreeHeap Fail", L"Tips", MB_OK );
- }
- }
- }
-
- return 0;
- }
先使用/MD链接各个模块并运行,效果如下:
A申请A释放:

A申请B释放:

B申请B释放:

B申请A释放:

现在使用/MT方式链接,并测试如下;
A申请A释放:

A申请B释放:

B申请B释放:

B申请A释放:

可见,测试结果说明了/MD和/MT的区别所在。
下一节将详细介绍这两张不同运行时的更细节的区别。