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

posted on 2021-05-20 10:35  NLazyo  阅读(6117)  评论(0编辑  收藏  举报