본문 바로가기
C | C++ | VC++

[Tip]32bit 프로그램에서 64bit DLL DllRegisterServer 등록하기

by 두루물 2010. 9. 24.

오늘도 잠시 유용한 팁하나 올립니다.
윈7 32비트 응용프로그램에서 64비트 DLL 호출 및 등록은 죽었다 깨어나도 안된다.
그리고 윈도우 95부터 등장한 32비트에서 16비트 하위 호환실행을 지원하기 위한 WOW(Windows-On-Windows) 시스템에 의해 이제는 64비트 os하의 32bit 어플들이 지원되긴 하는데 이 32비트 응용프로그램들은 (윈도우즈 파일들)모두 SysWOW64 폴더로 리다이렉션 되기 때문에 System32 하의 64비트 프로그램들은 호출이 기본적으로 안되게 되어 있다. 아래 소스를 참조 바란다.

따라서, 직접 DLL을 로드하여 DllRegisterServer 를 호출하려면 호출자 EXE도 같은 64비트여야 한다.
여기서는 간략하게 32비트 EXE에서 64비트 DLL을 등록하는 방법을 설명한다.
탐색기 팝업메뉴를 제어하기 위한 Shell Extension DLL 은 64비트 OS에선 반드시 64비트로 또한 작성되어야 함.

BOOL DEApp::RegisterShellCommand(BOOL bRegist)
{
 TCHAR szOS[256];
 int whatbit;
 OSVERSIONINFOEX osvi;
 TCHAR szDLL[MAX_PATH];
 GetOSString(szOS,&osvi,&whatbit);
 GetHomeDirectory(szDLL);
 if(whatbit == 64)
  lstrcat(szDLL,"DEShl64.dll");
 else
  lstrcat(szDLL,"DEShl.DLL");
 
 int whatsize = sizeof(int);
 typedef BOOL (WINAPI *LPFN_Wow64Disable)(PVOID* OldValue);
 typedef BOOL (WINAPI *LPFN_Wow64Revert)(PVOID OldValue);
 PVOID OldValue;
 LPFN_Wow64Disable pWowDis = NULL;
 LPFN_Wow64Revert pWowRev = NULL;
 BOOL bRet = 0;
 BOOL fc=1;
 //i am 32bit app and os is 64bit,register 64bit dll and
 //redirect folder.krkim
 if(whatsize == 4 && whatbit == 64){
  pWowDis = (LPFN_Wow64Disable) GetProcAddress(GetModuleHandle(TEXT("kernel32.dll")),
   "Wow64DisableWow64FsRedirection");
  pWowRev = (LPFN_Wow64Revert) GetProcAddress(GetModuleHandle(TEXT("kernel32.dll")),
   "Wow64RevertWow64FsRedirection");
  if(pWowDis)
   bRet = pWowDis(&OldValue);
 
  TCHAR szEXE[MAX_PATH*2];
  if(bRegist){
   wsprintf(szEXE,"/s \"%s\"",szDLL);
   ShellExecute(NULL,_T("open"),"regsvr32",szEXE,NULL,SW_SHOWDEFAULT);
  }
  else{
   wsprintf(szEXE,"/u /s \"%s\"",szDLL);
   ShellExecute(NULL,_T("open"),"regsvr32",szEXE,NULL,SW_SHOWDEFAULT);
  }
  if(bRet && pWowRev)
   bRet = pWowRev(OldValue);
 }
 else if((whatbit / whatsize) == 8){ //same bit
 //don't call different bit between app and dll, 32<->64bit direct
  fc = RegisterDll(szDLL,bRegist);
 }
 return fc;

}


*추가:
if(whatsize == 4 && whatbit == 64) 로 WOW64에서 실행중인 32비트 어플인지를 체크하는 부분을
다음 함수로 대체해도 된다.

#define WOW64API __fastcall
#define GetProc(m, n) ((PVOID)GetProcAddress(GetModuleHandleA(m), n))

BOOL WOW64API Wow64CheckProcess( )
{
 typedef BOOL (WINAPI *PFNISWOW64PROCESS)( HANDLE hProcess, PBOOL Wow64Process );

 PFNISWOW64PROCESS pfnIsWow64Process =(PFNISWOW64PROCESS)
  GetProc("KERNEL32.dll", "IsWow64Process");
 //fnIsWow64Process = (LPFN_ISWOW64PROCESS)GetProcAddress(
 // GetModuleHandle(TEXT("kernel32")),"IsWow64Process");

 BOOL bIsWow64;

 if (pfnIsWow64Process && pfnIsWow64Process(GetCurrentProcess(), &bIsWow64))
  return(bIsWow64);

 return(FALSE);
}

아니면 위 로직을 아예 DLL 자체의 DllRegisterServer( ) 와 DllUnregisterServer( )에 심어서
WOW64를 구분하여,리다이렉션을 해제하고 원복하도록 레지스트리에 등록하는
실제 코드의 앞뒤로 Wrapping 하여 호출하게 해놓고,외부에서는 그냥 이 함수들을 원래대로 호출하게 해도 되겠다.

*RegisterDll는 단순히 해당경로의 dll을 LoadLibrary하여 DllRegisterServer 와 DllUnregisterServer를 호출하는 함수임.귀찮아서 나머지는 생략하고 올립니다.
출처: 나(
http://krkim.net)