천객만래 [千客萬來] (It has an interminable succession of visitors)

INF파일 내용 포멧팅 혹은 구조에 대해 설명하는 문서이다

 


INFFileArchitecture.doc


 


아래는 관련 내용
출처 : http://zoomout.egloos.com/949444


ActiveX Installer 만들기

ActiveX 를 만들다보면, Cab파일을 만들어서 배포하는데, 잘 안되는경우가 있습니다.

시스템을 리부팅해야 한다는둥, 이전버젼이 계속 안지워지고, 매번 계속 다운을 받는다든가

하는 상황이 발생할때가 있습니다.

물론 inf랑 cab파일 다 잘만들었을때 얘기죠

그래서 저는 , 강제로, 이전버젼의 aCtiveX를 강제로 삭제하고, 새로운버젼을 시스템 디렉토리에

복사한다음, regsvr32까지 해주는 프로그램을 만들어서 씁니다.

cab파일을 받았을때 AcitveX를 설치하고 등록하고 업데이트 하는 일을 명시적으로 직접

프로그램에서 하는거죠 .

 

Required Skill

1. ActiveX ( ???.ocx) 파일을 실행파일에 포함시키는 방법

2. 파일을 regsvr32 사용해서 실제로 등록 하는 방법 ( 로컬컴퓨터의 regsvr32 를 이용하는것이 아니라

실제 구현한 함수를 사용합니다. )

References

1. Q/A 보드 184574 번글, 이승훈님의 '바이너리 리소스'라는 제목의 글을 참조하십시오 .

2. Tip And Trick , 2039번글, 하형욱님(-_-)의 'Regsvr Function'이라는 제목의 글을 참조하십시오.


Logique

1. OCX를 resource에 넣어서, exe파일에 같이 들어가게 합니다.

2. exe가 실행되면 , resource에 있는 ocx 파일을 로컬컴퓨터의 System Directory에 복사합니다.

 ( modeCreate 해서 이전파일을 지워주시구요 )

3. regsvr 함수를 사용하여 복사한 ocx를 등록해줍니다.


Another Information

CAB파일을 만들때는 다음과 같이 INF 파일을 만들어줍니다.


[Version]
signature="$CHICAGO$"
AdvancedINF=2.0

[Setup Hooks]
InstallHook=InstallHook

[InstallHook]
run=%EXTRACT_DIR%컴파일해서만든프로그램이름.exe -remote


웹페이지에 넣을때는 OCX 를 기준으로 해서 하던 것 처럼 해주시구요.

cab파일 만들때는 . exe랑 inf 만 해주면 되겠지요. , OCX에 대한 정보가 없으니 inf가 정말 간단해졌습니다.

 

그럼 로컬에 있는 버젼을 체크해서 버젼이 낮으면 

서버에 있는 cab파일을 다운받고 ( 여기까지는 자동이죠? )

inf 있는 내용대로 설치를 시작합니다.

위와 같이 적어져먼 InstallHook에 명시된 프로그램이 실행되므로,

우리가 프로그래밍한대로 , 수동으로 ocx복사하고, 등록까지 되겠죠. 

 

장점 :   설치를 프로그램에서 명시적으로 하므로 , 설치때 특별한 일을 해줄수 있습니다.

            (만든 사람이름을 따로 보여준다든가. .등등의. )

단점 : cab파일의 크기가 커집니다. 프로그램이 60k 가 좀 넘으므로, Ocx 를 패키징 하는것보다

         몇십 K 정도 더 커지겠죠.

 

바이너리 리소스...
1. 자신을 오픈하는 방법
CreateFile()에 FILE_SHARE_READ 옵션을 주시면 가능할 것도 같은데 해보지 않아서 장담
할 수 없군요.

2. 실행 파일에 합치는 방법

프로그램의 리소스에 바이너리 데이터를 추가할 수 있습니다.
컴파일이 될 때 합쳐집니다.


(프로젝트명).rc2에 아래와 같이 추가합니다.

/////////////////////////////////////////////////////////////////////////////
// Add manually edited resources here...
IDR_DATA1 DATA Data.zip

/////////////////////////////////////////////////////////////////////////////

IDR_DATA1은 리소스 데이터를 오픈할 때 쓸 이름입니다.
DATA는 리소스의 종류입니다.
Data.zip은 실제 파일명입니다.
프로젝트의 소스코드가 있는 폴더에 파일이 존재해야 에러없이 컴파일됩니다.
(즉, 컴파일 될 때 실행 파일 안으로 합쳐집니다.)

아래의 함수를 참고해서 사용하시기 바랍니다.

BOOL CTestDlg::SaveResource(LPTSTR lpName, LPTSTR lpPathName)
{
   BOOL bRtn; 
   LPTSTR lpRes; 
   HRSRC hResInfo;
   HANDLE hRes; 
   DWORD dwSize;
   
   // Find the wave resource.
   hResInfo = FindResource (NULL, lpName, "DATA"); 
   
   if (hResInfo == NULL) 
       return FALSE; 
   
   // Load the wave resource. 
   hRes = LoadResource (NULL, hResInfo);
   
   if (hRes == NULL) 
       return FALSE; 
   
   // Get size of resource.
   dwSize = SizeofResource(NULL, hResInfo);

   // Lock the wave resource and play it. 
   lpRes = (LPTSTR)LockResource (hRes);

   
   if (lpRes != NULL) 
        { // 실제 파일로 저장하는 부분
       CFile file;
       file.Open(lpPathName, CFile::modeCreate|CFile::modeWrite);
       file.Write(lpRes, dwSize);
       file.Close();
        } 
   else 
       bRtn = 0; 
   
   return bRtn; 
}


그럼...


Regsvr Function

regsvr32 소스가 있길래 거기서 함수를 간추려 올립니다.
파라메터에는 등록할 라이브러리 경로를 적어주시면 되겠죠..
등록해지 할때는 중간의 _szDllRegSvr 값을 _szDllUnregSvr로 교체 해 주심됩니다.

#include 
#include 
#include 
#include

#define FAIL_ARGS   1
#define FAIL_OLE    2
#define FAIL_LOAD   3
#define FAIL_ENTRY  4
#define FAIL_REG    5

int regLib (const char *LibraryName)
{    
const char* _szDllRegSvr = "DllRegisterServer";
const char* _szDllUnregSvr = "DllUnregisterServer";

int iReturn = 0;
   HRESULT (STDAPICALLTYPE * lpDllEntryPoint)(void);

   BOOL bVisualC = FALSE;
   BOOL bUnregister = FALSE;
   LPCSTR pszDllEntryPoint = _szDllRegSvr;
   LPCSTR pszDllName = LibraryName;

   if (FAILED(OleInitialize(NULL))) {
       return FAIL_OLE;
   }

   SetErrorMode(SEM_FAILCRITICALERRORS); 

       HINSTANCE hLib = LoadLibraryEx(pszDllName, NULL, 
LOAD_WITH_ALTERED_SEARCH_PATH);

       if (hLib < (HINSTANCE)HINSTANCE_ERROR) {
           TCHAR szError[12];
           wsprintf(szError, _T("0x%08lx"), GetLastError());

           iReturn = FAIL_LOAD;
           goto CleanupOle;
       }

       (FARPROC&)lpDllEntryPoint = GetProcAddress(hLib, 
pszDllEntryPoint);

       if (lpDllEntryPoint == NULL) {
           TCHAR szExt[_MAX_EXT];
           _tsplitpath(pszDllName, NULL, NULL, NULL, szExt);

           if ((_stricmp(szExt, ".dll") != 0) && (_stricmp
(szExt, ".ocx") != 0))
           {
       
           }
           else
           {
               
           }

           iReturn = FAIL_ENTRY;
           goto CleanupLibrary;
       }

       
       if (FAILED((*lpDllEntryPoint)())) {
           iReturn = FAIL_REG;
           goto CleanupLibrary;
       }

CleanupLibrary:
       FreeLibrary(hLib);
   
CleanupOle:
   OleUninitialize();

   return iReturn;
}

INFFileArchitecture.doc


Posted by SB패밀리
따라해보는 후킹
작성자 : 이은규
작성일 : 2003.11.02
홈페이지 : http://unkyulee.net/
 
목차
1. 들어가는 글
2. 후킹이란?
3. 후킹 프로시져를 만들어 보자.
4. 후킹 프로시져를 시작, 종료하는 함수
5. 프로시져 내에서 다른 윈도우로 데이터 전송하기
6. 간단한 샘플 프로그램
 

1. 들어가는 글
 
 "그냥 실행되는 걸 보고 싶었다."
  예전에 했던 프로젝트의 내용 중에 사용자가 키보드로 입력하는 내용을 얻어와서 처리해야 되는 부분이 있었다. 이러한 기능을 구현하기 위해서는 후킹 이라는 기술을 사용해야 한다. 그래서 관련된 내용을 인터넷에서 찾아봤는데, 왜 이렇게 알아야 되는 내용이 많은지… 또 내용들은 어찌나 어렵던지… 후킹 구현한답시고 한달 내내 문서 읽고 인터넷 뒤지고 엄청 고생 했었다. 결국 간단한 샘플 코드를 구해서 원하는 기능을 구현 했던 기억이 있다.
  프로젝트 내에서 그리 중요한 부분도 아니였고, 그냥 호기심에 후킹이라는 걸 실제로 구현해보고 싶었던 것 뿐이였는데, 정말 어렵게 공부했던 것 같다.
  이 강좌는 순전히 호기심으로 혹은 그냥(?) 한번 후킹을 실제로 구현해 보고자 하는 사람들을 대상으로 한다. 후킹에 대한 자세한 이론은 대부분 생략할 예정이다. 대신에 이 강좌를 다 읽고 나면 후킹을 사용한, 일단 돌아가는 코드를 작성 할 수 있을 것이다.
  일단 돌아가는 코드를 작성하고 나면, 그 외의 내용을 익히는 것은 시간 문제일 뿐이지 않을까 생각한다. ^0^)
 

2. 후킹이란?
 
 "후킹은 도청하는 걸 예로 들면 쉽게 이해할 수 있다."
  후킹이란 다른 프로세스에 걸려서(Hooked) 해당 프로세스의 정보를 얻어 오거나, 변경하는 것이 가능한 기술이다. 여기서 프로세스란 좁게 봐서 "윈도우 프로시져" 혹은 "윈도우 메시지" 라고 생각하면 되겠다.
  예를 들어 보자. 한 아파트 건물이 있다고 하자. 그리고 이 건물을 도청하고 싶다. 그럼 전화선들이 지나가는 곳(Window Process) 에 도청 장치(후킹 프로시져)를 설치한다. 그럼 도청장치 사이로 전화 내용들이(Window Message) 지나간다. 도청 장치는 그 중 필요한 메시지를 저장하고 있거나, 필요한 곳으로 전송한다.
  위의 과정들에 의해서 빌딩은 도청을 당한다. 그럼 실제 후킹의 경우를 살펴보자. 일단 윈도우 메시지(전화 내용)를 후킹 한다고 하면 윈도우 메시지를 발생시키는 곳(전화선들이 지나가는 곳)에 후킹 프로시져(도청 장치)를 설치한다. 그럼 해당 윈도우에서 발생하는 메시지가 후킹 프로시져를 거쳐가게 된다. 그럼 후킹 프로시져는 메시지들을 보고 필요한 내용을 저장하던지 필요한 곳에 전달을 하면 되는 것이다.
  그림 한번 보자. 위 그림은 Ivo Ivanov 라는 사람이 쓴 API Hooking Reveal 라는 문서에서 퍼 가지고 왔다. 그림을 보면 Hook Driver 라는 것들이 3개가 보인다. 그림에서 현재 윈도우가 3 개가 떠있는데 각각의 윈도우에 하나씩 Hook Driver 가 붙어 있는 모양이다. 따라서 이 드라이버(후킹 프로시져) 들이 각각의 윈도우에서 오는 메시지들을 받을 수가 있는 것이다.
  뭔가 굉장히 많아 보인다. 하지만 결국 개발자가 만들어 주는 것은 후킹 프로시져 하나이다.
  여기서 키포인트는 특정 위도우가 받는 메시지를 후킹 프로시져도 받을 수 있다는 것이다. 이런 기술을 바로 후킹이라고 한다.
 
3. 후킹 프로시져를 만들어 보자.
 
 "이론은 끝났다. 이제 만들어 보자."
  후킹 프로시져… 아까부터 프로시져라는 단어가 계속 나오는데 결국 프로시져는 함수와 그 의미가 비슷하다. 따라서 후킹 프로시져라고 함은 후킹을 하는 함수라고 생각하자. 따라서 후킹 프로시져를 만든다는 것은 함수를 하나 만든다고 생각하면 된다.
  후킹 함수를 만들기 위해서는 지켜야 하는 규칙들이 있다.
1. Call Back 함수이여야 한다.
2. 함수의 마지막 부분에서는 CallNextHookEx() 함수를 호출한다. 
3. 함수가 받는 인자는 정해져 있다.
4. 후킹 프로시져는 DLL 안에 있어야 한다.
 
Ex)
//--------------------------------------------------------------
// Hook Procedure - Keyboard
//--------------------------------------------------------------
LRESULT CALLBACK KeyboardProcedure(int nCode, WPARAM wParam, LPARAM lParam)
{
             if( nCode >= 0 )
             {           
             }
             // We must pass the all messages on to CallNextHookEx.
           return ::CallNextHookEx( g_Hook , nCode , wParam , lParam );
}
 위의 규칙들을 지켜서 만든 후킹 프로시져 함수이다.
 4번째 규칙에 의하면 후킹 함수는 DLL 내부에 있어야 한다. Visual C++ 6.0 에서 DLL 프로젝트를 하나 만들어 보자.
Step 1. Win32 Dynamic-Link Library 프로젝트 생성
Step 2. Simple 프로젝트 선택 후 Finish
Step 3. cpp 파일에 위의 후킹 함수를 만들어 준다.
위의 프로젝트를 컴파일 하면 HookDll.dll 파일이 생성된다.

전체 프로젝트 파일 내용
// HookDll.cpp : Defines the entry point for the DLL application.
//
#include "stdafx.h"
BOOL APIENTRY DllMain( HANDLE hModule, DWORD  ul_reason_for_call, 
                       LPVOID lpReserved)
{
    return TRUE;
}
 
//--------------------------------------------------------------
// Hook Procedure - Keyboard
//--------------------------------------------------------------
LRESULT CALLBACK KeyboardProcedure(int nCode, WPARAM wParam, LPARAM lParam)
{
             if( nCode >= 0 )
             {                          
             }
             // We must pass the all messages on to CallNextHookEx.
             return ::CallNextHookEx( g_Hook , nCode , wParam , lParam );
}

 
4. 후킹 프로시져를 시작, 종료하는 함수
 
 이번 단계에서는 앞서 만든 후킹 프로시져를 설치하고, 제거하는 함수를 만들어 보겠다. 후킹 프로시져는 특정 윈도우에 설치가 되어야 제 역할을 할 수 있게 된다. 이때 후킹 프로시져를 설치해주는 함수가 바로 SetWindowsHookEx() 이다. 그 다음에 설치된 후킹 프로시져를 제거하기 위해서는 UnhookWindowsHookEx() 가 쓰이게 된다. 각각의 사용법을 알아보고 앞에서 만든 프로젝트에 이어서 적용시켜 보자.
SetWindowsHookEx()의 사용법
HHOOK SetWindowsHookEx(
    int idHook,
    HOOKPROC lpfn,
    HINSTANCE hMod,
    DWORD dwThreadId
);
 
 첫번째 패러메터는 후킹 필터를 설정한다. 후킹 프로시져가 받은 메시지의 종류를 설정하는 항목이다. 예를 들어 WH_GETMESSAGE로 설정하면 모든 메시지를 받게 되고, WH_KEYBOARD로 설정하게 되면 키보드 관련 메시지만 전달 받게 된다. 더 자세한 내용은 MSDN 을 참고하기 바란다.
 두번재 패러메터는 후킹 프로시져의 포인터를 지정해야 한다. 간단하게 후킹 프로시져 함수 이름 써주면 된다.  
 세번째 패러메터는 DLL 의 핸들을 넘겨줘야 된다. 이 값은 앞에서 만든 프로젝트에서 DLlMain() 함수를 보면 HANDLE hModule 값이 넘어오는데 이걸 저장 해놨다가 넘겨주면 된다.
 네번째 패러메터는 후킹 프로시져를 설치할 윈도우 값을 넘겨준다. 이번 예에서는 0 을 넘겨준다. 0 을 넘겨주면 후킹 프로시져가 모든 윈도우에 설치가 된다.
 이 함수가 리턴하는 값을 잘 저장 해 놓자. 나중에 후킹을 해제할 때 필요하게 된다.
Ex) g_HookKeyboard = SetWindowsHookEx( WH_KEYBOARD , KeyboardProcedure , (HINSTANCE)g_Module , 0 ) ;
 
UnhookWindowsHookEx() 의 사용법

BOOL UnhookWindowsHookEx(          
             HHOOK hhk
);
 
 이 함수는 후킹 핸들을 받아서 해당 후킹 프로시져를 해제한다. 이때 받는 핸들은 SetWindowsHookEx() 함수가 리턴한 값을 넣어주면 된다.
프로젝트를 계속 진행 해보자.
1. 필요한 전역 변수를 만들어 준다.
//---------------------------------------------------
// Global Variables
// 공용 메모리
//---------------------------------------------------

#pragma data_seg(".HKT")
HINSTANCE g_Module = NULL ;     // DLL Handle 
HHOOK g_Hook = NULL ;  // Hook Handle
HWND g_HwndServer = NULL ;      // Hook Server Window Handle
#pragma data_seg()
 
2. SetHook, Remove 이라는 함수를 만든다.
//------------------------------------------------------------------// Set Hook
//------------------------------------------------------------------BOOL     SetHook( HWND hWnd ) 
{
             g_HwndServer = hWnd ;                // Set Hook Server
             g_Hook = SetWindowsHookEx( WH_KEYBOARD , KeyboardProcedure , (HINSTANCE)g_Module , 0 ) ;
             return false ;
}
//-------------------------------------------------------// Remove Hook
//------------------------------------------------------------------BOOL     RemoveHook() 
{
             UnhookWindowsHookEx( g_Hook ) ;
             return false;
}
// HookDll.def 파일 부분
LIBRARY   HookDll
SECTIONS
             .HKT   Read Write Shared
EXPORTS
             SetImeWindow                 @1 
             SetHook                                        @2
             RemoveHook                                 @3


3.. 위의 함수와 전역 변수의 세팅을 위한 [프로젝트명].def 파일을 만들어 준다.
LIBRARY   [프로젝트명]
SECTIONS
             .HKT   Read Write Shared
EXPORTS
             SetHook                                        @2
             RemoveHook                                 @3
 
4. DllMail 함수에서 핸들을 저장한다.
//---------------------------------------------------// DllMain : Entry point
//------------------------------------------------------------------BOOL 
APIENTRY DllMain( HANDLE hModule, DWORD  ul_reason_for_call, 
                       LPVOID lpReserved)
{
             switch (ul_reason_for_call)
             {
             case DLL_PROCESS_ATTACH:
                           g_Module = (HINSTANCE)hModule; // Save Dll Handle
                           break;
              case DLL_PROCESS_DETACH:
                           RemoveHook();
                           break;
             }
             return TRUE;
}
전체 프로젝트 파일

1. HookDll.cpp

// HookDll.cpp : Defines the entry point for the DLL application.
//

#include "stdafx.h"

//---------------------------------------------------
// Global Variables
// 공용 메모리
//---------------------------------------------------
#pragma data_seg(".HKT")
HINSTANCE g_Module = NULL ;     // DLL Handle 
HHOOK g_Hook = NULL ;  // Hook Handle
HWND g_HwndServer = NULL ;      // Hook Server Window Handle
#pragma data_seg()
 
BOOL    RemoveHook() ;
BOOL    SetHook( HWND hWnd ) ;
 
//------------------------------------------------------------------
// DllMain : Entry point
//------------------------------------------------------------------

BOOL APIENTRY DllMain( 
                                                                                HANDLE hModule, 
                                                                                DWORD  ul_reason_for_call, 
                                                                                LPVOID lpReserved
                                                                  )
{
             switch (ul_reason_for_call)
             {
             case DLL_PROCESS_ATTACH:
                           g_Module = (HINSTANCE)hModule; // Save Dll Handle
                           break; 
             case DLL_PROCESS_DETACH:
                           RemoveHook();
                           break;
             }
             return TRUE;
}
 
//--------------------------------------------------------------
// Hook Procedure - Keyboard
//--------------------------------------------------------------
LRESULT CALLBACK KeyboardProcedure(int nCode, WPARAM wParam, LPARAM lParam)
{
             if( nCode >= 0 )
             {                       
             }
             // We must pass the all messages on to CallNextHookEx.
             return ::CallNextHookEx( g_Hook , nCode , wParam , lParam );
}
 
//------------------------------------------------------------------
// Set Hook
//------------------------------------------------------------------
BOOL    SetHook( HWND hWnd ) 
{
             g_HwndServer = hWnd ;                // Set Hook Server
             g_Hook = SetWindowsHookEx( WH_KEYBOARD , KeyboardProcedure , (HINSTANCE)g_Module , 0 ) ;
             return false ;
}
 
//------------------------------------------------------------------
// Remove Hook
//------------------------------------------------------------------
BOOL    RemoveHook() 
{
             UnhookWindowsHookEx( g_Hook ) ;
             return true ;
}
 

2. HookDll.def 파일
LIBRARY   HookDll
SECTIONS
.HKT   Read Write Shared
EXPORTS
SetHook                                        @2
RemoveHook                                 @3

프로젝트를 컴파일 하면 HookDll.lib 와 HookDll.dll 파일이 생성이 된다.
5. 프로시져 내에서 다른 윈도우로 데이터 전송하기
 이번에는 앞서 만든 후킹 프로시져를 좀더 강화해보기로 하자. 후킹 프로시져 내에서 메시지를 받고 받은 메시지를 복사하여 특정 윈도우에게 보낼 것이다.  
 이때 WM_COPYDATA 메시지를 생성 할 것이다.
1. WM_COPYDATA 로 보낼 데이터의 구조를 정의한다.
// 메시지를 저장하는 구조체

typedef struct
{
             int                       Type ;
             WPARAM            Data ;
             LPARAM              lParam ;
} HEVENT;

 윈도우 메시지의 내용을 저장할 구조체

2. 현재의 메시지를 복사한다.

COPYDATASTRUCT  CDS;
HEVENT          Event;
// Set CDS
CDS.dwData = 0 ;
CDS.cbData = sizeof(Event);
CDS.lpData = &Event;
// 메시지의 내용을 저장한다.
Event.Type = 1 ;               // It's WM_KEY.. 
Event.Data = wParam ;     // Send CharCode
Event.lParam = lParam ;
3. g_HwndServer 에게로 메시지를 전달한다.
// g_HwndServer  에게로 메시지를 날린다.
// g_HwndServer 는 SetHook 함수 호출시 저장한 윈도우 핸들이다.
::SendMessage( g_HwndServer , WM_COPYDATA , 0 , (LPARAM)(VOID*)&CDS ) ;
프로젝트를 계속 진행 해보자.
1. 앞선 프로젝트의 내용 중 KeyboardProcedure() 함수의 내용을 수정한다.
//------------------------------------------------------------------
// Hook Procedure - Keyboard
//------------------------------------------------------------------
LRESULT CALLBACK KeyboardProcedure(int nCode, WPARAM wParam, LPARAM lParam)
{
             if( nCode >= 0 )
             {
                           // Send To HookServer
                           COPYDATASTRUCT  CDS;
                           HEVENT          Event;
                           // Set CDS
                           CDS.dwData = 0 ;
                           CDS.cbData = sizeof(Event);
                           CDS.lpData = &Event;
                           // Set Variables
                           Event.Type = 1 ;               // It's WM_KEY.. 
                           Event.Data = wParam ;     // Send CharCode
                           Event.lParam = lParam ;
                           ::SendMessage( g_HwndServer , WM_COPYDATA , 0 , (LPARAM)(VOID*)&CDS ) ;     
             }
             // We must pass the all messages on to CallNextHookEx.
             return ::CallNextHookEx( g_Hook , nCode , wParam , lParam );
}
 
2. Event 구조체를 정의 해준다.
typedef struct
{
             int                       Type ;
             WPARAM            Data ;
             LPARAM              lParam ;
} HEVENT;
 
6. 간단한 샘플 프로그램

 지금까지 만들어 본 후킹 프로시져를 가지고 실제로 샘플 프로그램을 작성해보자.

1. 프로젝트를 생성한다.
             - MFC 다이얼로그
2. 위의 프로젝트를 컴파일 하면 HookDll.lib 와 HookDll.dll 파일이 생성이 된다. 이 파일을 새롭게 생성할 프로젝트 폴더에 복사한다.
 
3. 프로젝트를 세팅한다.
             - 메뉴에서 Project -> Setting -> Link 탭에서 Object/Modules Library 칸에 HookDll.lib 를 지정한다.
 
4 . 다이얼로그를 위의 모양같이 만들어 주고 에디트 컨트롤을 생성하고 다음과 같이 변수를 연결해준다..
 ID : IDC_EDIT_CNT
 Value : m_Cnt 
 Type : int
5. 클래스 위저드로 WM_COPYDATA 메시지 핸들러를 생성한다.
BOOL CHookTestDlg::OnCopyData(CWnd* pWnd, COPYDATASTRUCT* pCopyDataStruct) 
{
             // TODO: Add your message handler code here and/or call default
             // WM_COPYDATA 메시지가 올때마다 카운트를 증가한다.
             m_Cnt++ ;
             UpdateData( false ) ;
             return CDialog::OnCopyData(pWnd, pCopyDataStruct);
}
위와 같이 수정해준다.
6. DLL 에 있는 함수를 사용하기 위해 헤더 파일에 다음을 추가한다.
BOOL    RemoveHook() ;
BOOL    SetHook( HWND hWnd ) ;

7. InitDialog() 함수에서 SetHook() 함수를 호출한다.
BOOL CHookTestDlg::OnInitDialog()
{
             CDialog::OnInitDialog();
             // Add "About..." menu item to system menu.
             // IDM_ABOUTBOX must be in the system command range.
             ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX);
             ASSERT(IDM_ABOUTBOX < 0xF000);
             CMenu* pSysMenu = GetSystemMenu(FALSE);
             if (pSysMenu != NULL)
             {
                           CString strAboutMenu;
                           strAboutMenu.LoadString(IDS_ABOUTBOX);
                           if (!strAboutMenu.IsEmpty())
                           {
                                        pSysMenu->AppendMenu(MF_SEPARATOR);
                                        pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu);
                           }
             }
             // Set the icon for this dialog.  The framework does this automatically
             //  when the application's main window is not a dialog
             SetIcon(m_hIcon, TRUE);                           // Set big icon
             SetIcon(m_hIcon, FALSE);                          // Set small icon
             
             // TODO: Add extra initialization here
             SetHook( this->GetSafeHwnd() ) ; // 후킹 프로시져 설치
             
             return TRUE;  // return TRUE  unless you set the focus to a control
}
 
자 이제 실행하면 키보드를 칠 때마다 카운트가 증가하는 프로그램이 완성이 되었다.




## 출처 ##

작성자 : 이은규
작성일 : 2003.11.02
홈페이지 : http://unkyulee.net/

Posted by SB패밀리

[version]
signature="$CHICAGO$"
advancedINF=2.0

[Setup Hooks]
hook1=hook1

[hook1]
run=%EXTRACT_DIR%\MyApp.exe 

이런식으로 ActiveX 컨트롤 다운로드 할 때 별도의 설치 프로그램으로 Hooking 을 할 수 가 있습니다.

그런데 Hooking 프로그램 작성시 WinMain 의 리턴값은 0이어야 합니다.
1 이상이면 Hooking 한 프로그램에서 설치하고 나서도 Browser에 컨트롤이 뜨질 않습니다.
아무래도 0이 아닌 값은 Error 값으로 인식을 하는듯..


[version]
signature="$CHICAGO$"
AdvancedINF=2.0
 
[Setup Hooks]
your_hook=your_hook
 
[your_hook]
Run=%EXTRACT_DIR%YourApp.exe
Posted by SB패밀리

INF파일 내용 포멧팅 혹은 구조에 대해 설명하는 문서이다


아래는 관련 내용
출처 : http://zoomout.egloos.com/949444


ActiveX Installer 만들기

ActiveX 를 만들다보면, Cab파일을 만들어서 배포하는데, 잘 안되는경우가 있습니다.

시스템을 리부팅해야 한다는둥, 이전버젼이 계속 안지워지고, 매번 계속 다운을 받는다든가

하는 상황이 발생할때가 있습니다.

물론 inf랑 cab파일 다 잘만들었을때 얘기죠

그래서 저는 , 강제로, 이전버젼의 aCtiveX를 강제로 삭제하고, 새로운버젼을 시스템 디렉토리에

복사한다음, regsvr32까지 해주는 프로그램을 만들어서 씁니다.

cab파일을 받았을때 AcitveX를 설치하고 등록하고 업데이트 하는 일을 명시적으로 직접

프로그램에서 하는거죠 .

 

Required Skill

1. ActiveX ( ???.ocx) 파일을 실행파일에 포함시키는 방법

2. 파일을 regsvr32 사용해서 실제로 등록 하는 방법 ( 로컬컴퓨터의 regsvr32 를 이용하는것이 아니라

실제 구현한 함수를 사용합니다. )

References

1. Q/A 보드 184574 번글, 이승훈님의 '바이너리 리소스'라는 제목의 글을 참조하십시오 .

2. Tip And Trick , 2039번글, 하형욱님(-_-)의 'Regsvr Function'이라는 제목의 글을 참조하십시오.


Logique

1. OCX를 resource에 넣어서, exe파일에 같이 들어가게 합니다.

2. exe가 실행되면 , resource에 있는 ocx 파일을 로컬컴퓨터의 System Directory에 복사합니다.

 ( modeCreate 해서 이전파일을 지워주시구요 )

3. regsvr 함수를 사용하여 복사한 ocx를 등록해줍니다.


Another Information

CAB파일을 만들때는 다음과 같이 INF 파일을 만들어줍니다.


[Version]
signature="$CHICAGO$"
AdvancedINF=2.0

[Setup Hooks]
InstallHook=InstallHook

[InstallHook]
run=%EXTRACT_DIR%컴파일해서만든프로그램이름.exe -remote


웹페이지에 넣을때는 OCX 를 기준으로 해서 하던 것 처럼 해주시구요.

cab파일 만들때는 . exe랑 inf 만 해주면 되겠지요. , OCX에 대한 정보가 없으니 inf가 정말 간단해졌습니다.

 

그럼 로컬에 있는 버젼을 체크해서 버젼이 낮으면 

서버에 있는 cab파일을 다운받고 ( 여기까지는 자동이죠? )

inf 있는 내용대로 설치를 시작합니다.

위와 같이 적어져먼 InstallHook에 명시된 프로그램이 실행되므로,

우리가 프로그래밍한대로 , 수동으로 ocx복사하고, 등록까지 되겠죠. 

 

장점 :   설치를 프로그램에서 명시적으로 하므로 , 설치때 특별한 일을 해줄수 있습니다.

            (만든 사람이름을 따로 보여준다든가. .등등의. )

단점 : cab파일의 크기가 커집니다. 프로그램이 60k 가 좀 넘으므로, Ocx 를 패키징 하는것보다

         몇십 K 정도 더 커지겠죠.

 

바이너리 리소스...
1. 자신을 오픈하는 방법
CreateFile()에 FILE_SHARE_READ 옵션을 주시면 가능할 것도 같은데 해보지 않아서 장담
할 수 없군요.

2. 실행 파일에 합치는 방법

프로그램의 리소스에 바이너리 데이터를 추가할 수 있습니다.
컴파일이 될 때 합쳐집니다.


(프로젝트명).rc2에 아래와 같이 추가합니다.

/////////////////////////////////////////////////////////////////////////////
// Add manually edited resources here...
IDR_DATA1 DATA Data.zip

/////////////////////////////////////////////////////////////////////////////

IDR_DATA1은 리소스 데이터를 오픈할 때 쓸 이름입니다.
DATA는 리소스의 종류입니다.
Data.zip은 실제 파일명입니다.
프로젝트의 소스코드가 있는 폴더에 파일이 존재해야 에러없이 컴파일됩니다.
(즉, 컴파일 될 때 실행 파일 안으로 합쳐집니다.)

아래의 함수를 참고해서 사용하시기 바랍니다.

BOOL CTestDlg::SaveResource(LPTSTR lpName, LPTSTR lpPathName)
{
   BOOL bRtn;
   LPTSTR lpRes;
   HRSRC hResInfo;
   HANDLE hRes;
   DWORD dwSize;
  
   // Find the wave resource.
   hResInfo = FindResource (NULL, lpName, "DATA");
  
   if (hResInfo == NULL)
       return FALSE;
  
   // Load the wave resource.
   hRes = LoadResource (NULL, hResInfo);
  
   if (hRes == NULL)
       return FALSE;
  
   // Get size of resource.
   dwSize = SizeofResource(NULL, hResInfo);

   // Lock the wave resource and play it.
   lpRes = (LPTSTR)LockResource (hRes);

  
   if (lpRes != NULL)
        { // 실제 파일로 저장하는 부분
       CFile file;
       file.Open(lpPathName, CFile::modeCreate|CFile::modeWrite);
       file.Write(lpRes, dwSize);
       file.Close();
        }
   else
       bRtn = 0;
  
   return bRtn;
}


그럼...


Regsvr Function

regsvr32 소스가 있길래 거기서 함수를 간추려 올립니다.
파라메터에는 등록할 라이브러리 경로를 적어주시면 되겠죠..
등록해지 할때는 중간의 _szDllRegSvr 값을 _szDllUnregSvr로 교체 해 주심됩니다.

#include
#include
#include
#include

#define FAIL_ARGS   1
#define FAIL_OLE    2
#define FAIL_LOAD   3
#define FAIL_ENTRY  4
#define FAIL_REG    5

int regLib (const char *LibraryName)
{   
const char* _szDllRegSvr = "DllRegisterServer";
const char* _szDllUnregSvr = "DllUnregisterServer";

int iReturn = 0;
   HRESULT (STDAPICALLTYPE * lpDllEntryPoint)(void);

   BOOL bVisualC = FALSE;
   BOOL bUnregister = FALSE;
   LPCSTR pszDllEntryPoint = _szDllRegSvr;
   LPCSTR pszDllName = LibraryName;

   if (FAILED(OleInitialize(NULL))) {
       return FAIL_OLE;
   }

   SetErrorMode(SEM_FAILCRITICALERRORS); 

       HINSTANCE hLib = LoadLibraryEx(pszDllName, NULL,
LOAD_WITH_ALTERED_SEARCH_PATH);

       if (hLib < (HINSTANCE)HINSTANCE_ERROR) {
           TCHAR szError[12];
           wsprintf(szError, _T("0x%08lx"), GetLastError());

           iReturn = FAIL_LOAD;
           goto CleanupOle;
       }

       (FARPROC&)lpDllEntryPoint = GetProcAddress(hLib,
pszDllEntryPoint);

       if (lpDllEntryPoint == NULL) {
           TCHAR szExt[_MAX_EXT];
           _tsplitpath(pszDllName, NULL, NULL, NULL, szExt);

           if ((_stricmp(szExt, ".dll") != 0) && (_stricmp
(szExt, ".ocx") != 0))
           {
      
           }
           else
           {
              
           }

           iReturn = FAIL_ENTRY;
           goto CleanupLibrary;
       }

      
       if (FAILED((*lpDllEntryPoint)())) {
           iReturn = FAIL_REG;
           goto CleanupLibrary;
       }

CleanupLibrary:
       FreeLibrary(hLib);
  
CleanupOle:
   OleUninitialize();

   return iReturn;
}


Posted by SB패밀리