c#从嵌入的资源dll文件加载程序集并导出函数

通过AssemblyResolve event实现。然后就可以using直接调用了。

GetManifestResourceStream里面加载的资源名称字符串由"项目名.路径文件夹名.dll文件名带扩展名"构成。看资源文件路径就可以得到。

static Assembly CurrentDomain_AssemblyResolve(object sender, ResolveEventArgs args)
        {//=> Assembly.LoadFrom($@"{new FileInfo(args.RequestingAssembly.Location).DirectoryName}\{args.Name.Split(',')[0]}.dll");
            using (Stream stream = Assembly.GetExecutingAssembly().GetManifestResourceStream("Qrcode.Resources.QRCoder.dll"))
            { //从嵌入的资源dll文件加载程序集
                byte[] byData = new byte[stream.Length];
                stream.Read(byData, 0, byData.Length);
                return Assembly.Load(byData);
            }
        }

 下面是一个我写的导出c#类给excel vba调用的代码。目的是在excel里生成二维码。我只生成X64的dll因为我的office是64位的应用。

using QRCoder;
using System;
using System.Drawing;
using System.Runtime.InteropServices;
using System.Reflection;
using System.IO;

namespace Qrcodes
{
    [ComVisible(true), ClassInterface(ClassInterfaceType.AutoDual)]
    public class myqrcode
    {
        public void CreateIm([MarshalAs(UnmanagedType.BStr)]string s, [MarshalAs(UnmanagedType.BStr)]string filePath)
        {
            using (QRCodeGenerator qrGenerator = new QRCodeGenerator())
            {
                QRCodeData qrCodeData = qrGenerator.CreateQrCode(s, QRCodeGenerator.ECCLevel.Q);
                QRCode qrCode = new QRCode(qrCodeData);
                Bitmap qrCodeImage = qrCode.GetGraphic(6, Color.Black, Color.White, null, 15, 6, true);
                qrCodeImage.Save(filePath);
            }
        }

    }
    static class UnmanagedExports
    {
        static UnmanagedExports()
           => AppDomain.CurrentDomain.AssemblyResolve += CurrentDomain_AssemblyResolve;

        static Assembly CurrentDomain_AssemblyResolve(object sender, ResolveEventArgs args)
        {//=> Assembly.LoadFrom($@"{new FileInfo(args.RequestingAssembly.Location).DirectoryName}\{args.Name.Split(',')[0]}.dll");
            using (Stream stream = Assembly.GetExecutingAssembly().GetManifestResourceStream("Qrcode.Resources.QRCoder.dll"))
            { //从嵌入的资源dll文件加载程序集
                byte[] byData = new byte[stream.Length];
                stream.Read(byData, 0, byData.Length);
                return Assembly.Load(byData);
            }
        }
        [DllExport]
        [return: MarshalAs(UnmanagedType.IDispatch)]
        static Object CreateQrcodeClass()
        {
            return new myqrcode();
        }
    }
}

.net语言导出函数其实是通过在IL代码里面添加.export指令进行处理。在dotnet官网里面有人展示过了过程。有兴趣可以看看。dll和il代码转来转去看着麻烦。当然也可以通过第三方辅助实现。我就是通过dllexport导出了c#类。而且可以生成il代码,我们可以研究dllexport到底修改了啥,从中学习。dllexport 的github地址:https://github.com/3F/DllExport。有离线版的可供使用。目前我在用的是1.62版。1.63版有些bug。我去看了下作者这两天一直在更新修复bug.另外官网的例子总是有些简单。呵呵。就像c++ win32编程。我看到网上很多例子都是用int这种很简单的数据类型做参数,一点参考价值都没有。一到了复杂的数据类型参数传递就懵了。注意不同语言的通用数据类型以及平台独立性。我给vba/vb调用。就需要注意c#对应com/vb/vba的数据类型。如下图:

C# 类型 非托管类型 VBA 类型 备注
String UnmanagedType.BStr String  
int UnmanagedType.SysInt Integer  
bool UnmanagedType.VariantBool Boolean  
Class UnmanagedType.IDispatch Object VBA返回一个类对象。
Array 如:int[] ar UnmanagedType.SafeArray Array 如:Dim ar() As Long 如使用数组作为参数确保 C#使用 “ref”关键字作为引用的选择.如: ref int[] ar

更详细的非托管的数据类型可以查看msdn:https://docs.microsoft.com/en-us/dotnet/api/system.runtime.interopservices.unmanagedtype?redirectedfrom=MSDN&view=netframework-4.8

注意里面里面有些是与c++相关的。 

我们可以通过dependency walker看看。生成的dll依然需要.net framework支持。但是我们可以看到导出了函数:

我们再将dll放到excel文件路径下通过vba调用:

Private Declare PtrSafe Function CreateQrcodeClass Lib "Qrcode.dll" () As Object
Sub gg()
ChDrive ThisWorkbook.FullName
ChDir ThisWorkbook.Path & "\"
Set d = CreateQrcodeClass()
d.CreateIm "你好", ThisWorkbook.Path & "\1.png"
Set d = Nothing
End Sub

 上面的vba代码通过切当前目录到excel路径下。那么dll文件必须和excel文件在同一路径下。另一个办法就是声明的时候带上具体路径。如:Lib "D:\Dll文件夹\生成二维码\Qrcode.dll"就可以了。不然会找不到dll文件。

扫描二维码关注公众号,回复: 12890232 查看本文章

上面的结果就生成了一个二维码图片1.png.如图。这样的好处是我们可以不用注册dll就可以调用.net里面的类库方法。以及第三方库。这对于vb/vba的扩展使用很方便吧。本文的实例展示下载地址:https://download.csdn.net/download/qq_24499417/11922883

猜你喜欢

转载自blog.csdn.net/qq_24499417/article/details/94699124