zoukankan      html  css  js  c++  java
  • 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

  • 相关阅读:
    Tarjan算法与割点割边
    kmp匹配
    最小表示法
    字典树
    哈希
    网络流入门浅谈
    关于两道搜索的题目
    2020 4.2校内测题解
    LIS最长上升子序列讲解&&洛谷P1439 【模板】最长公共子序列 题解
    浅谈拉格朗日插值公式
  • 原文地址:https://www.cnblogs.com/bile/p/14788828.html
Copyright © 2011-2022 走看看