繁体   English   中英

通过可执行的免注册方式使用COM对象

[英]Using a COM object from an executable registration-free way

我正在努力尝试修改使用COM对象实例进行通信的现有程序集。

COM服务器实际上是主应用程序的(可选)扩展名。 两者都通过简单副本部署到目标系统。

当前,这两个应用程序仅在本地部署到我们的办公室(尽管主要应用程序COM客户端在我们的客户中部署得更广泛),并且我们手动注册服务器。 我们需要针对云服务上的部署进行重新设计,因此,我正在研究免注册COM。

到目前为止,我已经尝试过:

  • 为客户端和服务器编写清单。 不幸的是,我们无法部署此解决方案,因为客户端随后与服务器应用程序紧密链接,并且无法单独部署(我们的客户就是这种情况)。
  • 创建一个新的激活上下文并从资源中读取服务器的清单。 这是可行的,但尝试实例化对象会导致“ Error in the Dll ” OLE异常。 一些谷歌搜索告诉我这是因为缺少DllgetClassObject导出。
  • 从可执行文件中导出DllGetClassObject (使用System.Win.ComServ的内置实现将export子句添加到项目源中。这在调用时(直接或通过激活上下文)会导致访问冲突。无法确定AV发生的位置。

这是我使用的清单(我以注释形式在代码中留下了各种尝试):

服务器应用程序清单

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
<assemblyIdentity
name="wgaticket.exe"
type="Win32"
version="1.0.0.0"
/>

<file name = "wgaticket.exe">

<comClass
    clsid="{E33A1F59-CEA2-463E-97B2-1CCDA66DA984}"
    />
<!-- comClass
    clsid="{E33A1F59-CEA2-463E-97B2-1CCDA66DA984}"
    threadingModel = "Apartment"
    /-->

<typelib tlbid="{414AE7FB-3025-40D8-B14C-2A29B6E42C29}"
       version="1.0" helpdir=""/>

</file>

<!--comInterfaceExternalProxyStub
    name="INewTicket"
    iid="{740BF585-3246-483E-9146-B6A8E49400B5}"
    proxyStubClsid32="{00020424-0000-0000-C000-000000000046}"
    baseInterface="{00000000-0000-0000-C000-000000000046}"
    tlbid = "{414AE7FB-3025-40D8-B14C-2A29B6E42C29}" /-->

  <dependency>
    <dependentAssembly>
      <assemblyIdentity
        type="win32"
        name="Microsoft.Windows.Common-Controls"
        version="6.0.0.0"
        publicKeyToken="6595b64144ccf1df"
        language="*"
        processorArchitecture="*"/>
    </dependentAssembly>
  </dependency>
  <trustInfo xmlns="urn:schemas-microsoft-com:asm.v3">
    <security>
      <requestedPrivileges>
        <requestedExecutionLevel
          level="asInvoker"
          uiAccess="false"/>
        </requestedPrivileges>
    </security>
  </trustInfo>
</assembly>

客户端代码稍微复杂一点,因为我使用的是Spring4D框架,但这是主要元素:

客户端激活上下文创建

function getActivationContext: IActivationContext;
var
  actCtx: TActCtx;
begin
  result := TActivationContext.Create;
  zeroMemory(@actCtx, SizeOf(actCtx));
  actCtx.cbSize := SizeOf(actCtx);
  actCtx.lpSource := 'wgaticket.exe';

  actCtx.lpResourceName := MakeIntResource(1);
  actCtx.lpAssemblyDirectory := PChar(ModulePath);
  actCtx.dwFlags := ACTCTX_FLAG_ASSEMBLY_DIRECTORY_VALID or ACTCTX_FLAG_RESOURCE_NAME_VALID;
  result.Handle := CreateActCtx(actCtx);
  if result.Handle = INVALID_HANDLE_VALUE then
  begin
    RaiseLastOSError;
  end;
  result.Cookie := 0;
end;

客户端激活上下文激活

procedure TActivationContext.Activate;
begin
  CriticalSection.Enter;
  try
    if (FHandle <> INVALID_HANDLE_VALUE) and (Cookie = 0) then
    begin
      if not ActivateActCtx(FHandle, FCookie) then
        RaiseLastOSError;
    end;
  finally
    CriticalSection.Leave;
  end;

end;

在客户端中创建新实例

class function CoNewTicket.CreateAsClient: INewTicket;
begin
  // GActContext is a global, lazy interface variable. It will be auto-created the first time GActContext.Value is referenced
  GActContext.Value.Activate;
  result := CreateComObject(CLASS_NewTicket) as INewTicket;
end;

您可以创建COM扩展的“虚拟”版本,该版本具有与真实扩展相同的公共接口,但没有真实功能。 在该界面上添加一个属性,您可以检查该属性是否为真实属性。 始终部署假人。 必要时,用真实的扩展名替换虚拟对象。

这似乎会使您的部署策略与运行时如何建立激活上下文脱钩。 也就是说,一个固定的清单文件(或嵌入的资源,无论哪个)将始终有效。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM