我开始使用一个非常复杂的客户端和服务器系统,带有COM引用和其他东西,我一直在减少,直到我意识到我甚至无法获得Microsoft示例代码来管理受管COM服务器的免注册COM激活用C#编写.
服务器代码:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.InteropServices.ComTypes;
using System.Runtime.InteropServices;
using System.ComponentModel;
namespace ClassLibrary1
{
[Guid("A7AC6D8C-FF17-4D2C-A3B1-2C8690A8EA04")
,ComVisible(true)]
public interface IClass1
{
[DispId(1)]
string DummyFunction(string inputValue);
}
[Guid("81723475-B5E3-4FA0-A3FE-6DE66CEE211C"),
ClassInterface(ClassInterfaceType.None),
ComDefaultInterface(typeof(IClass1)),
ComVisible(true)]
public class Class1 : IClass1
{
public string DummyFunction(string inputValue)
{
return inputValue.Substring(0, 1) + " Inserted " + inputValue.Substring(1);
}
}
}
Run Code Online (Sandbox Code Playgroud)
客户端VB6代码:
Dim c As ClassLibrary1.Class1
Set c = New Class1
MsgBox c.DummyFunction("Ben")
Run Code Online (Sandbox Code Playgroud)
客户端C++代码:
#include "stdafx.h"
#import <ClassLibrary1.tlb> raw_interfaces_only
using namespace ClassLibrary1;
int _tmain(int …Run Code Online (Sandbox Code Playgroud) 它是关于Window COM组件的.
我们知道,exe不能用作无注册表的COM组件,模仿这种行为,我通过提供确切的路径自己启动Server.exe进程:
如果我注册了Server.tlb,它可以正常工作,但是在取消注册Server.tlb之后,它只是无法创建ppAppObject,即使我将清单嵌入到Server.exe和Client.exe中:
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
<file name="Server.tlb">
<typelib tlbid="{DAC4A4C9-F84C-4F05-A7DC-E152869499F5}" version="1.0" helpdir=""></typelib>
</file>
<comInterfaceExternalProxyStub name="IApplication" iid="{D74208EA-71C2-471D-8681-9760B8ECE599}" tlbid="{DAC4A4C9-F84C-4F05-A7DC-E152869499F5}" proxyStubClsid32="{00020424-0000-0000-C000-000000000046}"></comInterfaceExternalProxyStub>
</assembly>
Run Code Online (Sandbox Code Playgroud)
你对此有什么想法吗?
编辑:事实证明,如果我为接口指定tlbid并将清单嵌入到两个exe中,它确实有效
我们正在开发一个基于MFC的大型应用程序与少数托管(.NET)加载项的集成.与这些加载项的通信是通过COM完成的.
从历史上看,我们刚刚使用注册表将这些加载项(作为COM服务器)提供给应用程序.但是,现在我们正在尝试使用无注册的COM互操作来实现这一目标.
我们希望这些加载项能够与运行应用程序的目录位于一个单独的目录中 - 最好是在任何地方.但是,由于无法解析依赖程序集,我们显然遇到了服务器对象实例化的问题,这些程序集也存在于COM服务器DLL的目录中.
"老式"COM互操作在加载目标程序集时使用LoadFrom上下文来处理此问题.但激活上下文机制似乎并没有这样做.
有谁知道如何让这个工作?目前尚不清楚我们是否可以在模块的SxS清单中识别依赖程序集,或者我们是否可以以不同方式创建激活上下文?
感谢您的任何想法/提示!
杰夫
我知道我们可以使用CoLoadLibrary和DllGetClassObject来获取IClassFactory接口并获取COM组件接口而无需注册DLL.
但是EXE中的COM组件怎么样?有没有办法通过提供不同的文件路径从EXE类型的COM服务器获取COM组件接口?
我已经构建了一个使用两个COM服务器dll的COM客户端应用程序; 我希望这个应用程序在没有COM注册的情况下运行 - 即:winsxs/.manifests
当我尝试从客户端应用程序创建COM对象的实例时,我得到了一个(...几乎可以预期......)"Class not registered"消息.
我之前已经成功完成了这种配置,但我无法弄清楚为什么这个配置失败了.
这里有一些细节:
我有的COM对象:
-
[
object,
uuid(262D00FB-3B9F-4A76-98FC-3051FDCAF0A6),
dual,
nonextensible,
helpstring("IDialogManager Interface"),
pointer_default(unique)
]
interface IDialogManager : IDispatch{
};
[
uuid(58562535-BCA5-4D04-BB92-78F90EDA201E),
//...
]
dispinterface _IDialogManagerEvents
{
};
[
uuid(D599D3F0-A4D1-44A7-87A9-16032CC613CA),
//...
]
coclass DialogManager
{
[default] interface IDialogManager;
[default, source] dispinterface _IDialogManagerEvents;
};
Run Code Online (Sandbox Code Playgroud)
-
-
[
object,
uuid(2A183A2E-A620-4E00-B657-C9D2E59201D4),
nonextensible,
helpstring("ICadWizardsManager Interface"),
pointer_default(unique)
]
interface ICadWizardsManager : IDispatch{
};
[
object,
uuid(FE97F3FB-8930-43BC-947D-64C90F45A071),
nonextensible,
helpstring("ICadWizard Interface"),
pointer_default(unique)
]
interface ICadWizard …Run Code Online (Sandbox Code Playgroud) 更新:在花了20多个小时尝试使一个简单的示例工作之后,我意识到这并不像看起来那样简单。诸如此类的文章揭示了“陷阱”-它是在Windows 7之前编写的(处理清单的方式有所不同)。我坚持通过VSTO将.NET程序集暴露给VBA 。
我制作了一个简单的COM-Visible .NET程序集,并试图从Excel VBA中调用它。如果我在.NET构建过程中“注册COM Interop”,则可以从VBA成功调用它。
Sub VBA()
Dim obj As Object
Set obj = actCtx.CreateObject("ComTest.Main")
MsgBox obj.Test() '<-- Displays "Hello"
End Sub
Run Code Online (Sandbox Code Playgroud)
但是,我想免注册。
根据汉斯的建议更新:
我取消选中``注册COM Interop'',然后将我的app.Manifest设置为:
Sub VBA()
Dim obj As Object
Set obj = actCtx.CreateObject("ComTest.Main")
MsgBox obj.Test() '<-- Displays "Hello"
End Sub
Run Code Online (Sandbox Code Playgroud)
我创建了一个虚拟的“ client.manifest”,如下所示:
<?xml version="1.0" encoding="utf-8"?>
<asmv1:assembly
manifestVersion="1.0"
xmlns="urn:schemas-microsoft-com:asm.v1"
xmlns:asmv1="urn:schemas-microsoft-com:asm.v1"
xmlns:asmv2="urn:schemas-microsoft-com:asm.v2"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<assemblyIdentity
type="win32"
version="1.0.0.0"
name="ComTest"
publicKeyToken="a36a7110110d7bd7" />
<clrClass
clsid="{975DC7E0-4596-4C42-9D0C-0601F86E3A1B}"
progid="ComTest.Main"
threadingModel="Both"
name="ComTest.Main"
runtimeVersion="v4.0.30319">
</clrClass>
<file name = "ComTest.dll"></file>
</asmv1:assembly>
Run Code Online (Sandbox Code Playgroud)
创建对象时,我修改了VBA以使用client.manifest: …
我的Delphi应用程序Client.exe需要几个.tlb文件才能工作.这些文件定义服务器接口.使用创建相应的对象实例System.Win.ComObj.CreateRemoteComObject.
问题是什么?
目前,.tlb文件在安装期间全局regtlibv12.exe注册,在卸载软件时未注册.这使得无法安装和卸载同一软件的多个实例,因为它可能会破坏TLB注册.
尝试使用免费注册COM解决问题
我们的想法是在.tlb没有注册但使用文件的情况下使用这些.manifest文件.我知道如何使用Delphi定制的Windows应用程序清单文件.但我不知道如何从.tlb文件中提取信息并创建正确的.manifest文件.
我找到了可用于生成文件的Mt.exe,.manifest但它对我没有帮助
-tlb设置参数时,它要求相应的DLL文件,但.dll由于在远程计算机上创建了COM对象,因此应用程序附带的文件没有
它不接受.tlb参数列表中的多个文件.
其他工具,如Make My Manifest或Unattended Make My Manifest不再可用,或者也不帮助我.
在这种情况下,创建清单文件的正确方法是什么?
有谁知道免注册COM和拖放功能之间可能存在哪种关系?
具体来说,我们有一个巨大的C++ CAD/CAM应用程序,包括许多EXE和数百个DLL.其中许多用作COM服务器(进程内和进程外)和/或客户端,还实现ActiveX控件.
大多数ActiveX控件和CMDIFrameWnd其中一个EXE 的主要窗口都实现了拖放功能.ActiveX控件实现了drop source和drop target,主窗口只是drop target,特别是来自Windows Explorer的文件.
拖/放实施是非常标准的并且基于来自衍生出的两个数据成员COleDataSource和COleDropTarget用于分别放置源和放置目标.所述COleDropTarget衍生的部件与在窗口的相应窗口注册OnCreate方法.它还覆盖OnDragEnter,OnDragOver并OnDrop以类似的方式方法.即,系统提供的COleDataObject参数被要求特定格式(特别是CF_HDROP),并且在肯定答案的情况下,从剪贴板提取数据(例如,文件路径).代码如下所示:
static FORMATETC g_FileFmt = {CF_HDROP, 0, DVASPECT_CONTENT, 0, TYMED_HGLOBAL};
....
// Inside OnDragEnter, OnDragOver or OnDrop method
STGMEDIUM stgmedium = {0,0,0};
if (pDataObject->IsDataAvailable(g_FileFmt.cfFormat))
{
HRESULT hr = pDataObject->GetData(g_FileFmt.cfFormat, &stgmedium);
HDROP hdrop = (HDROP)GlobalLock(stgmedium.hGlobal);
if (hdrop != 0)
{
int FilesCount = DragQueryFile(hdrop, (UINT)-1, 0, 0);
if (FilesCount != 0)
{
TCHAR FileName[_MAX_PATH]; …Run Code Online (Sandbox Code Playgroud) 在我的一个项目中,我有一个使用C++ DLL的c#应用程序.目前在客户端PC上,我们在注册表中的COM组件上注册C++ DLLS,以便我们在C#中使用它们.
我在NET上了解到有一个免费解决方案可以从微软获得链接http://msdn.microsoft.com/en-us/library/ms973913.aspx
但阅读后我没有太多线索,因为我的应用程序架构如下所示
我的客户端只打开C#Exe,后者又调用ConsumeForm.dll,它进一步调用CPForms.dll,显示C++表单(UI),有按钮验证,当用户在内部使用C++ Rules.dll单击该按钮时.目前我在注册表中注册了两个C++ dll.
现在客户端只希望将Rule.dll作为RegFree安装引用,因为Rule.dll经常更改,并且客户端不想使用管理员帐户一次又一次地注销和注册.
其他那个客户端可以注册CPForms.dll.
我的问题是我们如何生成清单文件?它在我的场景中将如何运作?