网上有些进程外的一些资料,但有些简单,研究了两天写了demo,可利用这种方式解决64位的程序调用32位的dll等问题,但注意方法参数不能含有IntPtr,因为指针跨进程是无效的,每个进程都有自己的内存区域
一.编写外部Com服务exe
1.首先新建一个winform的应用程序,并设置com程序集可见
2.编写com类
编写com接口,guid可利用vs的工具生成,代码设置com接口的可视,实现接口后,编写com工厂启用com
internal static class ComHelperClass
{
public const string s_IID_ITestComVisible = "C66C0654-49AE-4f2e-8EDA-BD01C8259C20";
public const string s_CLSID_TestComVisibleClass = "12D783BB-33BF-4973-B38B-2A8F0BA926E4";
public static readonly Guid IID_ITestComVisible = new Guid(s_IID_ITestComVisible);
public static readonly Guid CLSID_TestComVisibleClass = new Guid(s_CLSID_TestComVisibleClass);
public const string s_IID_IClassFactory = "00000001-0000-0000-C000-000000000046";
public static readonly Guid IID_IClassFactory = new Guid("00000001-0000-0000-C000-000000000046");
public static readonly Guid IID_IUnknown = new Guid("00000000-0000-0000-C000-000000000046");
[DllImport("ole32.dll")]
public static extern int CoRegisterClassObject(
[MarshalAs(UnmanagedType.LPStruct)] Guid rclsid,
[MarshalAs(UnmanagedType.IUnknown)] object pUnk,
uint dwClsContext,
uint flags,
out uint lpdwRegister);
[DllImport("ole32.dll")]
public static extern int CoRevokeClassObject(uint dwRegister);
[DllImport("ole32.dll")]
public static extern int CoInitializeSecurity(
IntPtr securityDescriptor,
Int32 cAuth,
IntPtr asAuthSvc,
IntPtr reserved,
UInt32 AuthLevel,
UInt32 ImpLevel,
IntPtr pAuthList,
UInt32 Capabilities,
IntPtr reserved3);
public const int RPC_C_AUTHN_LEVEL_PKT_PRIVACY = 6; // Encrypted DCOM communication
public const int RPC_C_IMP_LEVEL_IDENTIFY = 2; // No impersonation really required
public const int CLSCTX_LOCAL_SERVER = 4;
public const int REGCLS_MULTIPLEUSE = 1;
public const int EOAC_DISABLE_AAA = 0x1000; // Disable Activate-as-activator
public const int EOAC_NO_CUSTOM_MARSHAL = 0x2000; // Disable custom marshalling
public const int EOAC_SECURE_REFS = 0x2; // Enable secure DCOM references
public const int CLASS_E_NOAGGREGATION = unchecked((int)0x80040110);
public const int E_NOINTERFACE = unchecked((int)0x80004002);
}
[ComVisible(true)]
[Guid(ComHelperClass.s_IID_ITestComVisible)]
public interface ITestComVisible
{
[DispId(1)]
string TestProperty { get; set; }
[DispId(2)]
void TestMethod();
//可扩展相应的方法接口,并在TestComVisibleClass 实现
}
[ComVisible(true)]
[Guid(ComHelperClass.s_CLSID_TestComVisibleClass)]
public class TestComVisibleClass : ITestComVisible
{
public string TestProperty { get; set; }
public void TestMethod()
{
MessageBox.Show("我是32");
}
}
// 类厂
[
ComImport,
InterfaceType(ComInterfaceType.InterfaceIsIUnknown),
Guid(ComHelperClass.s_IID_IClassFactory)
]
internal interface IClassFactory
{
[PreserveSig]
int CreateInstance(IntPtr pUnkOuter, ref Guid riid, out IntPtr ppvObject);
[PreserveSig]
int LockServer(bool fLock);
}
internal class ComClassFactory : IClassFactory
{
#region IClassFactory Members
public int CreateInstance(IntPtr pUnkOuter, ref Guid riid, out IntPtr ppvObject)
{
ppvObject = IntPtr.Zero;
if (pUnkOuter != IntPtr.Zero)
Marshal.ThrowExceptionForHR(ComHelperClass.CLASS_E_NOAGGREGATION);
if (riid == ComHelperClass.IID_ITestComVisible ||
riid == ComHelperClass.IID_IUnknown)
{
ppvObject = Marshal.GetComInterfaceForObject(
new TestComVisibleClass(), typeof(ITestComVisible));
}
else
Marshal.ThrowExceptionForHR(ComHelperClass.E_NOINTERFACE);
return 0; // S_OK
}
public int LockServer(bool fLock)
{
return 0; // S_OK
}
#endregion
}
3.编写代码启动com工厂,调用;并编译生成程序
static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
RegisterDcomServer();
Application.ApplicationExit += new EventHandler(Application_ApplicationExit);
Application.Run(new Form1());
}
static void Application_ApplicationExit(object sender, EventArgs e)
{
RevokeDcomServer();
}
private static void RegisterDcomServer()
{
// 做一些安全检查,确保只有一些有权限的人才能调用你的C# Dcom组件
// 如果你对安全性不关心的话,可以删除下面的语句
//int hr = ComHelperClass.CoInitializeSecurity(
// IntPtr.Zero, // 这里要输入你的安全描述符
// -1,
// IntPtr.Zero,
// IntPtr.Zero,
// ComHelperClass.RPC_C_AUTHN_LEVEL_PKT_PRIVACY,
// ComHelperClass.RPC_C_IMP_LEVEL_IDENTIFY,
// IntPtr.Zero,
// ComHelperClass.EOAC_DISABLE_AAA | ComHelperClass.EOAC_SECURE_REFS | ComHelperClass.EOAC_NO_CUSTOM_MARSHAL,
// IntPtr.Zero);
//if (hr != 0)
// Marshal.ThrowExceptionForHR(hr);
int hr = ComHelperClass.CoRegisterClassObject(
ComHelperClass.CLSID_TestComVisibleClass,
new ComClassFactory(),
ComHelperClass.CLSCTX_LOCAL_SERVER,
ComHelperClass.REGCLS_MULTIPLEUSE,
out m_ComCookie);
if (hr != 0)
Marshal.ThrowExceptionForHR(hr);
}
private static void RevokeDcomServer()
{
if (m_ComCookie != 0)
ComHelperClass.CoRevokeClassObject(m_ComCookie);
}
4.在本机注册com服务程序(管理身份运行 regasm)生成tlb文件,并修改添加注册表为本地服务(LocalServer32),删除自动生成的服务(inprocServer32)
查看系统注册表(建议使用RegWorkshop查看,检索guid )
vs使用的话到此就可以了,但如果c++调用的话还要在注册表里声明下tlb的信息
扫描二维码关注公众号,回复:
4692775 查看本文章
tlb信息可以用oleview进行查看,并在注册表添加信息
二、外部对com服务进行调用
新建一个winform程序 ,编写调用代码,即可
System.Type t = Type.GetTypeFromProgID("TestComServer.TestComVisibleClass");
dynamic o = Activator.CreateInstance(t);
o.TestMethod();
至此我们的进程外com服务的编写和测试程序全部完成
注意下载Demo后,要现在本地进行com注册和相应注册表修改,如果感觉注册表操作麻烦,可以自己写个脚本
参考资料:
http://blog.csdn.net/zxdu721/article/details/7785277
https://www.cnblogs.com/killmyday/articles/1395432.html
https://www.codeproject.com/KB/COM/simplecomserver.aspx?display=Print