본문 바로가기

C | C++ | VC++

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

오늘도 잠시 유용한 팁하나 올립니다.
윈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)

  • 전도연이짱 2013.10.17 18:08

    저도 컨텍스트 메뉴때문에 dll을 32bit,64bit 두개로 만들었는데
    실행파일이 32bit전용이라
    LoadLibrary하면 64bit용은 못불러서 골치 썩고있습니다 ㅠㅠ..
    그러던중 regsvr32를 ShellExecute()로 실행하면 되겠다 싶었는데 문제는
    LoadLibrary()할때 뱉어내는 에러들이 좀 부러워서 다른 방법이 없을까
    검색하던 도중 이사이트를 알게되었습니다( 구글에서 ShellExecute regsvr32 로 검색ㅎㅎ )

    글을 보다가 궁금한게 생겼는데요. ShellExecute로 regsvr32를 불러다 쓰는 소스 위에 kernel32에
    Wow64DisableWow64FsRedirection 이런 API는 왜 불러다 쓰는거고
    맨마지막에 DLL파일을 왜 LoadLibrary()해주는지 모르겠거든요
    RegisterDll()함수 호출하기전에 regsvr32로 이미 DllRegisterServer,DllUnregisterServer이런걸 하고있지않습니까?
    다시 RegisterDll()함수를 호출하는 목적이 뭔지 궁금합니다^^;그럼 좋은하루되세요

    • Favicon of http://durueduit.com BlogIcon DURUEDIT.COM 2013.10.21 00:04

      님께서 작성한 32bit APP가 사용자 PC에서 설치될때는 사용자의 32bit,64bit OS를 모두 지원해야 합니다. 따라서,wow64 리다이렉션 기능이 지원되는지 여부를 체크하고 64비트인경우와 32비트인 일반적인경우(RegisterDLL() 부분) 에 대해 동시지원 하기 위한 코드입니다.

    • Favicon of http://durueduit.com BlogIcon DURUEDIT.COM 2013.10.21 00:07

      즉,둘다 연속해서 호출하는게 아니고(if else죠)
      wow64는 32bit os에서는 없는 함수 입니다.(pWowRev = NULL)


  • 전도연이짱 2013.10.23 13:11

    안녕하세요 답변 감사드립니다. 제가 이해가 좀 덜되어 그런데
    주인장님 말씀은

    64bit운영체제일 경우 regsvr32로 dll을 등록/해제하고
    운영체제가 32bit일 경우 regsvr32로 dll을 등록/해제 하지 않고
    LoadLibrary()처리해주기 위해서 하신건지요?


    else if((whatbit / whatsize) == 8){ //same bit
    //don't call different bit between app and dll, 32<->64bit direct
    fc = RegisterDll(szDLL,bRegist);
    }

    여기서 궁금한게 RegisterDll()에서는 어떤 dll을 LoadLibrary()하신다는건지요?kernel32.dll인지 아니면 shell extension dll인지

  • Favicon of http://durueduit.com BlogIcon DURUEDIT.COM 2013.10.25 01:09

    자신의 shell extension dll 입니다.