배경
  1. ROT(Running Object Table)를 통해 IPC(Inter-Process Communication)통신을 이루는 COM Server/Client. 본 채널을 가리켜 lightweight RPC라고 한다나?(Server와 Client 모두 동일 호스트에서 동작하기 때문에 RPC는 아니라고).
  2. COM Server는 USB 드라이브와 통신하며, COM Client는 IE browser에 내장되어 Server와 연결짓는 역할(따라서 COM client 역시 browser를 위한 COM Server 역할을 담당). Client의 메서드와 이벤트는 javascript를 통해 호출 및 수신한다.
  3. COM Server/Client 모두의 threading model은 STA(Single Thread Apartment).
  4. COM Server 쪽에는 UI가 있어 내장 IE Browser가 달려있음.
문제
  1. COM Server 메서드 호출은 성공. 허나 COM Server에서 event firing시 Fire 위치에 따라 성공 또는 실패하는 황당한 상황이 발생. 실패 시 HRESULT 값 : 0x8001010d(An outgoing call cannot be made since the application is dispatching an input-synchronous call)
  2. 우연찮게 COM Server의 threading model을 MTA(Multi Thread Apartment)로 바꿨더니, 1의 문제가 사라짐. 하지만 내장 IE Browser window의 위치가 desktop window origin에 달라붙어 떨어지지 않는 상황이 발생(MoveWindow() 등의 API가 전혀 안먹음).
문제 발생 원인
  • 이벤트 메서드(Fire_XX()) 호출이 실패한 위치는 USB 드라이브 측에서 던진 message(드라이브 연결/끊김 등) handler 내에서였음. 본 handler는 message를 던진 측 routine과 동기적으로 동작하기에, 본 handler 내에서 (process 외부에서 동기적으로 동작할?) method를 호출할 수 없기에 발생함. 위 HRESULT 값을 통해 본 사항을 간접적으로 확인할 수 있겠다.
해결
  • 동기적으로 발생하는 calling chain을 끊어버린다. 즉, USB event handler 내에서 non-blocking 모드로 동작하는 PostMessage()를 던짐으로써 USB 드라이브에서 던진 message에 대해 비동기적으로 이벤트를 처리한다.
    reference : http://discuss.develop.com/archives/wa.exe?A2=ind0303a&L=atl&P=3378
etc.
  1. 왜 MTA 기반에서는 정상적으로 동작했을까? STA 기반의 COM Server에서는 이벤트 발생 메서드인 Fire_XX()가 동기적으로 동작하나(blocking mode), MTA에서는 non-blocking 모드로 동작하기에 동기적 calling chain이 만들어지지 않으므로. 왜 이런식으로 동작하는지는 연구 대상.
    COM threading model reference :
    Understanding and Using COM Threading
    INFO: Descriptions and Workings of OLE Threading Models
  2. MTA 기반에서 IE Browser window의 위치가 제멋대로 노는 원인은 미결. IE Browser Control은 out-of-process COM이라는데, 요게 단서가 될지도 모른다는...
푸념
  • message가 SendMessage(동기 모드)으로 던저졌는지, PostMessage(비동기 모드)로 던저졌는지 그걸 뭔 수로 아는가. 딱히 구분할 값을 던져주는 것도 아니고. 각 message에 대한 설명서를 일일이 확인해야 하는 상황. 나참, 어이가 없어서리.
2008/03/20 18:25 2008/03/20 18:25

트랙백 주소 :: http://anyflow.net/trackback/364

댓글을 달아 주세요

제프리 릭터의 Programming Applications for Microsoft Windows에 담긴 내용입니다.

이벤트(Event) 커널 객체 : 커널 객체 중 가장 원시적인 객체. 사용 카운트(usage count), 자동 리셋(auto reset)-수동 리셋(manual reset) 상태 여부를 구분하는 불 값, 신호-비신호 상태 여부를 구분하는 불 값으로 구성되더라..
수동 리셋 이벤트 : 신호 상태가 되었을 때, 이벤트를 기다리던 모든 쓰래드가 스케쥴 가능 상태가 되더라..
자동 리셋 이벤트 : 신호 상태가 되었을 때, 이벤트를 기다리던 쓰래드 중 하나만 스케쥴 가능 상태가 되더라..

용도 : 쓰래드 하나가 초기 작업을 한 이후에 다른 쓰래드(들)로 하여금 나머지 작업을 하도록 신호를 보낼 경우에 사용하더라...

//이벤트 생성
HANDLE CreateEvent (
    PSECURITY_ATTRIBUTES psa,
    BOOL fManualReset,
    BOOL fInitialState,
    PCTSTR pszName);

fManualReset : 수동 리셋(TRUE)인지, 자동 리셋(FALSE)인지의 여부
fInitialState : 신호상태(TRUE)로, 비신호상태(FALSE)로 초기화되는지의 여부

HANDLE OpenEvent (
    DWORD fdwAccess,
    BOOL fInherit,
    PCTSTR pszName);

//이벤트를 신호 상태로 변경시킨다.
BOOL SetEvent ( HANDLE hEvent );

//이벤트를 비신호 상태로 변경시킨다.
BOOL ResetEvent ( HANDLE hEvent );

//SetEvent를 호출했다가 바로 ResetEvent를 호출한 것과 동일한 효과..
BOOL PulseEvent ( HANDLE hEvent );
2004/10/26 00:45 2004/10/26 00:45
TAG ,

트랙백 주소 :: http://anyflow.net/trackback/18

댓글을 달아 주세요