Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/sharepoint/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
通过准隔离COM使用EXE服务器_Com_Registration Free Com - Fatal编程技术网

通过准隔离COM使用EXE服务器

通过准隔离COM使用EXE服务器,com,registration-free-com,Com,Registration Free Com,我已经能够使用清单,特别是MSBuild任务GenerateApplicationManifest,以便我们的主应用程序使用独立的COM。我可以创建在DLL中实现的所有COM对象,而无需在客户端计算机上注册DLL。但是,我很贪婪 我们的应用程序套件也有一些单独的应用程序,通常通过COM调用。对于这些,有人说你不能做EXE到EXE隔离COM。严格地说,这是真的,但我已经得到了90%的方式,在其他论坛上,我看到其他人提供线索,以获得剩余的方式 对于我的EXE服务器,我在清单中有一个带有EXE服务器名

我已经能够使用清单,特别是MSBuild任务GenerateApplicationManifest,以便我们的主应用程序使用独立的COM。我可以创建在DLL中实现的所有COM对象,而无需在客户端计算机上注册DLL。但是,我很贪婪

我们的应用程序套件也有一些单独的应用程序,通常通过COM调用。对于这些,有人说你不能做EXE到EXE隔离COM。严格地说,这是真的,但我已经得到了90%的方式,在其他论坛上,我看到其他人提供线索,以获得剩余的方式

对于我的EXE服务器,我在清单中有一个带有EXE服务器名称的条目,在该条目中有一个子条目,因此当ATL服务器调用
LoadRegTypeLib()
时,调用将成功。这很有效

当然,棘手的部分是,您不能将EXE服务器的条目放入客户端应用程序清单中,并期望
CoCreateInstance()
成功(通过启动服务器EXE并执行COM所做的所有其他操作)

因为我知道要启动什么EXE服务器,所以我可以假装很多。我可以调用
CreateProcess()
,然后在客户端应用程序中调用
WaitForInputidle()
,使我的服务器为客户端应用程序中的CoCreateInstance()做好准备

如果我调用
CoCreateInstance()
并在客户端应用程序中请求
IDispatch
接口,则调用成功,我可以调用
Invoke()
,一切正常

现在贪婪的部分来了

IDispatch可以正常工作,但我希望能够通过从IDispatch派生的双接口进行调用。我想这样做,因为我有很多这样编写的代码,语法更简单,异常处理已经存在

但是,当我在我的
IDispatch
接口上为双接口调用
QueryInterface()
时,我得到一个E_NOINTERFACE返回。我在服务器EXE中的ATL server对象中设置了断点,可以确认在服务器端,它找到接口并返回S_OK。因此,似乎不知何故接口无法封送回客户端

因此,问题是,我如何获得
QueryInterface()
以使我的自定义/双接口成功?我已经尝试了在我的客户端清单(和服务器清单)中使用
的各种组合来尝试和封送接口,但我仍然看到
E\u NOINTERFACE
在我的客户端中返回

几年前,我在另一个论坛上看到Hans Passant的评论,说可能需要一个单独的代理/存根DLL来封送接口,但没有太多细节


在无需注册的环境中,是否有可能解决这个问题?是否需要创建代理/存根库?如果是这样,在我的客户机应用程序(和/或服务器应用程序和/或代理/存根DLL)中,清单条目会是什么样子?

如果您有代理/存根DLL,请将其作为
文件
元素,并为其处理的每个接口包含一个子
comInterfaceProxyStub
元素(不要忘记
threadingModel
属性)

如果您有一个类型库,请将其作为一个
文件
元素包含在子
类型库
元素中,并为类型库中的每个接口添加一个
comInterfaceExternalProxyStub
元素(不要忘记
tlbid
属性),其中
proxyStubClsid32
是自动化封送器:
“{00020424-0000-0000-C000-0000000000 46}“

例如,如果使用标准封送(代理/存根DLL):


如果使用类型库封送处理:


实际上,
ComInterfaceExternalProxySub
适用于任何其他已注册(非隔离)的代理/存根。例如:


其中,在本例中,
{proxyStubClsid32}
是注册的代理/stubclsid


如果我的记性还不错的话,回到Windows XP仍然受支持的时候,我已经成功地尝试在代理/存根DLL中为接口使用
comInterfaceExternalProxyStub
,然后在代理/存根
文件
元素中声明相应的
comInterfaceProxyStub
,实际上不需要
comInterfaceProxyStub元素


然而,这不是一个好的实践,
ComInterfaceExternalProxySub
实际上应该只用于外部代理/存根,正如文档所述,在激活所需的代理/存根时,COM基础结构似乎不允许在孤立的CLSID中查找。

嗯,我最终能够到达那里

诀窍是在我的客户端EXE中,在
条目下有一个
,在服务器EXE中,在
条目下有一个

总之,我有两个exe和一个代理存根DLL:MFCDialog.exe(客户端)、ExeServer2.exe(服务器)和ExeServer2PS.DLL(代理存根DLL).ExeServer2最初是一个ATL向导生成的带有代理/存根的EXE服务器。代理/存根DLL有点神秘。我根本没有接触过它。它没有唯一的源文件,只有一些由ExeServer2(EXE服务器项目)的MIDL编译生成的文件

调整ExeServer2.exe和MFCDialog.exe的清单文件后,我可以在手动启动服务器后封送接口

MFCDialog.exe.manifest的重要部分:

<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
   <file name="ExeServer2PS.dll">
      <comInterfaceProxyStub iid="{2985957C-3067-4361-A010-23735F13E4B9}" name="IMyServer2" numMethods="8" baseInterface="{00020400-0000-0000-C000-000000000046}" proxyStubClsid32="{2985957C-3067-4361-A010-23735F13E4B9}" threadingModel="Both"/>
   </file>
<!-- unimportant stuff like DPI, UAC, ComCtrl32 removed-->
</assembly>
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
   <file name="ExeServer2.exe">
      <typelib tlbid="{50142018-B402-4FDE-B085-67ABCC128526}" version="1.0" helpdir=""/>
   </file>
   <comInterfaceExternalProxyStub name="IMyServer2" iid="{2985957C-3067-4361-A010-23735F13E4B9}" tlbid="{50142018-B402-4FDE-B085-67ABCC128526}" proxyStubClsid32="{00020424-0000-0000-C000-000000000046}"/>
</assembly>
下面是对测试代码的按钮单击的响应:

void CMFCDialogDlg::OnExeServer2()
{
   CLSID clsid;
   HRESULT hr = CLSIDFromProgID(L"ExeServer2.MyServer2", &clsid);
   if (FAILED(hr))
   {
      _com_error err(hr);
      OutputDebugString(err.ErrorMessage());
   }

   CComDispatchDriver lpDisp;
   hr = lpDisp.CoCreateInstance(__uuidof(ExeServer2Lib::MyServer2));

   if (hr == REGDB_E_CLASSNOTREG)
   {
      SpinUpExe(_T("ExeServer2.exe"));
      hr = lpDisp.CoCreateInstance(__uuidof(ExeServer2Lib::MyServer2));
   }

   if (FAILED(hr))
   {
      _com_error err(hr);
      AfxMessageBox(err.ErrorMessage());
   }
   else 
   {
      ExeServer2Lib::IMyServer2Ptr lpServer;
      try
      {
         lpServer = lpDisp.p;
      }
      catch (_com_error e)
      {
         AfxMessageBox(e.ErrorMessage());
      }

      if (lpServer)
      {
         _bstr_t bstrtName = lpServer->Name;

         CString strMsg = CString(_T("From IMyServer: ")) + (LPCTSTR)bstrtName;
         AfxMessageBox(strMsg);
      }
      else
      {
         _variant_t vRet;
         hr = lpDisp.GetPropertyByName(L"Name", &vRet);
         if (FAILED(hr))
         {
            _com_error err(hr);
            AfxMessageBox(err.ErrorMessage());
         }
         else
         {
            CString strMsg = CString(_T("From IDispatch: ")) + (LPCWSTR)vRet.pbstrVal;
            AfxMessageBox(strMsg);
         }
      }
   }
}

对于我的简单测试应用程序,我只有一个具有单个双接口的对象。在您的示例中,您有带(In)和(In)的元素。我需要每个条目中的一个吗?我使用ATL生成带有PS DLL的EXE,有趣的是,代理存根(通过检查注册表找到)的CLSID是
void CMFCDialogDlg::OnExeServer2()
{
   CLSID clsid;
   HRESULT hr = CLSIDFromProgID(L"ExeServer2.MyServer2", &clsid);
   if (FAILED(hr))
   {
      _com_error err(hr);
      OutputDebugString(err.ErrorMessage());
   }

   CComDispatchDriver lpDisp;
   hr = lpDisp.CoCreateInstance(__uuidof(ExeServer2Lib::MyServer2));

   if (hr == REGDB_E_CLASSNOTREG)
   {
      SpinUpExe(_T("ExeServer2.exe"));
      hr = lpDisp.CoCreateInstance(__uuidof(ExeServer2Lib::MyServer2));
   }

   if (FAILED(hr))
   {
      _com_error err(hr);
      AfxMessageBox(err.ErrorMessage());
   }
   else 
   {
      ExeServer2Lib::IMyServer2Ptr lpServer;
      try
      {
         lpServer = lpDisp.p;
      }
      catch (_com_error e)
      {
         AfxMessageBox(e.ErrorMessage());
      }

      if (lpServer)
      {
         _bstr_t bstrtName = lpServer->Name;

         CString strMsg = CString(_T("From IMyServer: ")) + (LPCTSTR)bstrtName;
         AfxMessageBox(strMsg);
      }
      else
      {
         _variant_t vRet;
         hr = lpDisp.GetPropertyByName(L"Name", &vRet);
         if (FAILED(hr))
         {
            _com_error err(hr);
            AfxMessageBox(err.ErrorMessage());
         }
         else
         {
            CString strMsg = CString(_T("From IDispatch: ")) + (LPCWSTR)vRet.pbstrVal;
            AfxMessageBox(strMsg);
         }
      }
   }
}