use*_*691 22 .net c# clr vba runtime
我找到了一种直接从VBA宏调用.NET 2代码的方法:
Dim clr As mscoree.CorRuntimeHost
Set clr = New mscoree.CorRuntimeHost
clr.Start
Dim domain As mscorlib.AppDomain
clr.GetDefaultDomain domain
Dim myInstanceOfDotNetClass As Object
Set myInstanceOfDotNetClass = domain.CreateInstanceFrom("SomeDotNetAssembly.dll", "Namespace.Typename").Unwrap
Call myInstanceOfDotNetClass.ExecuteSomeDotNetMethod
Run Code Online (Sandbox Code Playgroud)
(为了使这段代码工作,我想在Excel中使用工具 - >引用...将对mscoree.tlb和mscorlib.tlb的引用添加到Excel VBA)
但这仅适用于.NET CLR 2程序集,最高可达.NET Framework 3.5版.
现在我需要使用.NET 4.
我已经了解.NET CLR4引入了另一种与版本无关的创建运行时实例的方法,我还发现了一个用C++编写的相当简单的代码示例:http: //dev.widemeadows.de/2014/02/ 04 /托管最净-4-运行时在-一个天然过程/
但是我的Excel VBA技能还不足以将这几行代码转换为工作的VBA makro.有人能帮帮我吗?
Jer*_*son 21
以下是从Excel(或VBA)调用.Net的3种主要方法的规范性答案.
这三种方式都适用于.Net 4.0.
第三方供应商Add-In Express提供XLL功能,但其免费且易于使用的Excel-DNA 作者在这里 /sf/users/3098511/
以下是Excel-DNA页面的摘录:https://excel-dna.net/
介绍
Excel-DNA是一个将.NET集成到Excel中的独立项目.使用Excel-DNA,您可以使用C#,Visual Basic.NET或F#为Excel创建本机(.xll)加载项,从而提供高性能的用户定义函数(UDF),自定义功能区界面等.您的整个加载项可以打包到单个.xll文件中,无需安装或注册.
入门
如果您使用的是版本的Visual Studio支持NuGet包管理器(包括的Visual Studio 2012 Express的Windows桌面),最简单的方法,使一个Excel-DNA加载项是:
在Visual Basic,C#或F#中创建一个新的类库项目.使用"管理NuGet包"对话框或包管理器控制台安装Excel-DNA包:
PM> Install-Package Excel-DNA
Run Code Online (Sandbox Code Playgroud)
添加代码(C#,Visual Basic.NET或F#):
using ExcelDna.Integration;
public static class MyFunctions
{
[ExcelFunction(Description = "My first .NET function")]
public static string SayHello(string name)
{
return "Hello " + name;
}
}
Run Code Online (Sandbox Code Playgroud)
在Excel中编译,加载和使用您的函数:
=SayHello("World!")
Run Code Online (Sandbox Code Playgroud)
Eric Carter的这篇文章展示了如何做到这一点,文章缺少大量的图像,所以我复制/粘贴整篇文章,并重新创建图像进行保存.
参考:https://blogs.msdn.microsoft.com/eric_carter/2004/12/01/writing-user-defined-functions-for-excel-in-net/
Excel允许创建可在Excel公式中使用的用户定义函数.开发人员必须创建一种称为XLL的特殊DLL.Excel还允许您在VBA中编写可在Excel公式中使用的自定义函数.遗憾的是,Excel不支持或建议编写使用托管代码的XLL.如果你愿意把你的机会,你的XLL可能无法在Excel的当前或未来的版本中运行,有可用,使这种情况下,在网络上搜索"管理XLL"的解决方案.
幸运的是,有一种更简单的方法来创建一个不需要您创建XLL dll的用户定义函数.Excel XP,Excel 2003和Excel 2007支持称为自动化加载项的功能.可以在C#或VB.NET中非常简单地创建自动化加载项.我将在C#中向您展示一个示例.
首先,启动Visual Studio并为此示例创建一个名为AutomationAddin的新C#类库项目.
然后,在Class1.cs文件中,输入如下所示的代码.使用Visual Studio的"工具"菜单中的"生成GUID"将GUID替换为您自己创建的GUID.
using System;
using System.Runtime.InteropServices;
using Microsoft.Win32;
namespace AutomationAddin
{
// Replace the Guid below with your own guid that
// you generate using Create GUID from the Tools menu
[Guid("A33BF1F2-483F-48F9-8A2D-4DA68C53C13B")]
[ClassInterface(ClassInterfaceType.AutoDual)]
[ComVisible(true)]
public class MyFunctions
{
public MyFunctions()
{
}
public double MultiplyNTimes(double number1, double number2, double timesToMultiply)
{
double result = number1;
for (double i = 0; i < timesToMultiply; i++)
{
result = result * number2;
}
return result;
}
[ComRegisterFunctionAttribute]
public static void RegisterFunction(Type type)
{
Registry.ClassesRoot.CreateSubKey(GetSubKeyName(type, "Programmable"));
RegistryKey key = Registry.ClassesRoot.OpenSubKey(GetSubKeyName(type, "InprocServer32"), true);
key.SetValue("", System.Environment.SystemDirectory + @"\mscoree.dll",RegistryValueKind.String);
}
[ComUnregisterFunctionAttribute]
public static void UnregisterFunction(Type type)
{
Registry.ClassesRoot.DeleteSubKey(GetSubKeyName(type, "Programmable"), false);
}
private static string GetSubKeyName(Type type, string subKeyName)
{
System.Text.StringBuilder s = new System.Text.StringBuilder();
s.Append(@"CLSID\{");
s.Append(type.GUID.ToString().ToUpper());
s.Append(@"}\");
s.Append(subKeyName);
return s.ToString();
}
}
}
Run Code Online (Sandbox Code Playgroud)
编写此代码后,双击解决方案资源管理器中项目下的属性节点,显示项目的属性.单击Build选项卡,选中"Register for COM Interop"复选框.此时,如果您在Windows Vista或更高版本上运行,则还有一个额外的步骤.必须以管理员权限运行Visual Studio才能注册COM互操作.保存项目并退出Visual Studio.然后在"开始"菜单中找到Visual Studio并右键单击它并选择"以管理员身份运行".在Visual Studio中重新打开您的项目.然后选择"Build"来构建加载项.
现在启动Excel并按照以下步骤进入自动化服务器对话框:
启动Excel并单击窗口左上角的Microsoft Office按钮.
选择Excel选项.
单击"Excel选项"对话框中的"加载项"选项卡.
从标有"管理"的组合框中选择"Excel加载项".然后单击"Go"按钮.
单击"加载项"对话框中的"自动化"按钮.
您可以通过在自动化加载项列表中查找AutomationAddin.MyFunctions来找到您创建的类:
现在,让我们尝试在Excel中使用MultiplyNTimes函数.首先创建一个简单的电子表格,其中包含一个数字,第二个数字与第一个数字相乘,第三个数字表示您希望将第一个数字乘以第二个数字的次数.此处显示了一个示例电子表格:
单击数字下方工作簿中的空单元格,然后单击公式栏中的"插入函数"按钮.从可用公式的对话框中,下拉"或选择一个类别"下拉框并选择"AutomationAddin.MyFunctions".
然后单击MultiplyNTimes函数,如下所示:
当您按下确定按钮时,Excel会弹出一个对话框,帮助您从电子表格中获取函数参数,如下所示:
最后,点击"确定",然后在单元格C3中查看自定义公式所示的最终电子表格.
REF:从vba调用.net库方法
使用Automation.AddIn项目中的代码,我们可以轻松地从Excel VBA调用MultiplyNTimes函数.
首先从Excel添加对DLL的引用,为此,您需要在VB编辑器中.按Alt + F11,然后单击工具菜单和参考:
选择AutomationAddIn DLL:
添加VBA代码以调用.Net DLL:
Sub Test()
Dim dotNetClass As AutomationAddIn.MyFunctions
Set dotNetClass = New AutomationAddIn.MyFunctions
Dim dbl As Double
dbl = dotNetClass.MultiplyNTimes(3, 2, 5)
End Sub
Run Code Online (Sandbox Code Playgroud)
嘿presto!
最后有一些关于Excel和.Net的优秀MSDN文章由"Andrew Whitechapel" - google他们
小智 7
这是您的解决方案,经过Soraco Technologies的测试,针对.NET 2.0和.NET 4.0,32位和64位进行了测试.
下面提出的解决方案使用后期绑定,不需要注册.NET程序集.
声明
将以下声明添加到项目中:
#If VBA7 Then
Private Declare PtrSafe Function GetShortPathName Lib “Kernel32.dll” Alias “GetShortPathNameW” (ByVal LongPath As LongPtr, ByVal ShortPath As LongPtr, ByVal Size As Long) As Long
Private Declare PtrSafe Function SetDllDirectory Lib “Kernel32.dll” Alias “SetDllDirectoryW” (ByVal Path As LongPtr) As Long
Private Declare PtrSafe Sub LoadClr_x64 Lib “QlmCLRHost_x64.dll” (ByVal clrVersion As String, ByVal verbose As Boolean, ByRef CorRuntimeHost As IUnknown)
Private Declare PtrSafe Sub LoadClr_x86 Lib “QlmCLRHost_x86.dll” (ByVal clrVersion As String, ByVal verbose As Boolean, ByRef CorRuntimeHost As IUnknown)
#Else
Private Declare Function GetShortPathName Lib “Kernel32.dll” Alias “GetShortPathNameW” (ByVal LongPath As Long, ByVal ShortPath As Long, ByVal Size As Long) As Long
Private Declare Function SetDllDirectory Lib “Kernel32.dll” Alias “SetDllDirectoryW” (ByVal Path As Long) As Long
Private Declare Sub LoadClr_x64 Lib “QlmCLRHost_x64.dll” (ByVal clrVersion As String, ByVal verbose As Boolean, ByRef CorRuntimeHost As IUnknown)
Private Declare Sub LoadClr_x86 Lib “QlmCLRHost_x86.dll” (ByVal clrVersion As String, ByVal verbose As Boolean, ByRef CorRuntimeHost As IUnknown)
#End If ‘ WinAPI Declarations
' Declare variables
Dim m_myobject As Object
Dim m_homeDir As String
Run Code Online (Sandbox Code Playgroud)
初始化
您必须将m_homeDir变量初始化为.NET程序集所在的路径.
例如,如果将.NET程序集安装在与Excel或MS-Access文件相同的文件夹中,则应将m_homeDir初始化为:
Excel:m_homeDir = ThisWorkbook.Path
访问:m_homeDir = CurrentProject.Path
.NET对象创建
将以下代码添加到项目中.
Private Function GetMyObject(dllPath As String, dllClass As String) As Object
Dim LongPath As String
Dim ShortPath As String
LongPath = “\\?\” & m_homeDir
ShortPath = String$(260, vbNull)
PathLength = GetShortPathName(StrPtr(LongPath), StrPtr(ShortPath), 260)
ShortPath = Mid$(ShortPath, 5, CLng(PathLength – 4))
Call SetDllDirectory(StrPtr(ShortPath))
Dim clr As mscoree.CorRuntimeHost
If Is64BitApp() Then
Call LoadClr_x64(“v4.0”, False, clr)
Else
Call LoadClr_x86(“v4.0”, False, clr)
End If
Call clr.Start
Dim domain As mscorlib.AppDomain
Call clr.GetDefaultDomain(domain)
Dim myInstanceOfDotNetClass As Object
Dim handle As mscorlib.ObjectHandle
Set handle = domain.CreateInstanceFrom(dllPath, dllClass)
Dim clrObject As Object
Set GetMyObject = handle.Unwrap
Call clr.Stop
End Function
Private Function Is64BitApp() As Boolean
#If Win64 Then
Is64BitApp = True
#End If
End Function
Run Code Online (Sandbox Code Playgroud)
实例化.NET对象
现在您已准备好实例化.NET对象并开始使用它.将以下代码添加到您的应用程序:
m_homeDir = ThisWorkbook.Path
m_myobject = GetMyObject(m_homeDir & “\yourdotnet.dll”, “namespace.class”)
Run Code Online (Sandbox Code Playgroud)
第一个参数是.NET DLL的完整路径.
第二个参数是所请求类型的完全限定名称,包括命名空间,但不是由Type.FullName属性返回的程序集.
必需的DLL
该解决方案需要部署2个负责托管.NET CLR的DLL.DLL预计将部署在与Excel或MS-Access文件相同的文件夹中.
DLL可以从Soraco的网站下载:https://soraco.co/products/qlm/QLMCLRHost.zip
LGPL-2.1的许可
只要您的应用程序不直接或间接与Quick License Manager竞争,我们特此授予您使用我们的DLL的权利.您可以在商业或非商业应用程序中使用这些DLL.
我不确定这只是巧合还是因为我发布了相关问题。所以向我展示了你的问题,我想我也可以贡献一些东西。
在使用 VBA 和 DLL 时,到目前为止我看到的大多数解决方案都告诉我注册 DLL 并使其 com/gac 可见。如果您在 PC 上执行此操作,那绝对没问题,但是如果您分发 VBA 应用程序,您真的不想在他们的系统中安装 DLL。您可能没有权限,或者您真的不想经历安装/卸载过程或处理引用问题。
但是,您可以使用某些 Windows API 动态加载 dll。
动态链接库
现在的问题是如何从 vba 访问 .NET dll?如果您的客户具有混合操作系统架构 x86 x64,您需要相应地处理此问题。假设我们正在使用 32 位办公/Excel。
如果您创建一个 .NET dll 并希望从 VBA 访问它,它将抛出类似于“找不到 dll 入口点”的错误消息。幸运的是,Robert Giesecke创建了一个抽象包装器,它允许您通过 VBA 创建简单的 DLL 消耗品。
可以在此处找到模板。
所有你需要做的
假设您已经按照他的模板创建了一个测试方法,如下所示。
[ComVisible(true), ClassInterface(ClassInterfaceType.AutoDual)]
public class YOUR_MAIN_CLASS
{
[return: MarshalAs(UnmanagedType.BStr)]
public string FN_RETURN_TEXT(string iMsg)
{
return "You have sent me: " + iMsg + "...";
}
}
Run Code Online (Sandbox Code Playgroud)
和您的非托管导出类:
static class UnmanagedExports
{
[DllExport]
[return: MarshalAs(UnmanagedType.IDispatch)]
static object YOUR_DLL_OBJECT()
{
return new YOUR_MAIN_CLASS();
}
}
Run Code Online (Sandbox Code Playgroud)
准备从vba端访问dll
将 DLL 添加到您的根文件夹:
#If VBA7 Then
Public Declare PtrSafe Function LoadLibrary Lib "kernel32" Alias "LoadLibraryA" (ByVal lpLibFileName As String) As LongPtr
Public Declare PtrSafe Function YOUR_DLL_OBJECT Lib "YOUR_DLL.dll" () As Object
#Else
Public Declare Function LoadLibrary Lib "kernel32" Alias "LoadLibraryA" (ByVal strFilePath As String) As Long
Public Declare Function YOUR_DLL_OBJECT Lib "YOUR_DLL.dll" () As Object
#End If
Run Code Online (Sandbox Code Playgroud)
现在一切都是关于加载 dll 并在 vba 中创建和访问它的对象。那将是:
LoadLibrary (FN_APP_GET_BASE_PATH & "YOUR_DLL.dll")
dim mObj as object
set mObj = YOUR_DLL_OBJECT()
debug.print mObj.FN_RETURN_TEXT("Testing ..")
Run Code Online (Sandbox Code Playgroud)
输出应该是
"You have sent me: Testing ....."
Run Code Online (Sandbox Code Playgroud)
优点 我个人不喜欢安装和引用 dll。通过遵循上述模板,您无需引用任何内容,无需安装任何内容,只需完全自由地加载和使用您的 DLL。
注意:我假设 dll/.net 代码是你的,你可以用上面的模板再次编译它。
我使用上述模板取得了成功,并为 vba 创建了一个 .NET 非阻塞通知,您可以在这里查看:非阻塞“toast”,如 Microsoft Access (VBA) 的通知
默认策略是阻止CLR 4从CLR 2中执行遗留代码:
Set clr = New mscoree.CorRuntimeHost
Run Code Online (Sandbox Code Playgroud)
要启用旧版执行,您可以excel.exe.config
在以下位置的文件夹中创建文件excel.exe
:
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<startup useLegacyV2RuntimeActivationPolicy="true">
<supportedRuntime version="v4.0"/>
</startup>
</configuration>
Run Code Online (Sandbox Code Playgroud)
或者,您可以调用本机函数CorBindToRuntimeEx
而不是New mscoree.CorRuntimeHost
:
Private Declare PtrSafe Function CorBindToRuntimeEx Lib "mscoree" ( _
ByVal pwszVersion As LongPtr, _
ByVal pwszBuildFlavor As LongPtr, _
ByVal startupFlags As Long, _
ByRef rclsid As Long, _
ByRef riid As Long, _
ByRef ppvObject As mscoree.CorRuntimeHost) As Long
Private Declare PtrSafe Function VariantCopy Lib "oleaut32" (dest, src) As Long
''
' Creates a .Net object with the CLR 4 without registration. '
''
Function CreateInstance(assembly As String, typeName As String) As Variant
Const CLR$ = "v4.0.30319"
Static domain As mscorlib.AppDomain
If domain Is Nothing Then
Dim host As mscoree.CorRuntimeHost, hr&, T&(0 To 7)
T(0) = &HCB2F6723: T(1) = &H11D2AB3A: T(2) = &HC000409C: T(3) = &H3E0AA34F
T(4) = &HCB2F6722: T(5) = &H11D2AB3A: T(6) = &HC000409C: T(7) = &H3E0AA34F
hr = CorBindToRuntimeEx(StrPtr(CLR), 0, 3, T(0), T(4), host)
If hr And -2 Then err.Raise hr
host.Start
host.GetDefaultDomain domain
End If
VariantCopy CreateInstance, domain.CreateInstanceFrom(assembly, typeName).Unwrap
End Function
Run Code Online (Sandbox Code Playgroud)
归档时间: |
|
查看次数: |
15002 次 |
最近记录: |