通过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文件。

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