'프로그래밍'에 해당되는 글 16건

  1. 2007.07.24 [COM] Moniker
  2. 2007.07.23 [COM] Persistense
  3. 2007.07.22 [COM] Type Library
  4. 2007.07.22 [COM] Component Category
  5. 2007.07.19 [COM] 오토메이션 타입 정리
  6. 2007.07.19 [COM] SafeArray 처리
프로그래밍2007.07.24 00:59
각 타입별 이름 짓는 규칙을 표준화된 모니커 인터페이스를 통해서 지을 수 있도록 함

시스템 모니커 종류 : 이름 짓는 객체에 대해 추가의 정보 필요
파일 모니커 : CreateFileMoniker
아이템 모니커 : CreateItemMoniker
포인터 모니커 : CreatePointerMoniker
안티 모니커 : CreateAntiMoniker
복합 모니커 : CreateGenericComposite
클래스 모니커 : CreateClassMoniker
URL 모니커 : CreateURLMoniker
OBJREF 모니커 : CreateObjrefMoniker

커스텀 모니커
IMoniker 인터페이스 구현

IBindCtx ( 바인드 컨텍스트 )
모니커 바인딩 동작에 대한 정보를 가지고 있는 객체

IMoniker::BindToObject ( 바인드 컨텍스트 정보를 인자로 넘겨줌 )
BindMoniker 헬퍼 메소드 ( 바인드 컨텍스트 정보 넘겨주지 않음 )

IMoniker::GetDisplayName 모니커의 디스플레이 이름을 리턴
IMoniker::ParseDisplayName 디스플레이 이름으로 모니커 객체를 가져옴

MkParseDisplayname 함수
원하는 타입의 모니커 객체를 가져옴
IMoniker::ParseDisplayName과 유사하나 모니커가 필요없이 모니커를 가져옴
ProgID:ObjectName 형식의 문자열을 취함 ex : "clsid:{0000-0000{00-00}}"

CoGetClassObject 함수 : 디스플레이 이름의 모니커를 변환하고 이름지어진 객체로 바인딩하는 과정을 단순화 시킴

IClassActivator 인터페이스 : 클래스 모니커의 기본 동작을 가로채서 변경할 수 있도록 해줌.

IMoniker * pClassMoniker;
CreateClassMoniker( clsid , &pClassMoniker);

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

// 바인드 컨텍스트 시작
IBindCtx * pBindCtx;
CreateBindCtx(0, &pBindCtx);

ULONG eaten;
IMoniker * pMoniker;
OLECHAR string[] = L"clsid:00000000-0000-0000-000000000000001";
MkParseDisplayName(pBindCtx, string, &eaten, &pMoniker);

// 모니커에서 클래스 팩토리를 바인딩 한다.
IClassFactory * pClassFactory;
pMoniker->BindToObject(pBindCtx, NULL, IID_IClassFactory, (void**)&pClassFactory);

// 클래스 팩토리로 COM객체를 생성한다.
IUser * pUser;
pClassFactory->CreateInstance(&pUser);

// 무엇을 한다
pUser->Some();

// 모든 것을 헤제한다.
pClassFactory->Release();
pUser->Release();
pBindCtx->Release();
pMoniker->Release();



ROT ( 동작 객체 테이블 )
객체들이 스스로 등록할 수 있는 컴퓨터 단위의 테이블
모니커를 객체에 바인딩 할때, ROT를 통해서 모니커는 객체가 이미 동작중인지를 확인할 수 있다. -> 불필요하게 새로운 인스턴스 생성X

GetRunningObject 함수를 통하여 IRunningObjectTable 인터페이스 를 얻어서 ROT에 등록 하고 해제한다.

// ROT의 모니커이름을 뿌려줌 ////////////////////////
/////////////////////////////////////////////////////////

IRunningObjectTable * pRunningObjectTable;
GetRunningObjectTable(NULL, &pRunningObjectTable);

IEnumMoniker * pEnumMoniker;
pRunningObjectTable->EnumRunning(&pEnumMoniker);

IMoniker * pMoniker;
IBindCtx * pBindCtx;
OLECHAR * moniker_name;

// 모든 모니커에 루프를 돔
while(pEnumMoniker->Next(1, &Moniker, NULL) == S_OK)
{
CreateBindCtx(0, &pBindCtx);

pMoniker->GetDisplayName(pBindCtx, NULL, &moniker_name);
wprintf(L"DisplayName is %s\n", moniker_name);
CoTaskMemFree(moniker_name);

pMoniker->Release();
pBindCtx->Release();
}

pEnumMoniker->Release();
pRunningObjectTable->Release();





MSDN : http://msdn2.microsoft.com/en-us/library/ms688618.aspx ( IMoniker-Class Moniker Implementation )
Posted by 꿍스
프로그래밍2007.07.23 22:21
COM 객체에 영속성을 부여하기 위한 방법

IPersist
COM 객체가 영속성 객체임을 구현

인터페이스를 상속받은 인터페이스
IPersistStream : 스트림 사용
IPersistStreamInit : IPersistStream에서 초기화를 위해 InitNew 메쏘드 추가
IPersistMemory : 스트림 대신에 메모리
IPersistStorage : 스토리지를 사용
IPersistFile : 파일을 사용
IPersistPropertyBag2 : 프로퍼티 백 사용 ( ActiveX 콘트롤 속성값 )
IPersistMoniker : 모니커 사용
IPersistHistory : 사용자 웹사이트 히스토리 저장(익스플로러)
위 인터페이스를 COM 객체에 구현하여 영속성을 부여 함

ATL에서는 위 인터페이스들 중에서 구현 클래스를 제공한다
IPersistStreamInitImpl
IPersistStoreageImpl
IPersistPropertyBagImpl

구현
IPersistStream을 구현할시에 CLSID도 같이 스트림에 저장하고 빼온다
OleSaveToStream, OleLoadFromStream 헬퍼 함수 사용

IStream
IPersistStream, IPersistStreamInit 인터페이스를 구현하는 COM 영속성 객체에 실제로 스트림에 읽거나 쓰는 클라이언트 구현 인터페이스
IPersistStream, IPersistStreamInit 의 Save , Load 메소드의 인자로 IStream 인터페이스가 전달됨

사용 방법
// COM 객체생성
IUnknown * pUnknown;
... CoCreateInstance 중략

// IPersistStreamInit 인터페이스 가져옴
CComPtr <IPersistStreamInit> pPersistStreamInit;
hr = pUnknown->QueryInterface(IID_IPersistStreamInit, (void**)&pPersistStreamInit);

// 메모리 기반 스트림
CComPtr <IStream> pStream;
hr = CreateStreamOnHGlobal(NULL, TRUE, &pStream);

// 초기화
hr = pPersistStreamInit->InitNew();

// 객체를 스트림으로 저장
hr = pPersistStreamInit->Save(pStream, TRUE);

// 포인터를 처음으로 옮김
LARGE_INTEGER zero = {0, 0};
hr = pStream->Seek(zero, STREAM_SEEK_SET, NULL);

// 새로운 객체 생성
// IPersistStreamInit 인터페이스를 가져옴

// 스트림에서 객체 가져옴
hr = pPersistStreamInit->Load(pStream);

구현 방법
CreateStreamOnHGlobal : 일반적인 IStream 인터페이스의 구현을 얻음 ( 글로벌 메모리의 블록에 기반한 스트림 객체 생성 ) <-> GetHGlobalFromStream
구조화된 저장 서비스 : 디스크 기반의 파일로 스트림 저장

데이터를 저정하기 위한 표준화 되고 구조적인 형식으로 단일 파일내에 데이터를 저장
IStorage 인터페이스를 이용하여 IStream 인터페이스 객체 생성

// 구조화된 저장소 파일을 생성 하거나 오픈하고 IStorage 인터페이스를 얻어옴
CComPtr IStorage pStorage;
hr = StgCreateStorageEx(L"C:\\test.stg", STGM_DIRECT | STGM_CREATE | STGM_READWRITE | STGM_SHARE_EXCLUSIVE, STGFMT_STORAGE, 0, 0, IID_IStorage, (void**)&pStorage);

// Stream 객체를 생성하고 IStream 인터페이스를 얻어옴
CComPtr IStream pStream;
hr = pStorage->CreateStream(L"TestStream", STGM_DIRECT | STGM_CREATE | STGM_WRITE | STGM_SHARE_EXCLUSIVE, 0, 0, &pStream);

// 파일에 데이터를 쓴다.
ULONG bytes_written;
char data[] = "HELLO THERE!";
pStream->Write(data, strlen(data), &bytes_written);

Property ( 속성 )
표준화된 방법 으로 요약정보를 저장하는 데 사용할 수 있는 속성 집합 형식 ( Ex : 파일 요약 정보 )

// IStorage 인터페이스로 IProperySetStorage 인터페이스를 가져옴
CComPtr <IPropertySetStorage> pPropertySetStorage;
pStorage->QueryInterface(IID_IPropertySetStorage, (void*)&pPropertySetStorage);

// IPropertySetStorage 인터페이스를 이용하여 IPropertyStorage 인터페이스 객체 생성
CComPtr <IPropertyStorage> pPropertyStorage;
pPropertyStorage->Create(FMTID_SummaryInformation, NULL, PROPSETFLAG_ANSI, STGM_CREATE | STGM_READWRITE | STGM_SHARE_EXCLUSIVE, &pPropertyStorage);

속성집합을 정의
PROPSPEC(속성구별자 또는 문자열 이름) , PROPVARIANT(속성 값) 구조체 이용

PROPSPEC ps;
ps.ulKind = PRSPEC_PROPID;
ps.propid = PIDSI_AUTHOR;

PROPVARIANT pv;
pv.vt = VT_LPSTR;
pv.pszVal = "Anna";

hr = pPropertyStorage->WriteMultiple(1, &ps, &pv, 0);

MSDN : http://msdn2.microsoft.com/en-us/library/aa380369.aspx (Structured Storage)
Posted by 꿍스
프로그래밍2007.07.22 17:20
타입 라이브러리는 인터페이스 정의의 이진 형식

IDL정의시 library 키워드 사용

타입 라이브러리 생성

// 타입 라이브러리 파일 생성
ICreateTypeLib2 * pCreateTypeLib2;
CreateTypelib2(SYS_WIN32, L"C:\\mylib.tlb",&pCreateTypeLib2);

// 타입 정보 추가
ICreateTypeInfo * pCreateTypeInfoInterface;
pCreateTypeLib2->CreateTypeInfo(L"IUser", TKIND_INTERFACE, &pCreateTypeInfoInterface);

타입 정보 얻기

ITypeLib* pTypeLib;
LoadRegTypeLib(LIBID_User, 1, 0, LANG_NEUTRAL, &pTypeLib);
HRESULT hr = pTypeLib->GetTypeInfoOfGuid(CLSID_UserCOM, &pTypeInfo);
pTypeLib->Release();

ITypeComp
ITypeLib, ITypeInfo를 거칠 필요 없이 타입 라이브러리내의 타입 정보들을 빠르게 찾아낼 수 있다.

자세한 사항은 MSDN : http://msdn2.microsoft.com/en-us/library/ms221398.aspx
Posted by 꿍스
프로그래밍2007.07.22 16:06
인터페이스가 많아지면 규모성의 문제가 생김 -> 특정 인터페이스들을 지원하는 컴포넌트를 카테고리 별로 분류
클라이언트 프로그램은 레지르스트리를 빠르게 검색하여 특정 카테고리를 지원하는 컴포넌트를 구별하여 인스턴스화 함

카테고리 구별자 CATID
HKEY_CLASSES_ROOT > Component Categories
HKEY_CLASSES_ROOT > CLSID

컴포넌트 객체는 Implemented Categories 레지스트리 키를 사용하여 자신이 지원하는 컴포넌트 카테고리들을 알린다.

컴포넌트 객체는 Required Categories 레지스트리 키를 사용하여 자신이 받아들일 수 있는 클라이언트의 카테고리를 알린다.
( 객체에 접근할 수 있는 클라이언트를 매우 제한하여 버리기 때문에 조심해서 사용 )

카테고리의 기본 컴포넌트

TreatAs 레지스트리 키를 이용하여 카테고리의 기본 컴포넌트로 사용할 수 있다.
ToolBoxBitmap32 서브키를 이용하면 OLEViewer 에서 아이콘을 볼수 있다.

클래스 에뮬레이션

코클래스가 발전해나감에 따라 새로운 CLSID를 할당하여 사용하고자 한다면 기존의 CLSID에서 에뮬레이션하여 새로운 CLSID로 연결할 수 있다.
CoTreatAsClass, CoGetTreatAsClass 함수로 에뮬레이션을 설정하거나, 설정된 에뮬레이션 클래스를 가져온다.
이역시 TreatAs 레지스트리 키를 이용 한다.

카테고리 등록
ICatRegister 인터페이스 이용
ComponentCategoryManager를 이용하여 카테고리를 관리한다.

#include // 컴포턴트 카테고리 지원

CATID_USER = {....{ ... }} // UUID

ICatRegister * pCatRegister;
CoCreateInstance(CLSID_StdComponentCategoriesMgr,Null, CLSCTX_INPROC_SERVER, IID_ICatRegister, (void)**&pCatRegister);

CATEGORYINFO catinfo;
catinfo.catid = CATID_USER;
wcsncpy(catinfo.szDescripction, L"사용자",128);

// 등록
pCatRegister->RegisterCategories(1, &catinfo);

// 등록해제
pCatRegister->UnRegisterCategories(1, &CATID_USER);

// 등록, 해제할 컴포넌트 카테고리들
CATID rgcatid[3];
rgcatid[0] = CATID_USER;
rgcatid[1] = CATID_......
rgcatid[2] = CATID_......

// 컴포넌트 카테고리들에 컴포넌트 객체 등록
pCatRegister->RegisterClassImplCategories(CLSID_UserCOM, 3 , rgcatid);
// 컴포넌트 카테고리들에 컴포넌트 객체 해제
pCatRegister->UnRegisterClassImplCategories(CLSID_UserCOM, 3 , rgcatid);

pCatRegister->Release();

카테고리 정보 얻기
ICatInformation 인터페이스 이용
ComponentCategoryManager를 이용하여 카테고리를 관리한다.

ICatInformation * pCatInformation;
CoCreateInstance(CLSID_StdComponentCategoriesMgr,Null, CLSCTX_INPROC_SERVER, IID_ICatInformation, (void)**&pCatInformation);

IEnumCLSID * pEnumCLSID;
pCatInformation->EnumClassesOfCategories(1, &CATID_USER, 0, NULL, &pEnumCLSID);

pCatInformation->Release();

액티브X 컨트롤은 자동으로 ActiveX의 컴포넌트 카테고리로 등록이 된다.

MSDN : http://msdn2.microsoft.com/en-us/library/ms692689.aspx
Posted by 꿍스
프로그래밍2007.07.19 23:54
헬퍼함수는 MSDN색인으로 나오지 않아서 따로 정리 하였습니다.

Variant
오토메이션 호환 타입들의 Union

헬퍼함수
VariantChangeType(Ex)
VariantClear
VariantCopy
VariantCopyInd
VariantInit

ATL 클래스
CComVariant

BSTR
문자열 길이를 접두어로 포함하는 문자열

헬퍼함수
SysAllocString
SysAllocStringByteLen
SysAllocStringLen
SysFreeString
SysReAllocString
SysReAllocStringLen
SysStringByteLen
SysStringLen

ATL클래스
CComBSTR

SafeArray
안전하게 다룰 수 있는 배열

헬퍼함수
SafeArrayAccessData
SafeArrayAllocData
SafeArrayAllocDescriptor(Ex)
SafeArrayCopy
SafeArrayCopyData
SafeArrayCreate(Ex)
SafeArrayCreateVector(Ex)
SafeArrayDestory
SafeArrayDestroyData
SafeArrayDestoryDescriptor
SafeArrayGetDim
SafeArrayGetElement
SafeArrayGetElemsize
SafeArrayGetLBound
SafeArrayGetUBound
SafeArrayLock
SafeArrayPtrOfIndex
SafeArrayPutElement
SafeArrayRedim
SafeArrayUnaccessData
SafeArrayUnlock
SafeArraySetRecordInfo
SafeArrayGetRecordInfo
SafeArraySetIID
SafeArrayGetIID
SafeArrayGetVartype

ATL클래스
CComSafeArray
CComSafeArrayBound

사용자 정의 타입
user-defined type, UDT

구조체에 GUID를 할당 하기 위해 typedef 이용

typedef [ uuid([UUID적음])]
 struct myDataType {
  int x;
  int y;
 } myDataType;

Variant 타입의 VT_RECORD
IRecordInfo 인터페이스 구현

GetRecordInfoFromTypeInfo : 타입정보에서 서술한 UDT의 RecordInfo 얻음
GetRecordInfoFromGuids : uuid 를 통해 UDT의 RecordInfo 얻음

IRecordInfo 포인터를 얻음

IRecordInfo * precordInfo = 0;
hr = GetRecordInfoFromTypeInfo(pTypeInfo, &pRecordInfo);

Posted by 꿍스
프로그래밍2007.07.19 23:18
#include <iostream>
using namespace std;

#include <windows.h>
#include <comdef.h>

void ComCall(VARIANT* pRetVal)
{
enum { ARR_SIZE = 5 };
VariantInit(pRetVal);

short ia[ARR_SIZE] = {5, 6, 7, 8, 9 }; //넘기고자 하는 배열

SAFEARRAYBOUND sab = { ARR_SIZE, 0 };
SAFEARRAY* pSa = SafeArrayCreate(VT_VARIANT, 1, &sab);

_variant_t* _p;
// 만든 SA배열에 포인터를 연결시킴
SafeArrayAccessData(pSa, reinterpret_cast<void**>(&_p));

for (long i = 0; i < ARR_SIZE; i++) {
_p[i] = (long)ia[i];
}

SafeArrayUnaccessData(pSa);

pRetVal->vt = VT_VARIANT | VT_ARRAY;
pRetVal->parray = pSa;

// 위에 두줄을 이렇게 해도 됨
//_variant_t var;
//var.vt = VT_VARIANT | VT_ARRAY;
//var.parray = pSa;
// 꼭 Detach로 넘겨야함 그냥 대입하면 var변수가 메모리가 헤제되버림
// 그럼 *pRetVal 도 같이 메모리 해제되어서 ....
//*pRetVal = var.Detach();
}

int main()
{
_variant_t var;
ComCall(&var);

SAFEARRAY* pSa;

if (var.vt & VT_ARRAY) {
if (var.vt & VT_BYREF)
pSa = *var.pparray;
else
pSa = var.parray;
}
else {
cout << "SafeArray가 아님" << endl;
reutrn 0;
}

long lUBound = 0;
SafeArrayGetUBound(pSa, 1, &lUBound);

_variant_t* _p;
SafeArrayAccessData(pSa, reinterpret_cast<void**>(&_p));

for (int i = 0; i <= lUBound; i++) {
cout << static_cast<long>(_p[i]) << endl;
}

SafeArrayUnaccessData(pSa);

cout << "== END ==" << endl;
cin.get();

return 0;
}


Posted by 꿍스