簡體   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