COM 개체 구현 실습 AddBack Local Server 예제 프로그램 작성. 2 AddBack Local Server...
-
Upload
claude-knight -
Category
Documents
-
view
223 -
download
2
Transcript of COM 개체 구현 실습 AddBack Local Server 예제 프로그램 작성. 2 AddBack Local Server...
COM 개체 구현 실습
AddBack Local Server 예제 프로그램 작성
2
AddBack Local Server 구현
1. Visual C++ 개발 환경의 [File/New] 메뉴 항목을 선택
2. [New] 대화 상자의 [Properties] 탭에서 [Win32 Application] 항목 선택
3. [Location] 텍스트 상자에 앞에서 생성한 AddBack 폴더를 지정
4. [Project] 텍스트 상자에 ‘ AddBack’ 이라고 입력5. [Location] 텍스트 상자 끝에 추가된 ‘ AddBack’ 을
‘OutProc’ 으로 변경6. [OK] 명령 단추를 클릭
3
4
7. 앞에서 생성한 AddEnd.cpp 와 Factory.cpp 파일을 OutProc 폴더에 복사한 후 , 두 파일을 AddBack 프로젝트에 추가
8. AddBack 프로젝트에 ‘ AddBack.cpp’ 파일을 생성하여 추가한다
9. AddBack.cpp 파일에 다음과 같은 6 개의 파일을 포함시킨다#include <windows.h>
#include <ole2.h>
#include "..\AddBack.h"
#include "..\Factory.h"
#include "..\Guid.h"
#include "..\Guid.cpp"
5
10. WinMain 함수 구현HINSTANCE g_hInstance;DWORD g_dwRegister;CFAddBack* g_pFactory;
BOOL OpenFactory(void);BOOL CloseFactory(void);void RegisterServer (void);void UnregisterServer (void);BOOL SetRegKeyValue(LPTSTR pszKey, LPTSTR pszSubkey, LPTSTR pszValue);
int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow){ // TODO: Place code here.
HRESULT hr;MSG msg;
hr = CoInitialize(NULL);if(FAILED(hr)) {
MessageBox(NULL, "COM 라이브러리를 초기화할 수 없습니다 !", NULL, MB_OK);
return 0;}
6
// EXE 화일은 DllGetClassObject, DllCanUnloadNow, DllRegisterServer, // DllUnregisterServer 함수를 노출시키지 못한다 . // 명령행에서 WinMain 함수에 넘어온 매개변수의 값이 RegServer 또는 UnregServer 옵션을 // 포함하고 있는 지를 검사하여 레지스트리에 등록 또는 해제하는 함수를 호출
if (lstrcmpiA(lpCmdLine, "-RegServer") == 0 ||lstrcmpiA(lpCmdLine, "/RegServer") == 0) {
g_hInstance = hInstance; RegisterServer(); return 0;
}elseif (lstrcmpiA(lpCmdLine, "-UnregServer") == 0 ||
lstrcmpiA(lpCmdLine, "/UnregServer") == 0) { UnregisterServer(); return 0;
}
if (lstrcmpiA(lpCmdLine, "-Embedding") == 0 ||lstrcmpiA(lpCmdLine, "/Embedding") == 0)
OpenFactory();
while(GetMessage(&msg, NULL, 0, 0)) { TranslateMessage(&msg); DispatchMessage(&msg);
}
CloseFactory();::CoUninitialize();
return 0;}
7
11.ROT(Running Object Table) 에 클래스 팩토리 COM 개체를 등록하는 코드 구현BOOL OpenFactory(void) // CoGetClassObject 에서 호출{ // (ROT 참조후 없으면 호출 ) BOOL bOK = FALSE; HRESULT hr;
g_pFactory = new CFAddBack; if(g_pFactory != NULL) { g_pFactory->AddRef(); hr = ::CoRegisterClassObject(CLSID_AddBack, g_pFactory,
CLSCTX_LOCAL_SERVER, REGCLS_MULTIPLEUSE,&g_dwRegister);
bOK = SUCCEEDED(hr); if(!bOK) { g_pFactory->Release(); delete g_pFactory; } } else bOK = FALSE;
return bOK;}
8
BOOL CloseFactory(void){ BOOL bOK = TRUE; HRESULT hr;
if (g_dwRegister != 0) { hr = CoRevokeClassObject(g_dwRegister); if (FAILED(hr)) bOK = FALSE; } if(g_pFactory) g_pFactory->Release();
return bOK;}
9
13.WinMain 함수 앞에 카운터로 사용할 전역 변수 정의HINSTANCE g_hInstance;DWORD g_dwRegister;CFAddBack* g_pFactory;LONG g_cObjects = 0; // COM 개체 카운터LONG g_cLocks = 0; // 로크 카운터
BOOL OpenFactory(void);BOOL CloseFactory(void);void RegisterServer (void);void UnregisterServer (void);BOOL SetRegKeyValue(LPTSTR pszKey, LPTSTR pszSubkey, LPTSTR pszValue);
int APIENTRY WinMain(HINSTANCE hInstance,
14.AddBack 프로젝트에 ‘ Add.h’ 헤더 파일을 생성하고 앞에서 정의한 전역 변수 선언
extern LONG g_cObjects;
extern LONG g_cLocks;
void CloseExe (void);
10
15.CFAddBack::CreateInstance 메소드에 COM 개체 카운터를 반영하는 코드 추가HRESULT __stdcall CFAddBack::CreateInstance(LPUNKNOWN pUnkOuter,
REFIID riid, LPVOID* ppv){ HRESULT hr = E_FAIL; CAddBack* pAddBack = NULL; *ppv = NULL;
if(pUnkOuter != NULL) hr = CLASS_E_NOAGGREGATION; else { pAddBack = new CAddBack; if(pAddBack != NULL) { ++g_cObjects; // COM 개체 카운터를 증가시킨다 . // 클라이언트에서 요청한 인터페이스 포인터를 // CAddBack COM 개체에게 요청한다 . hr = pAddBack->QueryInterface(riid, ppv); if(FAILED(hr)) { --g_cObjects; // 실패한 경우 COM 개체 카운터를 감소시킨다 . delete pAddBack; CloseExe(); // 가능하다면 종료한다 . } } else hr = E_OUTOFMEMORY; } return hr;}
11
16.CFAddBack::LockServer 메소드에 Lock Counter를 반영하는 코드 추가HRESULT __stdcall CFAddBack::LockServer(BOOL bLock){ if(bLock) ++g_cLocks; else --g_cLocks;
return S_OK;}
17.AddEnd.cpp 파일에 Add.h 헤더 파일을 포함시킨다
#include "..\AddEnd.h"#include "Add.h"
#include "..\AddBack_i.c"
12
18. CAddBack::Release 메소드에 COM 개체 카운터를 반영하는 코드를 추가ULONG __stdcall CAddBack::Release(void)
{
if(--m_cRef == 0) {
// COM 개체 카운터를 감소시킨다 .
--g_cObjects;
delete this;
// 가능하다면 종료한다 .
CloseExe();
}
return m_cRef;
}
19. CloseExe 함수를 구현void CloseExe (void)
{
if (g_cObjects == 0 && g_cLocks == 0)
PostQuitMessage(0);
}
13
20.AddBack COM 컴포넌트를 레지스트리에 등록 및 해제하는 RegisterServer 와 UnregisterServer 함수 구현void RegisterServer (void){ TCHAR szID[129]; TCHAR szCLSID[129]; TCHAR szModulePath[MAX_PATH]; wchar_t wszCLSID[129];
GetModuleFileName(g_hInstance, szModulePath, sizeof(szModulePath)/sizeof(TCHAR)); StringFromGUID2(CLSID_AddBack, wszCLSID, 128); wcstombs(szID, wszCLSID, 128) ;
lstrcpy(szCLSID, TEXT("CLSID\\")); lstrcat(szCLSID, szID); SetRegKeyValue(TEXT("AddBack.AddBack.1"), NULL, TEXT("AddBack Component")); SetRegKeyValue(TEXT("AddBack.AddBack.1"), TEXT("CLSID"), szID);
SetRegKeyValue(szCLSID, NULL, TEXT("AddBack Component")); SetRegKeyValue(szCLSID, TEXT("ProgID"), TEXT("AddBack.AddBack.1")); // 인 -프로세스 서버와 다른 부분 SetRegKeyValue(szCLSID, TEXT("LocalServer32"), szModulePath);}
14
void UnregisterServer (void){ TCHAR szID[129]; TCHAR szCLSID[129]; TCHAR szTemp[129]; wchar_t wszCLSID[129];
StringFromGUID2(CLSID_AddBack, wszCLSID, 128); wcstombs(szID, wszCLSID, 128) ;
lstrcpy(szCLSID, TEXT("CLSID\\")); lstrcat(szCLSID, szID);
RegDeleteKey(HKEY_CLASSES_ROOT, TEXT("AddBack.AddBack.1\\CLSID")); RegDeleteKey(HKEY_CLASSES_ROOT, TEXT("AddBack.AddBack.1"));
// 인 - 프로세스 서버와 다른 부분 wsprintf(szTemp, TEXT("%s\\%s"), szCLSID, TEXT("LocalServer32")); RegDeleteKey(HKEY_CLASSES_ROOT, szTemp); wsprintf(szTemp, TEXT("%s\\%s"), szCLSID, TEXT("ProgID")); RegDeleteKey(HKEY_CLASSES_ROOT, szTemp); RegDeleteKey(HKEY_CLASSES_ROOT, szCLSID);}
15
BOOL SetRegKeyValue(LPTSTR pszKey, LPTSTR pszSubkey, LPTSTR pszValue){ BOOL bOk = FALSE; LONG ec; HKEY hKey; TCHAR szKey[256];
lstrcpy(szKey, pszKey);
if(NULL != pszSubkey) { lstrcat(szKey, TEXT("\\")); lstrcat(szKey, pszSubkey); }
ec = RegCreateKeyEx(HKEY_CLASSES_ROOT, szKey, 0, NULL,REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS,NULL, &hKey, NULL);
if(ERROR_SUCCESS == ec) { if(NULL != pszValue) { ec = RegSetValueEx(hKey, NULL, 0, REG_SZ, (BYTE *)pszValue,
(lstrlen(pszValue)+1)*sizeof(TCHAR)); } if(ERROR_SUCCESS == ec) bOk = TRUE; RegCloseKey(hKey); }
return bOk;}
16
21.AddBack 프로젝트를 build 하여 AddBack.exe 파일 생성
22.AddBack COM 컴포넌트를 레지스트리에 등록1. AddBack /regserver
2. 이것을 수행하기 위해서는 예전에 등록하였던 것을 해제하고 새로 등록해야 한다 .
23.AddFront 애플리케이션을 실행하여 AddBack COM 컴포넌트 실행 확인1. AddBack 컴포넌트를 생성할 수 없다는 에러 발생2. AddBack Local Server 에 인터페이스를 marshalling 하는
Proxy/Stub DLL 이 없기 때문
17
Proxy/Stub DLL 생성
MIDL 컴파일러가 생성한 코드 사용1. Visual C++ 개발 환경의 [File/New] 메뉴 항목 선택2. [New] 대화 상자의 [Project] 탭에서 [Win32
Dynamic Link Library] 항목 선택3. [Location] 텍스트 상자에 앞에서 생성한 AddBack
폴더 지정4. [Project] 텍스트 상자에 ‘ Marshal’ 이라고 입력5. [Add to current workspace] 옵션 선택6. [OK] 버튼 클릭
18
19
7. MIDL 컴파일러가 생성한 AddBack_i.c, AddBack_p.c, 그리고 DllData.c 파일을 Marshal 프로젝트에 포함시킨다
20
8. 프로젝트에 RPC runtime import library 를 추가하기 위해 [Project/Settings] 메뉴 항목을 선택하여 [Project Settings] 대화 상자의 [Link] 탭을 선택한 후 [Object/libraries modules] 텍스트 상자에 rpcrt4.lib 파일을 추가한다
21
9. [Project Settings] 대화 상자 왼쪽의 트리뷰에서 DllData.c 항목을 선택하고 , 오른쪽 [C/C++] 탭에서 [Preprocessor definitions] 텍스트 상자에 ‘ REGISTER_PROXY_DLL’ 을 추가한다 . 이것은 생성된 Proxy/Stub 코드가 자기 등록을 할 수 있게 하기 위한 것이다 .
22
10.Marshal 프로젝트에 ‘ Marshal.def’ 파일을 생성하여 추가
LIBRARY Marshal.dll
DESCRIPTION 'Proxy/Stub DLL'
EXPORTSDllGetClassObject@1 PRIVATEDllCanUnloadNow @2 PRIVATEGetProxyDllInfo @3 PRIVATEDllRegisterServer@4 PRIVATEDllUnregisterServer @5 PRIVATE
11.Marshal 프로젝트를 build 하여 Marshal.dll 파일을 생성
12.regsvr32.exe 를 사용하여 Proxy/Stub DLL COM 컴포넌트를 레지스트리에 등록1. regsvr32 Marshal.dll
13.AddFront 애플리케이션을 실행하여 AddBack COM 컴포넌트가 제대로 실행되는지 확인