我有一些应用程序(一些本机,一些.NET)使用清单文件,以便它们可以完全隔离部署,而无需任何全局COM注册.例如,在myapp.exe.manifest文件中声明对dbgrid32.ocx com服务器的依赖关系如下,该文件与myapp.exe位于同一文件夹中:
<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<assembly manifestVersion="1.0" xmlns="urn:schemas-microsoft-com:asm.v1">
<assemblyIdentity type="win32" name="myapp.exe" version="1.2.3.4" />
<dependency>
<dependentAssembly>
<assemblyIdentity type="win32" name="dbgrid32.ocx" version="5.1.81.4" />
</dependentAssembly>
</dependency>
</assembly>
Run Code Online (Sandbox Code Playgroud)
dbgrid32.ocx与它自己的dbgrid32.ocx.manifest文件一起部署到同一文件夹:
<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<assembly manifestVersion="1.0" xmlns="urn:schemas-microsoft-com:asm.v1">
<assemblyIdentity type="win32" name="dbgrid32.ocx" version="5.1.81.4" />
<file name="dbgrid32.ocx">
<typelib
tlbid="{00028C01-0000-0000-0000-000000000046}"
version="1.0"
helpdir=""/>
<comClass progid="MSDBGrid.DBGrid"
clsid="{00028C00-0000-0000-0000-000000000046}"
description="DBGrid Control" />
</file>
</assembly>
Run Code Online (Sandbox Code Playgroud)
这一切都很好,但手动维护这些清单文件有点痛苦.有没有办法自动生成这些文件?理想情况下,我只想声明应用程序对COM服务器列表(本机和.NET)的依赖性,然后自动生成其余部分.可能吗?
我的程序正在使用Skype4COM.dll(Skype API的包装器).
我正在使用Delphi 2010 - 有没有办法确保我的程序始终使用我将随附的Skype4COM.dll?问题是,有不同版本的Skype4COM,如果我将我的注册用于别人,他们的应用可能不再适用.
通常我使用RegSvr32在人民系统上注册DLL,但是我听说它可以免费注册(在C#中),所以我的问题是:我们也可以在Delphi中这样做吗?
谢谢!
默认情况下,.NET对象是自由线程的.如果通过COM封送到另一个线程,它们总是被封送到自己,无论创建者线程是否是STA,并且无论其ThreadingModel注册表值如何.我怀疑,他们聚合了Free Threaded Marshaler(有关COM线程的更多细节可以在这里找到).
我想让我的.NET COM对象在封送到另一个线程时使用标准的COM marshaller代理.问题:
using System;
using System.Runtime.InteropServices;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Threading;
namespace ConsoleApplication
{
class Program
{
static void Main(string[] args)
{
var apt1 = new WpfApartment();
var apt2 = new WpfApartment();
apt1.Invoke(() =>
{
var comObj = new ComObject();
comObj.Test();
IntPtr pStm;
NativeMethods.CoMarshalInterThreadInterfaceInStream(NativeMethods.IID_IUnknown, comObj, out pStm);
apt2.Invoke(() =>
{
object unk;
NativeMethods.CoGetInterfaceAndReleaseStream(pStm, NativeMethods.IID_IUnknown, out unk);
Console.WriteLine(new { equal = Object.ReferenceEquals(comObj, unk) });
var marshaledComObj = (IComObject)unk;
marshaledComObj.Test();
}); …Run Code Online (Sandbox Code Playgroud) 我在c ++中有基础库,客户端应用程序在C#中.有一个c ++/cli接口可以从C#访问c ++ api.一切都运行正常,直到多个应用程序域没有像NUnit或WCF托管一样发挥,即有一个应用程序域.
我已经在cli 中的gcroot中存储了托管对象以进行回调.我已经读过这是应用程序域问题的根本原因("无法通过AppDomains传递GCHandle")因为它们没有应用程序域信息(http://lambert.geek.nz/2007/05/29/unmanaged -appdomain-callback /).有人建议使用委托,但我的基础c ++层期望对象不是函数指针(http://www.lenholgate.com/blog/2009/07/error-cannot-pass-a-gchandle-across-appdomains.html).我也尝试过IntPtr,但在这种情况下,我无法在回调期间将其强制转换为我的托管对象.
UPDATE
让我再详细说明一下我的问题.
我在C#中有"Receiver"类,它作为输入参数传递给api之一.此接收器对象用于回调.在C++/CLI中,我创建了一个Native/unmanaged类"ObjectBinder",它与托管的Receiver类具有相同的副本(具有相同的方法).它保存了gcroot中托管接收者对象的参考.当我们从C#调用api时,它来到CLI层,app域是"client exe".我们在gcroot中的ObjectBinder中存储参数"managed receiver object",并将本机ObjectBinder对象的引用传递给C++.现在后端代码(c ++和c)将一个asyn回调(新线程)发送到c ++层,该层使用ObjectBinder对象向CLI发送回调用.现在我们在ObjectBinder对象的CLI层中.但是App域已被更改(在WCF或NUNIT或任何其他创建它自己的App域的服务的情况下,在编译时不知道).现在我想访问存储在gcroot中的托管Receiver对象,以便将回调发送回C#,但它给出了APP DOMAIN错误.
我也尝试过IntPtr和IUnknown*而不是gcroot与Marshal :: GetIUnknownForObject和Marshal :: GetObjectForIUnknown但是得到相同的错误.
我有一节课:
public class A
{
public delegate void SetTextDel(string value);
public void Test()
{
SetTextDel setText = someInterface.SetText;
icom.Set(setText);
}
}
[ComVisible(true), Guid("81C99F84-AA95-41A5-868E-62FAC8FAC263"), InterfaceType(ComInterfaceType.InterfaceIsDual)]
public interface Icom
{
void Set(Delegate del);
}
[ComVisible(true)]
[Guid("6DF6B926-8EB1-4333-827F-DD814B868097")]
[ClassInterface(ClassInterfaceType.None)]
[ComDefaultInterface(typeof(Icom))]
public class B : Icom
{
Set(Delegate del)
{
del.DynamicInvoke("some text");
}
}
Run Code Online (Sandbox Code Playgroud)
我在Set(Delegate del)中获得了targetinvocation异常.有没有更好的方法来转发委托作为参数?或者我在这里犯了一些我没有看到的错误.我想做的是将someInterface.SetText这个方法作为参数传递.谢谢你的帮助.