最近在msdn查阅:Using Thread Local Storage in a dynamic-link library一文(http://msdn.microsoft.com/en-us/library/ms686997(v=VS.85).aspx),被此举的例子吓了一跳,随后赶紧写了个小程序,才知道例子程序运用extern来试图声明.dll里导出的函数,然后直接使用是完全不正确的。 这完全是一种想当然的做法。
我对其进行了更正:
// TestDll.dll的生成:
// The DLL code
#include <windows.h>
static DWORD dwTlsIndex; // address of shared memory
// DllMain() is the entry-point function for this DLL.
BOOL WINAPI DllMain(HINSTANCE hinstDLL, // DLL module handle
DWORD fdwReason, // reason called
LPVOID lpvReserved) // reserved
{
LPVOID lpvData;
BOOL fIgnore;
switch (fdwReason)
{
// The DLL is loading due to process
// initialization or a call to LoadLibrary.
case DLL_PROCESS_ATTACH:
// Allocate a TLS index.
if ((dwTlsIndex = TlsAlloc()) == TLS_OUT_OF_INDEXES)
return FALSE;
// No break: Initialize the index for first thread.
// The attached process creates a new thread.
case DLL_THREAD_ATTACH:
// Initialize the TLS index for this thread.
lpvData = (LPVOID) LocalAlloc(LPTR, 256);
if (lpvData != NULL)
fIgnore = TlsSetValue(dwTlsIndex, lpvData);
break;
// The thread of the attached process terminates.
case DLL_THREAD_DETACH:
// Release the allocated memory for this thread.
lpvData = TlsGetValue(dwTlsIndex);
if (lpvData != NULL)
LocalFree((HLOCAL) lpvData);
break;
// DLL unload due to process termination or FreeLibrary.
case DLL_PROCESS_DETACH:
// Release the allocated memory for this thread.
lpvData = TlsGetValue(dwTlsIndex);
if (lpvData != NULL)
LocalFree((HLOCAL) lpvData);
// Release the TLS index.
TlsFree(dwTlsIndex);
break;
default:
break;
}
return TRUE;
UNREFERENCED_PARAMETER(hinstDLL);
UNREFERENCED_PARAMETER(lpvReserved);
}
// The export mechanism used here is the __declspec(export)
// method supported by Microsoft Visual Studio, but any
// other export method supported by your development
// environment may be substituted.
#ifdef __cplusplus // If used by C++ code,
extern "C" { // we need to export the C interface
#endif
__declspec(dllexport)
BOOL WINAPI StoreData(DWORD dw)
{
LPVOID lpvData;
DWORD * pData; // The stored memory pointer
lpvData = TlsGetValue(dwTlsIndex);
if (lpvData == NULL)
{
lpvData = (LPVOID) LocalAlloc(LPTR, 256);
if (lpvData == NULL)
return FALSE;
if (!TlsSetValue(dwTlsIndex, lpvData))
return FALSE;
}
pData = (DWORD *) lpvData; // Cast to my data type.
// In this example, it is only a pointer to a DWORD
// but it can be a structure pointer to contain more complicated data.
(*pData) = dw;
return TRUE;
}
__declspec(dllexport)
BOOL WINAPI GetData(DWORD *pdw)
{
LPVOID lpvData;
DWORD * pData; // The stored memory pointer
lpvData = TlsGetValue(dwTlsIndex);
if (lpvData == NULL)
return FALSE;
pData = (DWORD *) lpvData;
(*pdw) = (*pData);
return TRUE;
}
#ifdef __cplusplus
}
#endif
避免名字冲突最好还是用.def文件
#include
<windows.h>
#include
<stdio.h>
#include
<iostream>
using
namespace std;
#define
THREADCOUNT 4
#define
DLL_NAME TEXT("TestDll.dll")
VOID
ErrorExit ( LPSTR
);
typedef
BOOL ( WINAPI * MYPROCSET )( DWORD
);
typedef
BOOL ( WINAPI * MYPROCGET )( DWORD
*);
MYPROCSET
ProcStoreData
;
MYPROCGET
ProcGetData
;
DWORD
WINAPI ThreadFunc ( VOID
)
{
int i
;
if (! ProcStoreData ( GetCurrentThreadId
()))
ErrorExit ( "StoreData error"
);
for ( i =0; i < THREADCOUNT ; i
++)
{
DWORD dwOut
;
if (! ProcGetData (& dwOut
))
ErrorExit ( "GetData error"
);
if ( dwOut != GetCurrentThreadId
())
printf ( "thread %d: data is incorrect (%d)/n" , GetCurrentThreadId (), dwOut
);
else printf ( "thread %d: data is correct/n" , GetCurrentThreadId
());
Sleep
(0);
}
return
0;
}
int
main ( VOID
)
{
DWORD IDThread
;
HANDLE hThread [ THREADCOUNT
];
int i
;
HMODULE hm
;
// Load the DLL
hm = LoadLibrary ( DLL_NAME
);
if (! hm
)
{
ErrorExit ( "DLL failed to load"
);
}
// 不能简单的声明:
//extern "C" BOOL WINAPI StoreData(DWORD dw);
//extern "C" BOOL WINAPI GetData(DWORD *pdw);
ProcStoreData = ( MYPROCSET )( GetProcAddress ( hm , "StoreData" ));
ProcGetData = ( MYPROCGET )( GetProcAddress ( hm , "GetData" ));
// Create multiple threads.
for ( i = 0; i < THREADCOUNT ; i
++)
{
hThread [ i ] = CreateThread ( NULL ,
// default security attributes
0,
// use default stack size
(
LPTHREAD_START_ROUTINE ) ThreadFunc ,
// thread function
NULL ,
// no thread function argument
0,
// use default creation flags
&
IDThread );
// returns thread identifier
// Check the return value for success.
if ( hThread [ i ] == NULL
)
ErrorExit ( "CreateThread error/n"
);
}
WaitForMultipleObjects ( THREADCOUNT , hThread , TRUE , INFINITE
);
FreeLibrary ( hm
);
cin . get
();
return
0;
}
VOID
ErrorExit ( LPSTR lpszMessage
)
{
fprintf ( stderr , "%s/n" , lpszMessage
);
ExitProcess
(0);