DCOM组件应该不是在远程机器上注册完就可以了,还应该在本机进行DCOM设置,这样客户程序才知道应该到哪台机器上去启动服务。通过你的描述,我想可能是你没有做DCOM配置这一步,所以远程启动失败。我没有直接调用过Invoke函数,因为一看函数原型就头大了。强烈推荐你用#import导入组件,这样调用就方便多了。

解决方案 »

  1.   

    luxyi:
       您好!我在论坛上已经见到你多次了,谢谢你的热心。
       不过您似乎对Dcom了解的不多,有两种方式调用Dcom 组件:一是不需改程序代码只需配置注册表(通过dcomcnfg.exe或OLE View工具),另一种是使用CoCreatInstanceEx(),因为有关远程机器的信息在这个函数的参数中。而后者不需要客户端配置信息,所以更加灵活。
       另外,#import导入方式是实现远程自动化的方法,用远程自动化要在服务器端和客户端配置许多信息,远程自动化和Dcom 是两种不同的方式。
      

  2.   

    惭愧,我的确不了解DCOM,只是根据学COM时候理解来回答的。我刚查过了MSDN,你的CoCreateInstanceEx应该没有问题,是不是机器名不能解析?换成IP地址试试?此外,我看不明白你对#import的论述,我们是不是说的同一个#import?我指的是预编译命令。
      

  3.   

    luxyi:
        我已经用ip地址试过了,情况一样。而且如果机器名不能解析,返回的错误码应为:0x800706BA(RPC 服务器无法使用)。
        您说的#import是编写自动化控制器常用的方式,而对于自动化控制器使用远程的自动化服务器,微软提供了远程自动化技术,而在Dcom中是无法用这种方式的。(我何尝不想避开Invoke函数,可是同志,不行啊!)
      

  4.   

    对于第一个问题,是VARIANTARG param ={1};这句话写错了。VARIANT不能这样被初始化。你应该这样初始化:
    VARIANT param;
    VariantInit(&param);
    param.vt = VT_I2; // short类型
    param.iVal = 5;
    最后别忘了VariantClear(&param);对于第二个问题,我做了个小例子,不过现在在远程创建的时候得到0x80070005,访问被拒绝!
      

  5.   

    我希望这是最终的答案:对于DCOM,应该在本机注册一个这个服务的proxy(且这个proxy是个DLL),根据《Inside COM》,这个DLL应该由*.h, *_p.c, *_i.c, dlldata.c, *.def和一个makefile(*.mk)编译而成。如果是用ATL来做这个EXE组件的话,这些文件在编译后编译器都会帮你生成,你只要运行命令行nmake *.mk即可得到proxy DLL,或在集成环境的project setting中的post-build step页添加这一命令行,这样在工程编译完后就有那个DLL了。然后注册这个DLL在本机,注册那个EXE在远程机器上,即可调用,我的例子这样做已经成功了。不过,对于用MFC编写的EXE服务器,我就不知道有没有那些帮助生成proxy的文件了。
      

  6.   

    谢谢luxyi,第一个问题您的解释是对的,我已经成功的实现了方法的调用。但是当参数是字符型时需要设置EXCEPINFO型的参数,可调试后返回的错误号为3,程序如下,不知错在什么地方?
       VARIANT var;
       var.vt = VT_BOOL;
       var.boolVal = TRUE;
       VARIANTARG param[4];
       short i;
       for (i = 0 ; i <= 3 ; i++)
            VariantInit(&param[i]);
       param[0].vt = VT_I4; // long类型
       param[1].vt = VT_I4; // long类型
       param[2].vt = VT_BSTR; // BSTR类型
       param[3].vt = VT_BSTR; // BSTR类型
       param[0].lVal = 11;
       param[1].lVal = 1;
       BSTR bstrVal = SysAllocString(L"hhhhh");
       param[2].bstrVal = bstrVal;
       param[3].bstrVal = bstrVal;
       EXCEPINFO exc;
       exc.wCode = 1001;
       exc.wReserved = 0;
       exc.bstrSource = SysAllocString(L"hhhhh");
       exc.bstrDescription = NULL;
       exc.bstrHelpFile = NULL;
       exc.dwHelpContext = NULL;
       exc.pvReserved = NULL;
       exc.pfnDeferredFillIn = NULL;
       exc.scode = 0;
       DISPPARAMS di = {&param[0],NULL,4,0};
       UINT err;
       m_ps->Invoke  
             (3,IID_NULL,LOCALE_SYSTEM_DEFAULT,DISPATCH_METHOD,&di,&var,&exc,&err);
       for (i = 0 ; i <= 3 ; i++)
            VariantClear(&param[i]);
       SysFreeString(bstrVal);此外,我在一台远程机器上运行了EXE组件(带/EMBEDDING参数),在客户端(并没有注册一个这个服务的proxy)创建远程对象成功。可是调用方法失败,不知何故。而且在另一台机器上远程同样运行了EXE组件,在客户端却不能成功创建远程对象,不知又是何故。
      

  7.   

    对于第二个问题,对于DCOM的内部操作我只有模糊的概念,现在还说不清楚,不过,你还是先做一个proxy,然后看看问题解决了没有。我觉得做proxy才是正道。
      

  8.   

    luxyi:
       我查了书,你说的是关于标准Marshaling的内容。等我把相关的细节了解清楚再和你讨论。
    和你讨论问题感到十分愉快。
      

  9.   

    COM/DCOM调用没这么复杂吧.
    new Atl Progject. test
    new interface love
    F7
    copy test.h test_i.c to your client;
    Add in stdafx.h
     #include "test.h"
    add in your call.cpp
    #include "love_i.cClassNamae::OnTest()
    {
      ILove *pLove;
      hr = ::CoCreateInstanceEx(..)
      pLove = (ILove *)mqi.pItf;
      pLove->YourMethod(...)
    }
            
      

  10.   

    copy test.h love_i.c to your client;
    Add Love Method.
    Login([in] BSTR* lpszUser,[in] BSTR* lpszPass)client:
    WCHAR* user[1];
    WCHAR* pass[1];
    user[0]= SysAllocString("user");
    pass[0]= SysALlocString("pass");
    pLove->Login(user,pass)
    SysFreeString(user[0]);
    SysFreeString(pass[0]);
      

  11.   

    在本地机器上调用远程的COM服务器可以成功,就是用COCREATEINSTANCEEX(如果不注册PROXY/STUB),但拿不到接口。。
      

  12.   

    书上讲还需要Marshaling,而且有三种方式,我采用了类库方式。在DCOM程序的应用类的InitInstance()函数中添加了如下代码:
           ITypeLib *pTLB;
           HRESULT hr = S_FALSE;
           char szFileName[MAX_PATH]; 
           OLECHAR wszFileName[MAX_PATH];
           GetModuleFileName(AfxGetApp()->m_hInstance, szFileName, MAX_PATH);
           int i,j;
           for(i = 0 ; i < MAX_PATH ; i++)    
              {
                 if (szFileName[i] == 0)
                    break;
    }
           szFileName[i-3] = 't';
           szFileName[i-2] = 'l';
           szFileName[i-1] = 'b';
           mbstowcs(wszFileName, szFileName, MAX_PATH);
           hr=LoadTypeLib(wszFileName,&pTLB);
           if(FAILED(hr))
               return hr;
           hr=RegisterTypeLib(pTLB,wszFileName,NULL);
           pTLB->Release(); 
    (类库文件和运行的程序文件放在同一目录下)
    当运行时会把类型库的有关信息注册到注册表中。然后,在客户端和远程都运行了程序,并在注册表中也看到了有关的信息(HKEY_CALSSES_RO
    OT\TypeLib\{my-typelibs-guid}\)
    可是运行客户端程序还是报“服务器运行失败”。
      

  13.   

    luxyi:
      我成功了,原来是DCOMCNFG配置不对。
    在这个程序中并不需要自己做proxy,我想可能系统使用了缺省的proxy吧。