2009-01-16 89 views
6

問題編程設置DLL搜索路徑

  • 我有一個使用VBA的Declare聲明鏈接到一個DLL,其路徑可以在VBA宏
  • 我內確定一個Word模板想要將其分解到用戶%APPDATA%\ Microsoft \ Word \ STARTUP目錄
  • 我不想永久更改用戶的PATH環境變量(暫時可以,但這似乎不起作用,因爲他們不會在應用程序重新啓動之前不會刷新)

嘗試性解決方案

我試圖動態地添加使用ThisDocument.VBProject.CodeModule.AddFromString(code)從一個普通的目錄裝載模板時,其運作Declare語句的代碼,但是當模板是Word中\ STARTUP內,它給以下錯誤:

Run-time error '50289':

Can't perform operation since the project is protected.

,並且設置註冊表鍵 「HKEY LOCAL_MACHINE ___ \軟件\微軟\辦公室\ 11.0 \字\安全\ AccessVBOM」 1不解決這個問題時,模板是在Word \ STARTUP


我真的很努力地找到解決方案。如果有人知道如何做到這一點,那就太好了。

+0

相關的MSACCESS http://stackoverflow.com/questions/28977285/how-do-i-find-the-current-path-directory-of-a-ms-access-database – DaveInCaz 2017-05-17 14:50:39

回答

5

您可以使用LoadLibrary api。

例如在我的項目的代碼如下所示:

If LibraryLoaded() Then 
    Call MyFunc ... 
End If 


Public Function LibraryLoaded() As Boolean 

Static IsLoaded As Boolean 
Static TriedToLoadAlready As Boolean 

If TriedToLoadAlready Then 
    LibraryLoaded = IsLoaded 
    Exit Function 
    End If 
    Dim path As String 
path = VBAProject.ThisWorkbook.path 
path = Left(path, InStrRev(path, "\") - 1) 
IsLoaded = LoadLibrary(path & "\bin\" & cLibraryName) 
TriedToLoadAlready = True 

LibraryLoaded = IsLoaded 

End Function 
2

還有另外一個非常非常醜陋的解決方案,但這個博客想通了,我想不出任何其他方式:

http://blogs.msdn.com/pranavwagh/archive/2006/08/30/How-To-Load-Win32-dlls-Dynamically-In-VBA.aspx

基本上,您編寫了一個在運行時在VBA中創建代碼模塊的過程。該模塊必須創建一個對dll的引用,並且它必須創建一個虛函數(或過程)作爲調用dll的該模塊的一部分。然後,從您的代碼中,使用Application.Run(dummyfunction(),arg1,arg2 ...)。這是必要的,否則,項目不會編譯,因爲dummyfunction還不是函數。

你會發現在他的代碼中,他使用InputBox()來獲取.dll的位置,但顯然你可以從電子表格的範圍中獲取位置。以下代碼片段可能會有用。

Dim cm As CodeModule 
Dim vbc As VBComponent 

Set cm = Application.VBE.ActiveVBProject.VBComponents.Add(vbext_ct_StdModule).CodeModule 
cm.AddFromString (decString & funcString) 
cm.Name = "MyNewModule" 
Set vbc = cm.Parent 
Application.VBE.ActiveVBProject.VBComponents.Remove vbc 

'decString' 和 'funcString' 只是我構建了喜歡他的 'SS' 的字符串。該代碼片段顯示瞭如何重命名代碼模塊,以便稍後在需要時刪除它。顯然,這只是在創建後立即刪除它,你可能不想這樣做,但至少它會告訴你如何完成它。

說了這麼多之後,我們現在主要只是編寫.exe的文件並將其解壓出來。如果您需要VBA等待外殼完成,那麼也有針對該問題的解決方案。

7

坦率地說,我不知道使用所有這些VBA代碼注入,用於LoadLibrary()調用的程序集生成等技術,我見過用於這個簡單任務的問題。在項目中,我用簡單的代碼來從相同的位置加載DLL的工作簿,就像這樣:

Declare Function MyFunc Lib "MyDll.dll" (....) As ... 

Sub Test() 
    .... 
    ChDir ActiveWorkbook.Path 
    ... = MyFunc(....) 
End Sub 

Excel 2003中,至少,沒有問題加載從目前的路徑的dll,設置CHDIR到任何路徑您DLL有。您可能還需要更改與當前路徑分開的當前驅動器。在第一次函數調用之前,您必須先執行一次,不管您的當前路徑位於何處,DLL保持連接狀態,因此您可以在workbook_open中執行一次,而不必在稍後再打擾該路徑。我爲DLL提供了一個空的虛擬函數。我不認爲MS Word在這方面有什麼不同。

Private Declare Sub Dummy Lib "MyDLL.dll"() 

Private Sub Workbook_Open() 
    ChDrive Left$(Me.Path, 1) 
    ChDir Me.Path 
    Dummy 
End Sub 
+0

哈,這是一個非常優雅的解決其他複雜問題的解決方案,謝謝! :D – CodeAndCats 2012-08-07 06:30:22

0

這裏就是我最後做,使用Pranav Wagh的方法由C皮爾遜的網站(http://www.cpearson.com/excel/vbe.aspx)以上和代碼鏈接。此代碼提示用戶使用打開文件窗口選擇dll的路徑,用輸入的路徑構建一個帶有聲明函數的新模塊,並使用與dll執行握手的函數。 DLL中的特製函數返回1,如果成功:

Public rtn As Integer 

Sub LinkToDll() 

Dim path As String, default As String 
MsgBox "Select Geo_DLL.dll file from next window" 

With Application.FileDialog(msoFileDialogOpen) 
    .AllowMultiSelect = False 
    .Title = "Select Geo_DLL.dll file" 
    If .Show = True Then 
     path = .SelectedItems(1) 
    End If 
End With 

'Add a module 
Dim VBProj As VBIDE.VBProject 
Dim VBComp As VBIDE.VBComponent 

Set VBProj = ActiveWorkbook.VBProject 
Set VBComp = VBProj.VBComponents.Add(vbext_ct_StdModule) 
VBComp.Name = "LinkModule" 

'Add procedure to module 
Dim CodeMod As VBIDE.CodeModule 
Dim LineNum As Long 

Set VBComp = VBProj.VBComponents("LinkModule") 
Set CodeMod = VBComp.CodeModule 

With CodeMod 
LineNum = .CountOfLines + 1 
.InsertLines LineNum, "Declare Function RegDll Lib " & Chr(34) & path & Chr(34) & " (ByRef rtn As Integer)" 
LineNum = LineNum + 1 
.InsertLines LineNum, "Sub runthisfunc(rtn)" 
LineNum = LineNum + 1 
.InsertLines LineNum, "On Error Resume Next" 
LineNum = LineNum + 1 
.InsertLines LineNum, "rtn = 0" 
LineNum = LineNum + 1 
.InsertLines LineNum, "RegDll rtn" 
LineNum = LineNum + 1 
.InsertLines LineNum, "If rtn = 1 Then MsgBox (" & Chr(34) & "DLL linked" & Chr(34) & ")" 
LineNum = LineNum + 1 
.InsertLines LineNum, "If rtn = 0 Then MsgBox (" & Chr(34) & "DLL not found" & Chr(34) & ")" 
LineNum = LineNum + 1 
.InsertLines LineNum, "End Sub" 
End With 

'This is what CodeMod.InsertLines is writing: 
'-------------------------------------------- 
'Declare Function RegDll Lib "C:\path\Geo_DLL.dll" (ByRef rtn As Integer) 
'Sub runthisfunc(rtn) 
'On Error Resume Next 
'rtn = 0 
'RegDll rtn 
'If rtn = 1 Then MsgBox ("DLL Linked") 
'If rtn = 0 Then MsgBox (DLL not found") 
'End Sub 

Application.Run "runthisfunc", rtn 

'Delete Module 
VBProj.VBComponents.Remove VBComp 

End Sub 

但是,一旦我打開的工作簿(XLSM)爲插件(xlam)我發現Excel中不會讓宏創建新的模塊所以我的LinkToDll不起作用。解決的辦法是將聲明函數放回到LinkToDll中,只需將dll文件名(「Geo_DLL.dll」)作爲Lib以及runthisfunc子文件。我發現讓用戶只需通過打開文件窗口選擇dll文件就足以將Excel指向dll,即使只使用Declare Function語句的Lib部分中的文件名。

克里斯