如何将Delphi从免注册执行方式改写为利用COM对象的长尾?
- 内容介绍
- 文章标签
- 相关推荐
本文共计893个文字,预计阅读时间需要4分钟。
我正在努力改进使用COM对象实例进行通信的现有程序集。COM服务器实际上是主应用程序的(可选)扩展。两者都通过简单的副本部署到目标系统。目前,这两个应用程序仅部署在我们办公室。
我正在努力修改使用COM对象实例进行通信的现有程序集.COM服务器实际上是主应用程序的(可选)扩展.两者都通过简单的副本部署到目标系统.
目前,这两个应用程序仅部署在我们的办公室本地(尽管主要应用程序,COM客户端,在我们的客户处更广泛地部署),我们手动注册服务器.我们需要重新设计在云服务上的部署,因此,我正在寻找免注册的COM.
到目前为止,我尝试过:
>为客户端和服务器编写清单.遗憾的是,我们无法部署此解决方案,因为客户端与服务器应用程序紧密关联,无法单独部署(我们的客户就是这种情况).
>创建新的激活上下文并从资源中读取服务器的清单.这有效但尝试实例化对象会导致“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扩展的“虚拟”版本,它具有与真实扩展相同的公共接口,但没有真正的功能.添加到该界面的属性,您可以检查它是否是真实的属性.始终部署假人.只要需要,就用真实的扩展名替换假人.
这似乎将您的部署策略与在运行时建立激活上下文的方式分离开来.即,一个固定的清单文件(或嵌入的资源,无论哪个)总是有效.
本文共计893个文字,预计阅读时间需要4分钟。
我正在努力改进使用COM对象实例进行通信的现有程序集。COM服务器实际上是主应用程序的(可选)扩展。两者都通过简单的副本部署到目标系统。目前,这两个应用程序仅部署在我们办公室。
我正在努力修改使用COM对象实例进行通信的现有程序集.COM服务器实际上是主应用程序的(可选)扩展.两者都通过简单的副本部署到目标系统.
目前,这两个应用程序仅部署在我们的办公室本地(尽管主要应用程序,COM客户端,在我们的客户处更广泛地部署),我们手动注册服务器.我们需要重新设计在云服务上的部署,因此,我正在寻找免注册的COM.
到目前为止,我尝试过:
>为客户端和服务器编写清单.遗憾的是,我们无法部署此解决方案,因为客户端与服务器应用程序紧密关联,无法单独部署(我们的客户就是这种情况).
>创建新的激活上下文并从资源中读取服务器的清单.这有效但尝试实例化对象会导致“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扩展的“虚拟”版本,它具有与真实扩展相同的公共接口,但没有真正的功能.添加到该界面的属性,您可以检查它是否是真实的属性.始终部署假人.只要需要,就用真实的扩展名替换假人.
这似乎将您的部署策略与在运行时建立激活上下文的方式分离开来.即,一个固定的清单文件(或嵌入的资源,无论哪个)总是有效.

