티스토리 뷰



엑셀 자동화를 사용하다보면, GetObject 혹은 GetActiveObject 함수를 이용하여, 현재 실행되고있는 엑셀 인스턴스의 디스패치를 얻어서 사용하게 될 경우가 발생한다.

이론적으로 ROT(Runtime Object Table) 에서 각 개별 인스턴스를 추출할 수 있지만 항상 모니커가 응용프로그램에 종속되므로 다른 인스턴스가 이미 ROT에 등록 되어있으면 Office 응용 프로그램은 인스턴스를 ROT에 등록하지 않는다.( 모니커는 등록되지만 인스턴스는 등록되지 않는다는 뜻 ). 즉, 첫 번째 제외한 모든 인스턴스에 연결할 수 없는 상태가 발생한다. 이를 해결할 수 있는 방법이 존재하는데, Office에서 문서 각각도 ROT에 등록이 된다는 점을 응용하여 해당 인스턴스의 문서를 특별하게 저장해두고 ROT에서 그 문서를 찾아 그 문서를 가지고 있는 인스턴스를 찾는 방법으로 해결할 수 있다.


아래의 내용은, ROT에 인스턴스의 워크북 디스패치를 등록하는 방법이다.

//새로운 엑셀 인스턴스 생성후 워크북까지 만듬, 그리고 Save As로 워크북의 이름을 지정함

TRACE_DEBUG( "[CExFinDlg][Install]2.1" );

if ( !xl.CreateDispatch("Excel.Application") ) {

THROW( CWinException::CreateException( "엑셀을 실행할 수 없습니다." ) );

}

TRACE_DEBUG( "[CExFinDlg][Install][CreateDispatch]2.2" );

books = xl.GetWorkbooks();

book = books.Add( covOptional );

TRACE_DEBUG( "[CExFinDlg][install][GetWorkbook]2.3" );

book.SaveAs(COleVariant(xlsPath), covOptional, covOptional,covOptional,covOptional,

covOptional,0,covOptional,covOptional,covOptional,covOptional);



다음으로, 등록한 워크북의 디스패치를 ROT에서 검색하고, 워크북 디스패치를 통해

어플리케이션의 디스패치를 얻어 리턴하는 함수를 구현한다.

IRunningObjectTable * pRot = NULL;

IEnumMoniker * pEnum = NULL;

IDispatch *pDisp = NULL;

HRESULT hr;

if( SUCCEEDED( GetRunningObjectTable( 0, &pRot )))

{

CString sCurName;

if( SUCCEEDED( pRot->EnumRunning( &pEnum )))

{

IMoniker *pMoniker = NULL;

IMoniker *prevMoniker = NULL;

while( SUCCEEDED( pEnum->Next( 1, &pMoniker, NULL )) && (NULL != pMoniker)

&& (pMoniker != prevMoniker))

{

IBindCtx * pContext = NULL;

if( SUCCEEDED( CreateBindCtx( 0, &pContext )))

{

WCHAR *wCurName = NULL;

hr = pMoniker->GetDisplayName( pContext, NULL, &wCurName );

sCurName = wCurName;

if( (SUCCEEDED( hr )) && (sCurName.Find( xlsPath ) > -1 ))

{

pMoniker->BindToObject( pContext, NULL, IID_IDispatch, (void **)&pDisp);

Workbooks wbs = Workbooks( pDisp );

pDisp = wbs.GetApplication();

break;

}

}

prevMoniker = pMoniker;

}

//pMoniker->Release();

//prevMoniker->Release();

}

}

pRot->Release();

pEnum->Release();

return pDisp;

위 두 가지 과정을 통해 엑셀 자동화기능을 통한 접근에서, 엑셀의 인스턴스를 따로 생성하여 이용할 수 있도록 GetObject 함수를 수정해보았다.

이 기능에서, 워크북 파일을 내부에 생성하게 되므로, 프로그램이 실행되었을 때, 엑셀 워크북이 ROT에 존재하는지 먼저 체크하고 ROT에 존재한다면 AttachDispatch 를 실행. 존재하지 않는다면 워크북 파일이 로컬에 존재하는지 체크하여 삭제 후 다시 새로운 워크북 생성후 저장

등 조금은 더러운 코딩이 되었다 흑흑...





참조 문서

http://www.devpia.com/MAEUL/Contents/Detail.aspx?BoardID=50&MAEULNo=20&no=608230&ref=608230 (코드)

http://www.trilightzone.org/board/about2285.html (이론적내용)

댓글