在EXCEL VBA中使用C#dll
我遇到了一个小问题,需要你们的帮助 我有一个通过COM互操作公开的C#DLL。它工作正常,但显然C#interop对象的部署是一场灾难,每次更新DLL时都需要重新命名 所以我想知道如何使用这个C#DLL中的函数,如下所示: 或者我可以通过把DLL和电子表格放在一起来调用函数的任何东西在EXCEL VBA中使用C#dll,c#,vba,dll,C#,Vba,Dll,我遇到了一个小问题,需要你们的帮助 我有一个通过COM互操作公开的C#DLL。它工作正常,但显然C#interop对象的部署是一场灾难,每次更新DLL时都需要重新命名 所以我想知道如何使用这个C#DLL中的函数,如下所示: 或者我可以通过把DLL和电子表格放在一起来调用函数的任何东西 Declare Function getString Lib "<PATH of my DLL>" () as string sub test() range("A1").value = get
Declare Function getString Lib "<PATH of my DLL>" () as string
sub test()
range("A1").value = getString
End Sub
将函数getString Lib”“()声明为字符串
子测试()
范围(“A1”)。值=getString
端接头
语法可能有误。我多次遇到这个问题。 最后,我在regasm util上使用shell和wait方法从vba注册com dll,以注册/取消注册dll,然后通过创建com对象进行后期绑定
CreateObject('yourclasshere')
这有点像黑客,但它是有效的,下面是shellandwait方法和一个register and unregister方法
Private Declare Function OpenProcess Lib "kernel32" _
(ByVal dwDesiredAccess As Long, ByVal bInheritHandle As Long, _
ByVal dwProcessId As Long) As Long
Private Declare Function GetExitCodeProcess Lib "kernel32" _
(ByVal hProcess As Long, lpExitCode As Long) As Long
Private Const STATUS_PENDING = &H103&
Private Const PROCESS_QUERY_INFORMATION = &H400
Private Function ShellandWait(ExeFullPath As String, _
Optional TimeOutValue As Long = 0) As Boolean
Dim lInst As Long
Dim lStart As Long
Dim lTimeToQuit As Long
Dim sExeName As String
Dim lProcessId As Long
Dim lExitCode As Long
Dim bPastMidnight As Boolean
On Error GoTo ErrorHandler
lStart = CLng(Timer)
sExeName = ExeFullPath
'Deal with timeout being reset at Midnight
If TimeOutValue > 0 Then
If lStart + TimeOutValue < 86400 Then
lTimeToQuit = lStart + TimeOutValue
Else
lTimeToQuit = (lStart - 86400) + TimeOutValue
bPastMidnight = True
End If
End If
lInst = Shell(sExeName, vbHide)
lProcessId = OpenProcess(PROCESS_QUERY_INFORMATION, False, lInst)
Do
Call GetExitCodeProcess(lProcessId, lExitCode)
DoEvents
If TimeOutValue And Timer > lTimeToQuit Then
If bPastMidnight Then
If Timer < lStart Then Exit Do
Else
Exit Do
End If
End If
Loop While lExitCode = STATUS_PENDING
ShellandWait = True
Exit Function
ErrorHandler:
ShellandWait = False
End Function
Private Function RegisterPayload() As Boolean
Dim script As String
script = "cmd /c"
script = script + " " + "%windir%\Microsoft.NET\Framework\v2.0.50727\regasm"
script = script + " " + Chr(34) + InstallationPath + Chr(34)
script = script + " /codebase"
RegisterPayload = ShellandWait(script)
End Function
Private Function UnRegisterPayload() As Boolean
Dim script As String
script = "cmd /c"
script = script + " " + "%windir%\Microsoft.NET\Framework\v2.0.50727\regasm"
script = script + " " + Chr(34) + InstallationPath + Chr(34)
script = script + " /u"
UnRegisterPayload = ShellandWait(script)
End Function
私有声明函数OpenProcess Lib“kernel32”_
(ByVal希望访问时间尽可能长,ByVal bInheritHandle希望访问时间尽可能长_
ByVal dwProcessId As Long)As Long
私有声明函数GetExitCodeProcess Lib“kernel32”_
(ByVal HPPROCESS尽可能长,lpExitCode尽可能长)尽可能长
私有常量状态\u挂起=&H103&
Private Const PROCESS\u QUERY\u INFORMATION=&H400
私有函数ShellandWait(ExeFullPath为字符串_
可选的超时值(长=0)为布尔值
昏暗的林斯特一样长
黯淡的开始和漫长的
我会尽可能地退出
Dim sExeName作为字符串
将lProcessId变长
Dim lExitCode尽可能长
Dim bPastMidnight作为布尔值
关于错误转到错误处理程序
lStart=CLng(计时器)
sExeName=ExeFullPath
'处理在午夜重置超时
如果超时值>0,则
如果lStart+TimeOutValue<86400,则
lTimeToQuit=lStart+TimeOutValue
其他的
lTimeToQuit=(lStart-86400)+超时值
bPastMidnight=True
如果结束
如果结束
lInst=Shell(sExeName,vbHide)
lProcessId=OpenProcess(进程查询信息,False,lInst)
做
调用GetExitCodeProcess(lProcessId,lExitCode)
多芬特
如果TimeOutValue和Timer>LTI退出,则
如果是午夜
如果计时器<开始,则退出Do
其他的
退出Do
如果结束
如果结束
lExitCode=状态_挂起时循环
ShellandWait=True
退出功能
错误处理程序:
ShellandWait=False
端函数
私有函数RegisterPayload()为布尔值
将脚本变暗为字符串
script=“cmd/c”
script=script++%windir%\Microsoft.NET\Framework\v2.0.50727\regasm
脚本=脚本+“”+Chr(34)+安装路径+Chr(34)
script=script+“/codebase”
RegisterPayload=ShellandWait(脚本)
端函数
私有函数UnRegisterPayload()为布尔值
将脚本变暗为字符串
script=“cmd/c”
script=script++%windir%\Microsoft.NET\Framework\v2.0.50727\regasm
脚本=脚本+“”+Chr(34)+安装路径+Chr(34)
脚本=脚本+“/u”
UnRegisterPayload=ShellandWait(脚本)
端函数
希望有帮助:)您可以这样做,但您必须了解VBA和.Net的区别。
首先,您必须创建一个实际的DLL(.Net程序集不是),为此,请使用。 同样,您必须知道如何封送内容。
VBA只支持stdcall作为调用约定,它不能真正处理用于DLL函数的Unicode。这本身并不坏,因为.Net中字符串的默认封送处理是VBA所期望的(指向Ansi字符的指针)。另外,stdcall是我用于导出的默认调用约定 我将重新使用最近为另一个SO线程创建的示例: 将其放入使用“我的模板”创建的项目中:
[ComVisible(true), ClassInterface(ClassInterfaceType.AutoDual)]
public class Sample
{
public string Text
{
[return: MarshalAs(UnmanagedType.BStr)]
get;
[param: MarshalAs(UnmanagedType.BStr)]
set;
}
[return: MarshalAs(UnmanagedType.BStr)]
public string TestMethod()
{
return Text + "...";
}
}
static class UnmanagedExports
{
[DllExport]
[return: MarshalAs(UnmanagedType.IDispatch)]
static Object CreateDotNetObject(String text)
{
return new Sample { Text = text };
}
}
以下是如何从VBA调用它:
Declare Function CreateDotNetObject Lib "The full path to your assembly or just the assembly if it is accessible from Excel" _
(ByVal text As String) As Object
Sub test()
Dim instance As Object
Set instance = CreateDotNetObject("Test 1")
Debug.Print instance.Text
Debug.Print instance.TestMethod
instance.text = "abc 123" ' case insensitivity in VBA works as expected'
Debug.Print instance.Text
End Sub
以下是要放在类顶部的关键using语句: 使用系统诊断; 使用RGiesecke.DllExport 还要确保在Nuget PM语句之前启动了一个项目,以安装上面的模板。我在这方面是新手——我相信还有其他人。我正在使用AutoCAD VBA,但由于它是64位的,因此出现了另一个错误-我必须在Declare语句中使用PtrSafe(etc),以便VBA在没有错误的情况下继续运行(有关此信息,请参阅MS docs) 顺便说一句,它成功了 我的最终代码(基于上述内容) 和我的vba代码:
#If VBA7 Then
Private Declare PtrSafe Function CreateDotNetObject Lib "G:\gitRepository\VS\ClassLibrary3\ClassLibrary3\bin\Debug\ClassLibrary3.dll" (ByVal text As String) As Object
#Else
Private Declare Function CreateDotNetObject Lib "G:\gitRepository\VS\ClassLibrary3\ClassLibrary3\bin\Debug\ClassLibrary3.dll" (ByVal text As String) As Object
#End If
Sub test()
Dim instance As Object
Set instance = CreateDotNetObject("Test 1")
Debug.Print instance.text
Debug.Print instance.TestMethod
instance.text = "abc 123" ' case insensitivity in VBA works as expected'
Debug.Print instance.text
End Sub
项目模板页面不可用。当我从公司网络内部尝试时,我遇到了类似的错误,但我怀疑我们臭名昭著的内容过滤防火墙是罪魁祸首。我可以从我的Android手机上下载。不确定谷歌今天是否把事情搞砸了。不过我对此表示怀疑。我也可以从IPhone上浏览网页。但无法下载。不知道为什么会发生这种情况。但是,如果你想让我直接向你发送模板,你可以通过谷歌邮件服务的robert dot giesecke给我发邮件。我在Visual C#2010 express中使用这个模板,我无法编译空项目,因为找不到Lib.exe。
#If VBA7 Then
Private Declare PtrSafe Function CreateDotNetObject Lib "G:\gitRepository\VS\ClassLibrary3\ClassLibrary3\bin\Debug\ClassLibrary3.dll" (ByVal text As String) As Object
#Else
Private Declare Function CreateDotNetObject Lib "G:\gitRepository\VS\ClassLibrary3\ClassLibrary3\bin\Debug\ClassLibrary3.dll" (ByVal text As String) As Object
#End If
Sub test()
Dim instance As Object
Set instance = CreateDotNetObject("Test 1")
Debug.Print instance.text
Debug.Print instance.TestMethod
instance.text = "abc 123" ' case insensitivity in VBA works as expected'
Debug.Print instance.text
End Sub