2011-08-08 4 views
0

Shellextensions에서 64 비트 대 32 비트 문제를 피하기 위해 Visual Studio 2010과 함께 C++에서 Out-Of-Proc-COM 서버를 개발했습니다. (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); 
}; 

이 파일은 나에게 나는 또한 표준 Marshaller의 방법을 사용하도록 등록 프록시/스텁 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 :

클라이언트 구현은 : 서버 클라이언트 방식에서는

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

디버거 BSTR 인식을 :

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; 
} 

서버 방식은 다음과 같이 선언 wchar_t * -arrays로 스트링. 그러나 서버 메서드에서 문자열 "file"에 대한 예를 들면 다음과 같습니다. 0x02546e80 "㤈 榧".

인코딩은 Multibyte-Encoding (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 : public IClassFactory { public : 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에는 인코딩이 하나만 있습니다 (utf16). A2OLE() 변환을 잘못 수행 할 수있는 많은 기회를 남겨 둡니다.이 코드는 기본 코드 페이지에 크게 의존합니다. 인코딩 문제가 있다고 결론을 내림으로써 문제를 개선하십시오. –

+0

문제는 ShowFileInfo() 구현에서 발생할 가능성이 큽니다. 'htmlFile' 매개 변수를 할당하는 코드를 보여 주시겠습니까? – sharptooth

+0

나는 A2OLE/Multibyte 인코딩 물건을 모두 제거하고 싶습니다. 'const char * file'은 특히 Windows에서는 이해가되지 않습니다; 경로는 UTF-16입니다. – MSalters

답변

1

먼저 당신이 A2OLE이 귀하의 경우 생산 무엇을 검사해야하고 그 여부를 SysAllocString()에 적합한 입력합니다.

그러면 //TODO을 구현해야합니다. out 매개 변수의 값을 올바르게 작성하려면 호출 수신자의 책임입니다. 새로운 BSTR이 생성되기 때문에

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

두 번째 매개 변수로 전달 된 BSTR을 잃게됩니다 : 또한

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을 누출하고 있습니다 : 당신이 뭔가를해야 할 것이다 피 호출자. 대신 널 포인터로 초기화 : 할 때 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

현재 클라이언트가 ICallFactory 인터페이스를 검색하고 E_INVALIDARG를 반환합니다. 이 인터페이스를 구현해야합니까? – Tobias

관련 문제