網(wǎng)上有些進(jìn)程外的一些資料,但有些簡單,研究了兩天寫了demo,可利用這種方式解決64位的程序調(diào)用32位的dll等問題,但注意方法參數(shù)不能含有IntPtr,因?yàn)橹羔樋邕M(jìn)程是無效的,每個進(jìn)程都有自己的內(nèi)存區(qū)域
一.編寫外部Com服務(wù)exe
1.首先新建一個winform的應(yīng)用程序,并設(shè)置com程序集可見

2.編寫com類
編寫com接口,guid可利用vs的工具生成,代碼設(shè)置com接口的可視,實(shí)現(xiàn)接口后,編寫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");
public static extern int CoRegisterClassObject( [MarshalAs(UnmanagedType.LPStruct)] Guid rclsid, [MarshalAs(UnmanagedType.IUnknown)] object pUnk,
public static extern int CoRevokeClassObject(uint dwRegister);
public static extern int CoInitializeSecurity( IntPtr securityDescriptor,
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);
[Guid(ComHelperClass.s_IID_ITestComVisible)] public interface ITestComVisible string TestProperty { get; set; }
//可擴(kuò)展相應(yīng)的方法接口,并在TestComVisibleClass 實(shí)現(xiàn)
[Guid(ComHelperClass.s_CLSID_TestComVisibleClass)] public class TestComVisibleClass : ITestComVisible public string TestProperty { get; set; }
InterfaceType(ComInterfaceType.InterfaceIsIUnknown), Guid(ComHelperClass.s_IID_IClassFactory) internal interface IClassFactory int CreateInstance(IntPtr pUnkOuter, ref Guid riid, out IntPtr ppvObject); int LockServer(bool fLock); internal class ComClassFactory : IClassFactory #region IClassFactory Members
public int CreateInstance(IntPtr pUnkOuter, ref Guid riid, out IntPtr ppvObject) 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)); Marshal.ThrowExceptionForHR(ComHelperClass.E_NOINTERFACE); public int LockServer(bool fLock)
3.編寫代碼啟動com工廠,調(diào)用;并編譯生成程序
Application.EnableVisualStyles(); Application.SetCompatibleTextRenderingDefault(false); Application.ApplicationExit += new EventHandler(Application_ApplicationExit); Application.Run(new Form1());
static void Application_ApplicationExit(object sender, EventArgs e)
private static void RegisterDcomServer() // 做一些安全檢查,確保只有一些有權(quán)限的人才能調(diào)用你的C# Dcom組件 // 如果你對安全性不關(guān)心的話,可以刪除下面的語句 //int hr = ComHelperClass.CoInitializeSecurity( // IntPtr.Zero, // 這里要輸入你的安全描述符 // ComHelperClass.RPC_C_AUTHN_LEVEL_PKT_PRIVACY, // ComHelperClass.RPC_C_IMP_LEVEL_IDENTIFY, // ComHelperClass.EOAC_DISABLE_AAA | ComHelperClass.EOAC_SECURE_REFS | ComHelperClass.EOAC_NO_CUSTOM_MARSHAL, // Marshal.ThrowExceptionForHR(hr);
int hr = ComHelperClass.CoRegisterClassObject( ComHelperClass.CLSID_TestComVisibleClass, ComHelperClass.CLSCTX_LOCAL_SERVER, ComHelperClass.REGCLS_MULTIPLEUSE, Marshal.ThrowExceptionForHR(hr);
private static void RevokeDcomServer() ComHelperClass.CoRevokeClassObject(m_ComCookie);
4.在本機(jī)注冊com服務(wù)程序(管理身份運(yùn)行 regasm)生成tlb文件,并修改添加注冊表為本地服務(wù)(LocalServer32),刪除自動生成的服務(wù)(inprocServer32)


查看系統(tǒng)注冊表(建議使用RegWorkshop查看,檢索guid )


vs使用的話到此就可以了,但如果c++調(diào)用的話還要在注冊表里聲明下tlb的信息
tlb信息可以用oleview進(jìn)行查看,并在注冊表添加信息


二、外部對com服務(wù)進(jìn)行調(diào)用
新建一個winform程序 ,編寫調(diào)用代碼,即可
System.Type t = Type.GetTypeFromProgID("TestComServer.TestComVisibleClass"); dynamic o = Activator.CreateInstance(t);
至此我們的進(jìn)程外com服務(wù)的編寫和測試程序全部完成
完成的程序Demo
注意下載Demo后,要現(xiàn)在本地進(jìn)行com注冊和相應(yīng)注冊表修改,如果感覺注冊表操作麻煩,可以自己寫個腳本
參考資料:
http://blog.csdn.net/zxdu721/article/details/7785277
https://www.cnblogs.com/killmyday/articles/1395432.html
https://www./KB/COM/simplecomserver.aspx?display=Print
|