COM-Out-Of-Proc mit DLL Surrogate



  • Hallo,

    ich versuche, für eine Shell-Extension einen COM-Server zu schreiben, damit auch unter einem 64-Bit-Windows der 32-Bit-Code ausgeführt werden kann (http://blog.mattmags.com/2007/06/30/accessing-32-bit-dlls-from-64-bit-code/).

    Ich habe den COM-Server von IUnknown so abgeleitet:

    class IShellServerx86 : public IUnknown {
    public:
    
       virtual HRESULT ShowFileInfo(BSTR file, BSTR* htmlFile, BSTR path) = 0;
    
    };
    

    Die dazugehörige Implementation ist so definiert:

    class CShellServerx86 : public IShellServerx86 {
    public:
       CShellServerx86();
       virtual ~CShellServerx86();
       //geerbte Methoden von IUnknown
       ULONG STDMETHODCALLTYPE AddRef(void);
       ULONG STDMETHODCALLTYPE Release(void);
       HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, void** ppv);
    
       HRESULT ShowFileInfo(BSTR file, BSTR* htmlFile, BSTR path);
    
    protected:
       ULONG m_uRefCount;
    };
    

    Die dazugehörige IClass-Factory habe ich ebenfalls deklariert:

    class CShellServerx86ClassFactory : public IClassFactory {
    public:
       CShellServerx86ClassFactory();
       ~CShellServerx86ClassFactory();
    
       //geerbte Methoden von IUnknown
       ULONG STDMETHODCALLTYPE AddRef(void);
       ULONG STDMETHODCALLTYPE Release(void);
       HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, void** ppv);
    
       //geerbte Methoden von IClassFactory
       HRESULT STDMETHODCALLTYPE CreateInstance(IUnknown *pUnkOuter, REFIID riid, void** ppv);
       HRESULT STDMETHODCALLTYPE LockServer(BOOL fLock);
    protected:
       ULONG m_uRefCount;
    };
    

    Die dazugehörige IDL-Datei, die mir die Proxy-/Stub-DLL erzeugt fürs Standard-Marshalling, habe ich so deklariert:

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

    Wenn ich den Server starte, nachdem COM-DLL und Proxy/Stub-DLL registriert sind, wird er soweit korrekt initialisiert und mit Hilfe der dllhost.exe gestartet:

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

    Der Aufruf ist im Client so deklariert und die BSTRs werden nach dem Debugger auch korrekt initialisiert:

    //Interface des Servers aufrufen
    wchar_t* fileW = A2OLE(file);
       BSTR filebstr = ::SysAllocString(fileW);
       wchar_t* pathW = A2OLE("c:\datei.txt");
       BSTR pathbstr = ::SysAllocString(pathW);
       BSTR htmlbstr = NULL;
       hr = pShellServer->ShowFileInfo(filebstr, &htmlbstr, pathbstr);
    

    Auf der Server-Seite wird die Methode auch zunächst korrekt gestartet:

    HRESULT CShellServerx86::ShowFileInfo(BSTR file, BSTR* htmlFile, BSTR path) {
    
       if (htmlFile == NULL) {
          return E_POINTER;
       }
       *htmlFile = ::SysAllocString(L"bla");
    }
    

    Allerdings sind die Parameter auf der Serverseite ungültig und sehen aus, als ob die falsche Codierung gewählt wurde oder sind uninitialisiert. Dabei habe ich für alle Projekte in VS 2010 Multibyte-Codierung festgelegt.
    Meine erste Annahme war, dass die Pfade zu den DLLs falsch sind. Die Struktur in der Registry sieht momentan so aus:

    HKCR\CLSID\{__uuidof(CShellServerx86)}\
       AppID={__uuidof(CShellServerx86)}
    HKCR\CLSID\{__uuidof(CShellServerx86)}\InProcServer32\
        Standard=<Pfad zur COM-Server-DLL>
        ThreadingModel=Apartment
    HKLM\SOFTWARE\Classes\{__uuidof(CShellServerx86)}
        DllSurrogate=""
    

    Muss im Pfad von "InProcServer32" die COM-DLL oder die Proxy/Stub-DLL stehen?
    Oder reicht das Standard-Marshalling der Proxy/Stub-DLL nicht aus, um die Daten korrekt zu übertragen?
    Gibt es eine Möglichkeit, die Proxy/Stub-DLL zu debuggen?

    Vielen Dank schon mal für die Hilfe.

    Gruß,

    Tobias


  • Mod

    Wie benutzt Du den die BSTR?

    Eigentlich ist ein BSTR von der Unicode/Multibyte EInstellung unabhängig. BSTR sind immer Unicode Strings, die in einem eigenen Heap abgelegt werden.
    Castest Du die BSTR evtl. direkt?



  • Die BSTR caste ich von char* mit Hilfe der ATL-Makros:

    char* file = "Datei";
    wchar_t* fileW = A2OLE(file);
    BSTR filebstr = ::SysAllocString(fileW);
    wchar_t* pathW = A2OLE("c:\datei.txt");
    BSTR pathbstr = ::SysAllocString(pathW);
    BSTR htmlbstr = NULL;
    hr = pShellServer->ShowFileInfo(filebstr, &htmlbstr, pathbstr);
    

    Auf der Client-Seite sind die BSTRs soweit korrekt erstellt und im Debugger auch lesbar. Die Größenangabe im Header stimmt ebenfalls. Nur nach dem Marshalling im Aufruf der Server-Methode haben die Pointer ungültige und nicht lesbare Werte und scheinen teilweise nicht initialisiert.


  • Mod

    Ich meinte die Serverseite, denn dort hast Du ja die Probleme, oder?



  • Hallo,

    auf der Serverseite habe ich es auf folgende Minimal-Methode eingegrenzt:

    HRESULT CShellServerx86::ShowFileInfo(BSTR file, BSTR* htmlFile, BSTR pathBSTR)
    {
        if( htmlFile == 0 ) {
           return E_POINTER;
        }
        *htmlFile = SysAllocString( L"" );
        return S_OK;
    }
    

    Die BSTR sind bereits beim Einspringen in die Methode nicht lesbar, also bevor ich irgendwas mit ihnen anstelle.


Anmelden zum Antworten