64位程序調用32位dll的方法


1.wcf(已實現,)

2.注冊com組件服務

由於有一些32位dll沒有源代碼,無法重新編譯為64位dll,所以只能想辦法解決64位進程調用32位dll問題.

相關資料:
微軟公司的官方網站針對這個問題描述如下:
在64位的windows系統中,一個64位進程不能加載一個32位dll,同理一個32位進程也不能加載一個64位dll。但是,64位windows支持64位和32位進程(包括本機或跨機)間進程間通信(RPC)。在64位windows中,一個進程外32位COM服務器能夠與64位客戶端進行通信,同樣一個進程外64位COM服務器也能與32位客戶端進行通信。因此,如果你有一個32位COM無法識別的DLL,你可以將它封裝到一個進程外COM服務器中並在一個64位進程中用COM配置調用DLL。(最后一句我也看不太懂!!哈哈哈)

驗證:
工作流程:
1.創建一個進程外COM服務器(EXE)。
2.將32位dll的接口函數封裝為COM服務器的相關接口。
3.注冊COM服務器*.exe /regserver  (注銷 *.exe /unregserver)。
4.64位進程調用32位COM服務器接口,成功。從而曲線實現了64位進程調用32位dll。

具體步驟:
我首先創建了一個簡單的dll工程,只輸出一個函數int c = add(int a,int b); 生成lib和dll
然后創建一個進程外COM(EXE類型),內部鏈接dll,添加方法Method: Add(long *c)
{ *c = add(1,2);}編譯生成。
然后注冊COM,*.exe /regserver
最創建一個64位WIN32工程驗證64位環境下方法調用是否正確,經驗證正確!!!

結論:以上方法可以解決64位進程調用32位dll的問題

32位進程調用64位dll應該也可以通過這種方法解決,原因64位windows系統下安裝了32位和64位兩套COM系統

網上有些進程外的一些資料,但有些簡單,研究了兩天寫了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的信息

tlb信息可以用oleview進行查看,並在注冊表添加信息

 

 

二、外部對com服務進行調用
    新建一個winform程序 ,編寫調用代碼,即可

        

System.Type t = Type.GetTypeFromProgID("TestComServer.TestComVisibleClass");
dynamic o = Activator.CreateInstance(t);

o.TestMethod();

 至此我們的進程外com服務的編寫和測試程序全部完成

完成的程序Demo 

注意下載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
————————————————
版權聲明:本文為CSDN博主「那里有顆樹」的原創文章,遵循CC 4.0 BY-SA版權協議,轉載請附上原文出處鏈接及本聲明。
原文鏈接:https://blog.csdn.net/shu19880720/article/details/79537277


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM