mjones Posted October 14, 2012 Posted October 14, 2012 i'm having trouble linking a simple dll to do function detouring in windows. everything is pretty straightforward but i haven't been able to resolve these linking errors:test.obj : error LNK2005: "void * (__stdcall* pCreateFileW)(wchar_t const *,unsigned long,unsigned long,struct _SECURITY_ATTRIBUTES *,unsigned long,unsigned long,void *)" (?pCreateFileW@@3P6GPAXPB_WKKPAU_SECURITY_ATTRIBUTES@@KKPAX@ZA) already defined in main.objZ:\test\Debug\test.dll : fatal error LNK1169: one or more multiply defined symbols foundhere is what i've done thus far.1. installing detours- downloaded detours express 3.0 from http://research.micr...ojects/detours/- added VC10\bin to %PATH%- ran vcvars32.bat- ran nmake under detours src and samples directories- copied contents of detours include and lib.X86 directories to VC include and lib directories, respectivelyall of that went off without a hitch, as they say.2. started a new project in vc++ 2010, type dll, empty application. i have three files:test.h:// test.h#ifndef _TELLME_H_#define _TELLME_H_#endif#include <Windows.h>HANDLE (WINAPI *pCreateFileW)(LPCTSTR lpFileName, DWORD dwDesiredAccess, DWORD dwShareMode, LPSECURITY_ATTRIBUTES lpSecurityAttributes, DWORD dwCreationDisposition, DWORD dwFlagsAndAttributes, HANDLE hTemplateFile) = CreateFileW;HANDLE WINAPI MyCreateFileW(LPCTSTR lpFileName, DWORD dwDesiredAccess, DWORD dwShareMode, LPSECURITY_ATTRIBUTES lpSecurityAttributes, DWORD dwCreationDisposition, DWORD dwFlagsAndAttributes, HANDLE hTemplateFile);test.cpp:// test.cpp#include "test.h"HANDLE WINAPI MyCreateFileW(LPCTSTR lpFileName, DWORD dwDesiredAccess, DWORD dwShareMode, LPSECURITY_ATTRIBUTES lpSecurityAttributes, DWORD dwCreationDisposition, DWORD dwFlagsAndAttributes, HANDLE hTemplateFile) {OutputDebugString(lpFileName);return pCreateFileW(lpFileName, dwDesiredAccess, dwShareMode, lpSecurityAttributes, dwCreationDisposition, dwFlagsAndAttributes, hTemplateFile);}main.cpp:// main.cpp#pragma comment(lib, "detours.lib")#include "test.h"#include "detours.h"__declspec(dllexport) INT APIENTRY DllMain(HMODULE hDLL, DWORD Reason, LPVOID Reserved) {switch(Reason) {case DLL_PROCESS_ATTACH:DisableThreadLibraryCalls(hDLL);DetourTransactionbegin();DetourUpdateThread(GetCurrentThread());DetourAttach(&(PVOID&)pCreateFileW, MyCreateFileW);if(DetourTransactionCommit() == NO_ERROR)OutputDebugString(L"\nCreateFileW() detoured successfully\n");break;case DLL_PROCESS_DETACH:DetourTransactionbegin();DetourUpdateThread(GetCurrentThread());DetourDetach(&(PVOID&)pCreateFileW, MyCreateFileW);if(DetourTransactionCommit() == NO_ERROR)OutputDebugString(L"\nCreateFileW() detour detached successfully\n");break;}return TRUE;}when i build the project, i get the linker errors mentioned in the top of the post. i've been googling around but the results coming back just say to "find where the problem is" and i've got no idea what it is i should be looking for to figure out "where the problem is". i added /verbose:lib into the linker options and the output listed the libraries, but i can't tell which, if any, are problematic or if the ordering is the issue (and what the proper order should be) or what.here is the output from the build, using /verbose:lib:------ Build started: Project: test, Configuration: Debug Win32 ------Build started 10/14/2012 1:23:19 PM.InitializeBuildStatus:Touching "Debug\test.unsuccessfulbuild".ClCompile:All outputs are up-to-date.test.obj : error LNK2005: "void * (__stdcall* pCreateFileW)(wchar_t const *,unsigned long,unsigned long,struct _SECURITY_ATTRIBUTES *,unsigned long,unsigned long,void *)" (?pCreateFileW@@3P6GPAXPB_WKKPAU_SECURITY_ATTRIBUTES@@KKPAX@ZA) already defined in main.objSearching librariesSearching C:\Program Files\Microsoft SDKs\Windows\v7.0A\lib\kernel32.lib:Searching C:\Program Files\Microsoft SDKs\Windows\v7.0A\lib\user32.lib:Searching C:\Program Files\Microsoft SDKs\Windows\v7.0A\lib\gdi32.lib:Searching C:\Program Files\Microsoft SDKs\Windows\v7.0A\lib\winspool.lib:Searching C:\Program Files\Microsoft SDKs\Windows\v7.0A\lib\comdlg32.lib:Searching C:\Program Files\Microsoft SDKs\Windows\v7.0A\lib\advapi32.lib:Searching C:\Program Files\Microsoft SDKs\Windows\v7.0A\lib\shell32.lib:Searching C:\Program Files\Microsoft SDKs\Windows\v7.0A\lib\ole32.lib:Searching C:\Program Files\Microsoft SDKs\Windows\v7.0A\lib\oleaut32.lib:Searching C:\Program Files\Microsoft SDKs\Windows\v7.0A\lib\uuid.lib:Searching C:\Program Files\Microsoft SDKs\Windows\v7.0A\lib\odbc32.lib:Searching C:\Program Files\Microsoft SDKs\Windows\v7.0A\lib\odbccp32.lib:Searching C:\xp\Development\Microsoft Visual Studio 10.0\VC\lib\detours.lib:Searching C:\xp\Development\Microsoft Visual Studio 10.0\VC\lib\MSVCRTD.lib:Searching C:\xp\Development\Microsoft Visual Studio 10.0\VC\lib\OLDNAMES.lib:Searching C:\Program Files\Microsoft SDKs\Windows\v7.0A\lib\kernel32.lib:Searching C:\Program Files\Microsoft SDKs\Windows\v7.0A\lib\user32.lib:Searching C:\Program Files\Microsoft SDKs\Windows\v7.0A\lib\gdi32.lib:Searching C:\Program Files\Microsoft SDKs\Windows\v7.0A\lib\winspool.lib:Searching C:\Program Files\Microsoft SDKs\Windows\v7.0A\lib\comdlg32.lib:Searching C:\Program Files\Microsoft SDKs\Windows\v7.0A\lib\advapi32.lib:Searching C:\Program Files\Microsoft SDKs\Windows\v7.0A\lib\shell32.lib:Searching C:\Program Files\Microsoft SDKs\Windows\v7.0A\lib\ole32.lib:Searching C:\Program Files\Microsoft SDKs\Windows\v7.0A\lib\oleaut32.lib:Searching C:\Program Files\Microsoft SDKs\Windows\v7.0A\lib\uuid.lib:Searching C:\Program Files\Microsoft SDKs\Windows\v7.0A\lib\odbc32.lib:Searching C:\Program Files\Microsoft SDKs\Windows\v7.0A\lib\odbccp32.lib:Searching C:\xp\Development\Microsoft Visual Studio 10.0\VC\lib\detours.lib:Finished searching librariesCreating library Z:\test\Debug\test.lib and object Z:\test\Debug\test.expSearching librariesSearching C:\Program Files\Microsoft SDKs\Windows\v7.0A\lib\kernel32.lib:Searching C:\Program Files\Microsoft SDKs\Windows\v7.0A\lib\user32.lib:Searching C:\Program Files\Microsoft SDKs\Windows\v7.0A\lib\gdi32.lib:Searching C:\Program Files\Microsoft SDKs\Windows\v7.0A\lib\winspool.lib:Searching C:\Program Files\Microsoft SDKs\Windows\v7.0A\lib\comdlg32.lib:Searching C:\Program Files\Microsoft SDKs\Windows\v7.0A\lib\advapi32.lib:Searching C:\Program Files\Microsoft SDKs\Windows\v7.0A\lib\shell32.lib:Searching C:\Program Files\Microsoft SDKs\Windows\v7.0A\lib\ole32.lib:Searching C:\Program Files\Microsoft SDKs\Windows\v7.0A\lib\oleaut32.lib:Searching C:\Program Files\Microsoft SDKs\Windows\v7.0A\lib\uuid.lib:Searching C:\Program Files\Microsoft SDKs\Windows\v7.0A\lib\odbc32.lib:Searching C:\Program Files\Microsoft SDKs\Windows\v7.0A\lib\odbccp32.lib:Searching C:\xp\Development\Microsoft Visual Studio 10.0\VC\lib\detours.lib:Searching C:\xp\Development\Microsoft Visual Studio 10.0\VC\lib\MSVCRTD.lib:Searching C:\xp\Development\Microsoft Visual Studio 10.0\VC\lib\OLDNAMES.lib:Finished searching librariesZ:\test\Debug\test.dll : fatal error LNK1169: one or more multiply defined symbols foundBuild FAILED.Time Elapsed 00:00:03========== Build: 0 succeeded, 1 failed, 0 up-to-date, 0 skipped ==========
kao Posted October 14, 2012 Posted October 14, 2012 Include guard in test.h is wrong. #endif should be at end-of-file, not right after #define 1
mjones Posted October 14, 2012 Author Posted October 14, 2012 good catch, thanks! modified and rebuilt, still getting the same link errors unfortunately.
kao Posted October 14, 2012 Posted October 14, 2012 Moving all code into one file and getting rid of test.h and test.cpp solves all the problems. Good enough for me. Hopefully some smarter person will be able to suggest proper solution.
mjones Posted October 15, 2012 Author Posted October 15, 2012 all the examples i've seen have everything in one file. i want to end up detouring several dozen APIs though so would really like to separate things if possible.
atom0s Posted October 15, 2012 Posted October 15, 2012 You can achieve what you want using externs:main.cpp:#include <Windows.h>#pragma comment( lib, "detours.lib" )#include <detours.h>#include "CreateFileW.h"extern "C" HANDLE ( WINAPI *Real_CreateFileW )( LPCWSTR, DWORD, DWORD, LPSECURITY_ATTRIBUTES, DWORD, DWORD, HANDLE );BOOL WINAPI DllMain( HINSTANCE hInstance, DWORD fdwReason, LPVOID lpvReserved ){ switch (fdwReason) { case DLL_PROCESS_ATTACH: { DisableThreadLibraryCalls( hInstance ); DetourTransactionbegin(); DetourUpdateThread( GetCurrentThread() ); DetourAttach( &(PVOID&)Real_CreateFileW, Mine_CreateFileW ); DetourTransactionCommit(); break; } } return TRUE;}CreateFileW.h:#ifndef __CREATEFILEW_H_INCLUDED__#define __CREATEFILEW_H_INCLUDED__#include <Windows.h>HANDLE WINAPI Mine_CreateFileW( _In_ LPCWSTR lpFileName, _In_ DWORD dwDesiredAccess, _In_ DWORD dwShareMode, _In_opt_ LPSECURITY_ATTRIBUTES lpSecurityAttributes, _In_ DWORD dwCreationDisposition, _In_ DWORD dwFlagsAndAttributes, _In_opt_ HANDLE hTemplateFile );#endif // __CREATEFILEW_H_INCLUDED__CreateFileW.cpp:#include "CreateFileW.h"extern "C"{ HANDLE ( WINAPI *Real_CreateFileW )( LPCWSTR, DWORD, DWORD, LPSECURITY_ATTRIBUTES, DWORD, DWORD, HANDLE ) = CreateFileW;}HANDLE WINAPI Mine_CreateFileW( _In_ LPCWSTR lpFileName, _In_ DWORD dwDesiredAccess, _In_ DWORD dwShareMode, _In_opt_ LPSECURITY_ATTRIBUTES lpSecurityAttributes, _In_ DWORD dwCreationDisposition, _In_ DWORD dwFlagsAndAttributes, _In_opt_ HANDLE hTemplateFile ){ OutputDebugString( lpFileName ); return Real_CreateFileW( lpFileName, dwDesiredAccess, dwShareMode, lpSecurityAttributes, dwCreationDisposition, dwFlagsAndAttributes, hTemplateFile );}
iLovro Posted October 15, 2012 Posted October 15, 2012 (edited) You're providing two definitions for pCreateFileW. You defined the function pCreateFileW in test.h and then you included test.h in both test.cpp and main.cpp. Doing this causes the linker to get confused as it doesn't know which definition to use (even though they're the same). This would be the same as declaring two variables with the same name in one .cpp.To resolve this issue do this://test.hextern HANDLE (WINAPI *pCreateFileW)(args...); //no = CreateFileW. You could (not 100% sure though) but it is not a good practice. When dealing with externs it is always the best to provide the declaration in a .h and the definition in a .cpp.MyCreateFileW prototype...//test.cpp#include "test.h"MyCreateFileW definition...//main.cpp#include <other stuff>#include "test.h"pCreateFileW = CreateFileW;other stuff here...What extern really does is it exposes your variable (which is defined in some .cpp) to any .cpp that includes the .h in which that variable was declared.Hope this helps,iLovro Edited October 18, 2012 by iLovro 2
Recommended Posts
Create an account or sign in to comment
You need to be a member in order to leave a comment
Create an account
Sign up for a new account in our community. It's easy!
Register a new accountSign in
Already have an account? Sign in here.
Sign In Now