服务端程序很简单,写了一个组件和一个对应的类厂,然后在main()函数里,调用CoRegisterClassObject登记类产后,就进入消息循环,没有任何写注册表的代码,没有IDL,没有TLB。客户端程序也就是调用CoCreateInstance(),调试发现,QueryInterface IID_IUnknown和IID_MyObj都可以进入服务器程序,QueryInterface IID_IUnknown成功,但QueryInterface IID_MyObj就返回E_NOINTERFACE。是不是没有在注册表里注册组件信息?
高手帮忙!

解决方案 »

  1.   

    1.no implement Classfactory?
    2.No implement interface IID_MyObj?
    3.no implement QueryInterface?
    ...
    ...
      

  2.   

    如果你没用到MFC和ATL,那么QueryInterface()就完全是由你自己实现的啊。E_NOINTERFACE也是你自己返回的。
      

  3.   

    源代码:
    #include "windows.h"static const GUID IID_IHelloSvr = { 0xaae4361a, 0xae2d, 0x4a72, { 0xbe, 0x5f, 0x35, 0x8d, 0xe7, 0x6d, 0x5a, 0x8f } };
    static const GUID CLSID_HelloSvr = { 0xca0f0f8, 0xbeda, 0x4a67, { 0x80, 0x5c, 0xa9, 0x10, 0x1b, 0x8c, 0x10, 0x5d } };void BSTRCopy(BSTR dest, BSTR src)
    {
    wchar_t ch = *src++;
    while(ch != NULL){
    *dest++ = ch;
    ch = *src++;
    }
    *dest = 0;
    }struct IHelloSvr: public IUnknown
    {
    STDMETHOD(SayHello)(BSTR Name, BSTR* pVal) = 0;
    };class CHelloSvr: public IHelloSvr
    {
    public:
    STDMETHOD(QueryInterface)(const GUID& riid, void ** ppvObject)

    if(riid==IID_IHelloSvr || riid==IID_IUnknown)
    *ppvObject = static_cast<IHelloSvr *>(this);
    else {*ppvObject = NULL; return E_NOINTERFACE; }
    AddRef();
    return NOERROR;
    }
    virtual ULONG __stdcall AddRef(){ return ++m_cRef; }
    virtual ULONG __stdcall Release()

    if(--m_cRef == 0)delete this;
    return m_cRef;
    }
    STDMETHOD(SayHello)(BSTR Name, BSTR* pVal)
    {
    BSTR s = new wchar_t[SysStringLen(L"Hello ") + SysStringLen(Name) + 1];
    BSTRCopy(s, L"Hello ");
    BSTRCopy(s+6, Name);
    *pVal = SysAllocString(s);
    delete s;
    return S_OK;
    }
    CHelloSvr(): m_cRef(3){} 
    ULONG m_cRef;
    };class CClassFactory: public IClassFactory
    {
    public:
    ULONG m_cRef;
    STDMETHOD(QueryInterface)(const GUID& riid, void ** ppvObject){ 
    if(riid==IID_IClassFactory || riid==IID_IUnknown){
    *ppvObject = static_cast<IClassFactory *>(this);
    AddRef();
    return S_OK;
    }
    else return E_NOINTERFACE; 
    }
    virtual ULONG __stdcall AddRef(){ return ++m_cRef; }
    virtual ULONG __stdcall Release()

    if(--m_cRef == 0)delete this;
    return m_cRef;
    }
    STDMETHOD(CreateInstance)(IUnknown* punkOuter, const GUID& riid, void ** ppv)
    {
        if(punkOuter != NULL) return CLASS_E_NOAGGREGATION; 
    if(riid==IID_IHelloSvr || riid==IID_IUnknown){
    CHelloSvr* pSvr= new CHelloSvr();
    HRESULT hr = pSvr->QueryInterface(riid, ppv);
    if(SUCCEEDED(hr)) pSvr->Release();
    else delete pSvr;
    return hr;
    }
    else return E_NOINTERFACE;
    }
    STDMETHOD(LockServer)(BOOL fLock){ return E_NOTIMPL; }//不需要支持
    CClassFactory(): m_cRef(1){} 
    };void main(int argc, char* argv[])
    {
    MSG msg;
    CoInitialize(NULL);
    CClassFactory ClassFactory;
    DWORD dwRegister = 0; 
    CoRegisterClassObject(CLSID_HelloSvr, (IUnknown *)&ClassFactory, CLSCTX_LOCAL_SERVER, REGCLS_MULTIPLEUSE, &dwRegister); 
    while(GetMessage(&msg, 0, 0, 0) > 0){
    TranslateMessage(&msg);
    DispatchMessage(&msg);
    }
    }
    大家看看什么问题?
      

  4.   

    QueryInterface()应该没有问题,我没有找到完全的怎么写EXE COM的资料,担心有一些该做的事情没有做,比如注册组件类
      

  5.   

    你说QueryInterface IID_IUnknown可以,但是IID_IHelloSvr不行?
      

  6.   

    1.你写了一个进程外服务器,但是程序运行时没有在注册表中注册;
    2。 
    struct IHelloSvr: public IUnknown
    ~~~~~~interface
    {
    STDMETHOD(SayHello)(BSTR Name, BSTR* pVal) = 0;
    };3.建议使用idl
      

  7.   

    easyrock() 是的,我在客户端曾经这样尝试过:
    CoCreateInstance(CLSID_HelloSvr, ..., ..., IID_Unknown, (void**)&pUnk);
    pUnk有内容,但是:pUnk->QueryInterface(IID_HelloSvr, (void**)&pSvr)就返回E_NOINTERFACE的错误。
      

  8.   

    调试服务器时发现,QueryInterface(IID_Unknown)被调用了两次,QueryInterface(IID_IHelloSvr)只被调用了一次。
      

  9.   

    我始终觉得这一切都在你的控制下。在你的QueryInterface()中设置断点,就能知道是怎么回事。
      

  10.   

    我跟进去,发现后来就进入asm状态了,也看不出什么花样,只是发现,QueryInterface(IID_Unknown)被调用了两次,QueryInterface(IID_IHelloSvr)只被调用了一次。
      

  11.   

    用ATL生成的最简单的EXE服务器代码比较一下,然后试一试!
      

  12.   

    尝试过调试相同功能的ATL代码,除了它有一些检查注册表的程序外,没有发现什么特别的。
      

  13.   

    如果你建立DEBUG版调试,肯定是源代码极的。这里的调试对象是你的服务器,而不是客户程序。
      

  14.   

    easyrock() ,函数运行完了,自然进入系统代码,系统代码没有源代码。
      

  15.   

    问题解决了,编译一个proxy/stub的DLL就可以了。
      

  16.   

    proxy/stub怎么编写?能否给个简单的事例?
      

  17.   

    (1)写DEF文件:
    LIBRARY         HelloSvrCon.dll
    DESCRIPTION     'Proxy/Stub DLL'EXPORTS
                    DllGetClassObject   @1 PRIVATE
                    DllCanUnloadNow     @2 PRIVATE
                    GetProxyDllInfo     @3  PRIVATE
                    DllRegisterServer   @4 PRIVATE
                    DllUnregisterServer @5 PRIVATE(2)写IDL文件
    import "unknwn.idl" ; [
    object,
    uuid(AAE4361A-AE2D-4A72-BE5F-358DE76D5A8F),
    dual,
    nonextensible,
    helpstring("IHelloSvr Interface"),
    pointer_default(unique)
    ]
    interface IHelloSvr : IUnknown
    {
    [id(1), helpstring("method Hello")] HRESULT SayHello([in] BSTR Name, [out,retval] BSTR* pVal);
    };[
    uuid(9005A3DE-F527-411B-ACC0-058792F3CEF7),
    version(1.0),
    helpstring("HelloSvrCon 1.0 Type Library")
    ]
    library HelloSvrLib
    {
    importlib("stdole2.tlb");
    [
    uuid(0CA0F0F8-BEDA-4A67-805C-A9101B8C105D),
    helpstring("HelloSvr Class")
    ]
    coclass HelloSvr
    {
    [default] interface IHelloSvr;
    };
    };
    (3)编译:midl HelloSvrCon.idl
    cl /c /DWIN32 /Ox /D_WIN32_WINNT=0x0400 /DREGISTER_PROXY_DLL HelloSvrCon_i.c
    cl /c /DWIN32 /Ox /D_WIN32_WINNT=0x0400 /DREGISTER_PROXY_DLL HelloSvrCon_p.c
    cl /c /DWIN32 /Ox /D_WIN32_WINNT=0x0400 /DREGISTER_PROXY_DLL dlldata.c
    link /dll /out:HelloSvrCon.dll /def:HelloSvrCon.def HelloSvrCon_i.obj HelloSvrCon_p.obj dlldata.obj kernel32.lib rpcndr.lib rpcns4.lib rpcrt4.lib oleaut32.lib uuid.lib 
    regsvr32 HelloSvrCon.dll