2011-08-08 13 views
0

Shellextensionsで64ビットと32ビットの問題を回避するために、Visual Studio 2010でC++でOut-Of- (http://blog.mattmags.com/2007/06/30/accessing-32-bit-dlls-from-64-bit-code/)。Out-Of-Proc-COM-Server:BSTRが適切にマーシャリングされていない

私は、IDL-ファイルにここのようなインターフェイス(http://msdn.microsoft.com/en-us/library/ms686605%28v=VS.85%29.aspxを)説明:

import "unknwn.idl"; 
[ 
object, 
uuid("xx"), 
helpstring("IShellServerx86-Interface") 
] 
interface IShellServerx86 : IUnknown 
{ 
    HRESULT ShowFileInfo([in]BSTR file, [out]BSTR* htmlFile, [in]BSTR pathChar); 
}; 

をこのファイルには、私がまた標準マーシャラーメソッドを使用するように登録し、プロキシ/スタブDLLを生成します。 私は

IShellServerx86* pShellServer = NULL; 
CoCreateInstance(__uuidof(CShellServerx86), NULL, CLSCTX_LOCAL_SERVER, 
       __uuidof(IShellServerx86), (void**)&pShellServer); 

を呼び出した場合、サーバーが作成され、私は方法

HRESULT CShellServerx86::ShowFileInfo(BSTR file, BSTR* htmlFile, BSTR pathChar) 

し、作成したパラメータ(クライアント側)で呼び出すことができます。クライアントでは

BSTR filebstr = ::SysAllocString(A2OLE(file)); 
BSTR pathBstr = ::SysAllocString(A2OLE(pathChar)); 
BSTR htmlFileBstr = ::SysAllocString(A2OLE("")); 

をBSTRは正しく生成されますが、COMメソッドが呼び出されると(彼はそれを見つけます!)、dllhost.exeにデバッグします。間違ったエンコーディングが選択された場合、パラメータは無効です。私はプロジェクト全体を "Unicode"に設定しようとしましたが、何も変わりません。

設定を忘れてしまったのですか、マーシャリングのために他のデータ型を試す必要がありますか?

ありがとうございました。

EDIT:

クライアントの実装は次のとおりです。

int CShellWrapperx64Module::ShowFileInfo(IN const char* file, 
                OUT VARIANT &htmlFile, 
                IN const char* pathChar) 
{... 
    ::CoInitialize(NULL); 
    IShellServerx86* pShellServer = NULL 
    hr = ::CoCreateInstance(__uuidof(CShellServerx86), NULL, 
          CLSCTX_LOCAL_SERVER, __uuidof(IShellServerx86), 
          (void**)&pShellServer); 
    BSTR filebstr = ::SysAllocString(A2OLE(file)); 
    BSTR pathBstr = ::SysAllocString(A2OLE(pathChar)); 
    BSTR htmlFileBstr = ::SysAllocString(A2OLE("")); 
    //Call method of Server 
    hr = pShellServer->ShowFileInfo(filebstr, &htmlFileBstr, pathBstr); 
    ::CoUninitialize(); 
    VariantInit(&htmlFile); 
    htmlFile.vt = VT_BSTR; 
    htmlFile.bstrVal = htmlFileBstr; 
} 

サーバーメソッドは、次のように宣言されます。サーバーとクライアントの方法では

HRESULT CShellServerx86::ShowFileInfo(BSTR file, BSTR* htmlFile, BSTR pathBSTR) 
{... 
//TODO 
} 

デバッガBSTRを認識wchar_t * -arraysとしてストリング。しかし、例えばサーバーメソッドの文字列 "file"の内容は0x02546e80 "㤈榧"のようなものです。

エンコーディングは、マルチバイトエンコーディング(Visual Studio)に設定されているすべてのプロジェクト(クライアント/サーバー)用です。

EDIT2:

サーバはfollwedとして宣言されている:インタフェースの

class IShellServerx86 : public IUnknown { 
    public: 

    virtual HRESULT ShowFileInfo(BSTR file, BSTR* htmlFile, BSTR pathChar) = 0; 

}; 

実装:

//CoClass from Interface (Implementation) 
class CShellServerx86 : public IShellServerx86 { 
public: 
    CShellServerx86(); 
    virtual ~CShellServerx86(); 
    //inherited from IUnknown 
    ULONG STDMETHODCALLTYPE AddRef(void); 
    ULONG STDMETHODCALLTYPE Release(void); 
    HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, void** ppv); 

    HRESULT ShowFileInfo(BSTR file, BSTR* htmlFile, BSTR pathChar); 

protected: 
    ULONG m_uRefCount; 
}; 

...そしてクラスファクトリ クラスCShellServerx86ClassFactory:公共のIClassFactory { 公共: CShellServerx86ClassFactory()。 〜CShellServerx86ClassFactory();保護

//inherited methods from IUnknown 
ULONG STDMETHODCALLTYPE AddRef(void); 
ULONG STDMETHODCALLTYPE Release(void); 
HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, void** ppv); 

//inherited methods from IClassFactory 
HRESULT STDMETHODCALLTYPE CreateInstance(IUnknown *pUnkOuter, 
              REFIID riid, void** ppv); 
HRESULT STDMETHODCALLTYPE LockServer(BOOL fLock); 

: ULONG m_uRefCount。 };

のGetClass-方法DLLから:

STDAPI DllGetClassObject (REFCLSID rclsid, REFIID riid, void** ppv) { 
    if (!::InlineIsEqualGUID(rclsid, __uuidof(CShellServerx86))) { 
    return CLASS_E_CLASSNOTAVAILABLE; 
    } 
    *ppv = NULL; 
    CShellServerx86ClassFactory* pShellServerFac; 
    pShellServerFac = new CShellServerx86ClassFactory; 
    if (pShellServerFac == NULL) { 
    return E_OUTOFMEMORY; 
    } 
    pShellServerFac->AddRef(); 
    HRESULT hr = pShellServerFac->QueryInterface(riid, ppv); 
    pShellServerFac->Release(); 
    return hr; 

}

+1

BSTRには1つのエンコードutf16しかありません。 A2OLE()変換を間違えるようにする機会は十分に残されています。これは、デフォルトのコードページに非常に依存しています。エンコーディングの問題がどのように結論づけられたかを文書化して、質問を改善してください。 –

+0

この問題は、ShowFileInfo()実装の可能性が最も高いです。 'htmlFile'パラメータを割り当てるコードを表示してください。 – sharptooth

+0

私は、A2OLE/Multibyteのエンコーディングを完全に排除します。 'const char * file'は特にWindowsでは意味をなさない。パスはUTF-16です。 – MSalters

答えて

1

まずあなたがA2OLEは、あなたの場合には、それがSysAllocString()に適した入力のかどうか作り出すものを検査する必要があります。それが適切にパラメータの値を構築するための呼び出し先の責任です -

次に、あなたは//TODOことを実装する必要があります。あなたはこのような何かをする必要があります:

HRESULT CShellServerx86::ShowFileInfo(BSTR file, BSTR* htmlFile, BSTR pathBSTR) 
{ 
    if(htmlFile == 0) { 
     return E_POINTER; 
    } 
    // do useful stuff, generate the string for the htmlFile, then 
    *htmlFile = SysAllocString(TheStringForHtmlFileParameter); 
    return S_OK; 
} 

また、あなたは、呼び出し元でBSTR漏れしている:新しいBSTRが作成されますので、

BSTR htmlFileBstr = ::SysAllocString(A2OLE("")); 
//Call method of Server 
hr = pShellServer->ShowFileInfo(filebstr, &htmlFileBstr, pathBstr); 

は、2番目のパラメータとして渡されたBSTRを失うことになります被告人によって代わりに、単にNULLポインタにそれを初期化します。終わったらあなたはSysFreeString()を呼び出すことはありませんので、

BSTR htmlFileBstr = 0; 
//Call method of Server 
hr = pShellServer->ShowFileInfo(filebstr, &htmlFileBstr, pathBstr); 

はまた、あなたはとにかくすべてBSTR秒を漏らします。あなたが所有する各BSTRSysFreeString()を呼び出すか、より良いATL::CComBSTRまたは_bstr_tのようなラッパークラスを使用しますか。

+0

こんにちは、私はA2OLE-Macroを調べ、クライアント側のBSTR文字列が正しく初期化されています。あなたの提案(BSTR * htmlfile)のようなサーバーメソッドも変更しました。メソッド呼び出しとクライアント側からのパラメータは正しいです。しかし、サーバーがメソッドを開始しても、パラメーターは正しくありません。サーバーが返す文字列ポインタも誤ってマーシャリングされています。 HRESULTの戻り値のみが正しいです。私は本当に混乱していますか? – Tobias

+0

実装エラーを排除できるように、クラスファクトリ(EDIT2)の実装を追加しました。 – Tobias

+0

私は現在、クライアントがInterface ICallFactoryを検索し、E_INVALIDARGを返していることに気付きました。このインタフェースを実装する必要がありますか? – Tobias

関連する問題