2012-03-21 23 views
0

私の例: PowerPointは、埋め込みワークブックを挿入するときにExcelを起動します。 私はPowerPointを使い続けています。 Excelは隠されたプロセスのままです。 私はPowerPointを閉じると、それ自体を閉じるためにExcelに言います(Excelは後でPowerPointを閉じます)。 PowerPointを殺すとExcelがゾンビになります。 アドインがExcelプロセスに読み込まれます。STA COMからSTA COMへの通信を外すか、または参照カウントを減らすのか?

どのようなメッセージ(私はCOM STAオブジェクトがWindowsメッセージングを介して通信していることを読んでいます)を傍受してそのようなイベントについて通知する必要がありますか?私はどんなフックを使うべきですか? COMオブジェクトの変更を参照する回数について通知する意味はありますか?

UPDATE

私の質問はあいまいだったようです。私はPowerPointを殺すと大文字小文字を処理しようとしていません。 PowerPointが正常に終了したときにPowerPointが何らかのメッセージをExcelに送信したという証拠にすぎません。私は正当な理由でこのメッセージを傍受しようとしています。

アップデート2

私はAPIを使用することはできません - APIが失敗したため。私は解決しようとしていますCreating class in new thread in new app domain and providing it with Office COM object in embedded mode leads to zombie process

+0

は良い仕組みがありません予期しないプロセスの終了に対処するためにout-of-proc COMで実行します。ハードクラッシュが捕捉され、RPC_E_SERVERFAULTエラーコードを使用してクライアントに報告されます。サーバーは稼動し続けます。あなたが頭の中でそれを撃つならば、混乱を取り除くのはあなたの仕事です。 –

+0

"正当な理由でこのメッセージを傍受しようとしています。"これを行うには理由がありません。あなたは何を***実際にしようとしていますか? – Ben

+0

私の問題を説明するUPDATE2を追加しました。 –

答えて

1

なしローカルサーバー上のCOMはWindowsメッセージを使用しますが、実装の詳細なプライベートメッセージを使用します。本当にしていることは、「あなたのアパートに新しいCOMイベントがある」という意味の隠れたウィンドウへの投稿メッセージです。隠しウィンドウは、共有メモリを使用して他のプロセスと通信するCOMライブラリを渡し、イベントの内容(コール、コールリターンなど)を見つけるなどの残りの作業を行います。

言い換えれば、「excel go away」と言うメッセージはなく、変更することができる実装の詳細なので、それに頼ることができなかったとしても。

  • あなたが埋め込みスプレッドシートを含むPowerPointの文書を閉じ

    は、PowerPointは、それが保持しているすべてのオブジェクト上のIUnknown :: release()を呼び出します。 Excelは未処理のオブジェクトの内部トラックを保持し、すべてが消えたときに閉じます。

は、Excelプロセスでアドインを持っている、とExcelが閉じたときに知りたい場合は、調べるためにアドインAPIを使用します。

アドインのタイプによっては、このためのAPIが異なります。 COMアドインには、登録可能なイベントがあります。しかし、それは別の質問です。「私のExcelアドインで、目に見えないExcelインスタンスが終了していることをどうすれば通知できますか?実際の問題/質問へ

に加えた溶液をasd.and.Rizzo @

を求めていない、これはあなたがExcelで作成されたオブジェクトへの保持ノウサギので、発生しています。これは、誰かがオブジェクトを使用しているためにExcelが終了できないとExcelが判断したことを意味します。そのsomoneがアドインであるため、Excelは正しいです。

この種の生涯の問題は、OfficeアドインまたはExcelアドインを作成する場合によく発生し、.Netアドイン固有の問題ではありません。

Excelの参照カウントを不正使用して問題を解決したいと考えています。しかし、それはあなたの手にあります:オブジェクトを保持しているので、参照カウントは唯一です!あなたがそれらをリリースすれば、カウントは0になるでしょう。

ソリューション

最善の解決策は、イベントをシンク避け、任意のオブジェクトへの保持を避けるためです。あなたのアドインが何をしているかによっては、これは不可能かもしれません。

できない場合は、ドキュメントのクローズイベントをシンクする必要があります。それぞれに、開いている文書の数を確認してください。カウントがゼロになると、イベントハンドラを削除し、これまで持っていたすべてのオブジェクトに対してMarshall.ReleaseComObjectを呼び出して、アドインをアンロードする必要があります。 Excelが終了します。

しかし、注意してください:あなたの必見コールMarshall.ReleaseComObjectあなたが保持するすべてのオブジェクトを。そうしないと、Excelは決して終了しません。このは、AppDomainをアンロードするとになるはずです。

+0

ExcelアドインでExcelに関連して呼び出されるIUnknown :: Release()を傍受する方法はありますか? –

+0

@ asd.and.Rizzo、あなたは足にフィットするようにつま先を切り取る最善の方法を求めています。 ***そうしないでください***。あなたは別の靴が必要です。あなたが実際に解決しようとしている問題を教えてください。私たちの中には、Excelのアドインを書いている人もいますし、COMのことを知っている人もいます。 – Ben

+0

私はこのフォーラムで私の前の投稿を削除しましたが、無回答のままでした。 –

1

「PowerPoint」を削除すると、Excelで参照カウントの変更が発生しません。だからこそアンロードされていないのです。

私はあなたが単にExcelプロセスのメインウィンドウにWM_QUITメッセージを投稿するかもしれないと信じています。 Visual Studioにバンドルされているツールである "Spy ++。exe"を使って見つけることができます。また、Excelでオブジェクトのクラスファクトリを取得し、fLock = FALSEを指定して 'LockServer'メソッドを呼び出すこともできます。これにより、Excelサーバーの参照カウントが減少します。

アドインはホストアプリケーションの動作に影響を与えてはならないので、これをハックと見なしてください。

+0

私はいくつかのネイティブAPIを使用して早急にExcelを「解放する」ことがクールだと思います。私はIClassFactoryを試みます。 –

0

私は次に(COMインターフェイスを純粋なC構造体+関数とDirect Xハックと解釈することから)見つけました。動作しますが何らかの理由で問題を解決しません。私のBEは...ワークブック、ワークシートのために同じことを行う必要があります

宣言:


typedef HRESULT STDMETHODCALLTYPE QueryInterfacePtr( REFIID, void **); 
typedef ULONG STDMETHODCALLTYPE AddRefPtr(); 
typedef ULONG STDMETHODCALLTYPE ReleasePtr(); 

typedef ULONG STDMETHODCALLTYPE GetTypeInfoCountPtr(UINT *) ; 
typedef ULONG STDMETHODCALLTYPE GetTypeInfoPtr  (UINT, LCID, ITypeInfo **) ; 
    typedef ULONG STDMETHODCALLTYPE GetIDsOfNamesPtr (REFIID, LPOLESTR *, 
             UINT, LCID, DISPID *) ; 
    typedef ULONG STDMETHODCALLTYPE InvokePtr   (DISPID, REFIID, 
             LCID, WORD, DISPPARAMS *, 
             VARIANT *, EXCEPINFO *, UINT *) ; 

typedef struct { 
     // IUnknown functions 
    QueryInterfacePtr * QueryInterface; 
    AddRefPtr   * AddRef; 
    ReleasePtr   * Release; 
     // IDispatch functions 
GetTypeInfoCountPtr* GetTypeInfoCount; 
GetTypeInfoPtr* GetTypeInfo; 
GetIDsOfNamesPtr* GetIDsOfNames; 
InvokePtr* Invoke; 


} IDispatchInterceptor; 



typedef ULONG __stdcall releasePTR(IDispatch *self); 
typedef ULONG __stdcall addrefPTR(IDispatch *self); 

次は私がエクセルのために行われています:

 
static IDispatch * application = NULL; 
static releasePTR* realRelease = NULL; 
static addrefPTR* realAddRef = NULL; 
static ULONG wasAdd = 0; 
static ULONG oldCount = 0;

HRESULT STDMETHODCALLTYPE QueryInterfaceNativeOutOfProcSrv(REFIID riid, void **ppv){ return application->QueryInterface(riid,ppv);
}

ULONG STDMETHODCALLTYPE AddRefNativeOutOfProcSrv(){ return application->AddRef(); }

ULONG STDMETHODCALLTYPE ReleaseNativeOutOfProcSrv(){ return application->Release(); }

ULONG STDMETHODCALLTYPE GetTypeInfoCountSrv(UINT * count) { return application->GetTypeInfoCount(count); } ULONG STDMETHODCALLTYPE GetTypeInfoSrv (UINT n, LCID id, ITypeInfo ** inf) { return application->GetTypeInfo(n,id,inf); } ULONG STDMETHODCALLTYPE GetIDsOfNamesSrv (REFIID a, LPOLESTR * b, UINT c, LCID d, DISPID * e) { return application->GetIDsOfNames(a,b,c,d,e); } ULONG STDMETHODCALLTYPE InvokeSrv (DISPID a, REFIID b, LCID c, WORD d, DISPPARAMS * e, VARIANT * i, EXCEPINFO * j, UINT *k) { return application->Invoke(a,b,c,d,e,i,j,k); }

static IDispatchInterceptor interceptor = {QueryInterfaceNativeOutOfProcSrv,AddRefNativeOutOfProcSrv,ReleaseNativeOutOfProcSrv, GetTypeInfoCountSrv,GetTypeInfoSrv,GetIDsOfNamesSrv,InvokeSrv };

ULONG __stdcall release(IDispatch *self) {

ULONG c = realRelease(self); 
    Log->logWrite("release %d",c); 

    if ( c == 1) 
    { 
     if (instance != NULL) 
     { 

      instance->OnBeginShutdown(NULL); 
      Log->logWrite("OnBeginShutdown %d",c); 
      instance->OnEmbeddedDisconnection(); 
      Log->logWrite("OnEmbeddedDisconnection %d",c); 
      instance = NULL; 
     } 
    } 
//if (c == 2) { 
// c = realRelease(self); 
// c = realRelease(self); 
//} 

return c; 

}

ULONG __stdcall addref(IDispatch *self) {
ULONG c = oldCount; if (wasAdd == 0) { c = realAddRef(self); oldCount = c; wasAdd++; } else if (wasAdd == 1) { Log->logWrite("ADDREF FAKE %d",c); wasAdd++; } else if (wasAdd == 2) { Log->logWrite("ADDREF FAKE %d",c); wasAdd++; } else { c = realAddRef(self); }
Log->logWrite("ADDREF %d",c); return c; }

void InterceptRelease( IDispatch obj){ void iunknown_vtable= (void*)((unsigned int)obj); void* idispatch_vtable = (void*)(((unsigned int)iunknown_vtable)+8); unsigned int* v1 = (unsigned int*)idispatch_vtable; realRelease = (releasePTR*)*v1; DWORD old; VirtualProtect(v1,4,PAGE_EXECUTE_READWRITE,&old);

*v1 = (unsigned int) release; 

//while(obj->Release() > 0){}; 

}

void InterceptAddRef( IDispatch obj){ void iunknown_vtable= (void*)((unsigned int)obj); void* idispatch_vtable = (void*)(((unsigned int)iunknown_vtable)+4); unsigned int* v1 = (unsigned int*)idispatch_vtable; realAddRef = (addrefPTR*)*v1; DWORD old; VirtualProtect(v1,4,PAGE_EXECUTE_READWRITE,&old); *v1 = (unsigned int) addref; }

が適用されます。


IDispatch * app = Application; 
InterceptRelease(app); 
InterceptAddRef(app); 
関連する問題