Out-Of-Proc-COM-сервер: BSTR неправильно распределяется - PullRequest
0 голосов
/ 08 августа 2011

Я разработал Out-Of-Proc-COM-сервер на C ++ с Visual Studio 2010, чтобы избежать 64-битных и 32-битных проблем в расширениях Shellextensions (http://blog.mattmags.com/2007/06/30/accessing-32-bit-dlls-from-64-bit-code/).

Я описал интерфейсы как здесь (http://msdn.microsoft.com/en-us/library/ms686605%28v=VS.85%29.aspx) в IDL-файле: </p> <pre><code>import "unknwn.idl"; [ object, uuid("xx"), helpstring("IShellServerx86-Interface") ] interface IShellServerx86 : IUnknown { HRESULT ShowFileInfo([in]BSTR file, [out]BSTR* htmlFile, [in]BSTR pathChar); };

Этот файл генерирует мне Proxy / Stub-DLL, которую я также зарегистрировал, чтобы использовать стандартные методы Marshaller. Если я позвоню сейчас

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 параметры недопустимы, так как выбрана неправильная кодировка. Я пытался для всего проекта установить «Юникод», но ничего не изменилось.

Я забыл какие-либо настройки или мне нужно попробовать другие типы данных для сортировки?

Заранее спасибо за помощь.

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 «㤈 榧».

Кодировка для всех проектов (клиент / сервер) установлена ​​на Multibyte-Encoding (Visual Studio).

EDIT2:

Сервер объявлен следующим образом:

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: public 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 Ответ

1 голос
/ 09 августа 2011

Сначала вы должны проверить, что 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 htmlFileBstr = ::SysAllocString(A2OLE(""));
//Call method of Server
hr = pShellServer->ShowFileInfo(filebstr, &htmlFileBstr, pathBstr);

потеряет BSTR, переданный как второйпараметр, так как вызываемый будет создавать новый BSTR.Вместо этого просто инициализируйте его нулевым указателем:

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

Кроме того, вы все равно пропускаете все BSTR с, так как вы не вызываете SysFreeString(), когда закончите.Либо звоните SysFreeString() на каждый BSTR, который у вас есть, либо лучше используйте класс-оболочку, например ATL::CComBSTR или _bstr_t.

...