2009-01-16 40 views
6

Vấn đềlập trình thiết lập đường dẫn tìm kiếm DLL trong VBA vĩ mô

  • Tôi có một mẫu từ đó sử dụng tuyên bố Declare VBA để liên kết đến một dll, có đường có thể được xác định trong các macro VBA
  • tôi muốn trợ giúp điều này cho người dùng% APPDATA% \ Microsoft \ Word \ STARTUP thư mục
  • Tôi KHÔNG muốn thay đổi vĩnh viễn biến môi trường PATH của người dùng (tạm thời là OK, nhưng điều này dường như không hoạt động khi họ không không được làm mới cho đến khi ứng dụng khởi động lại)

giải pháp Cố gắng

tôi đã cố gắng tự động thêm mã với Declare báo cáo sử dụng ThisDocument.VBProject.CodeModule.AddFromString(code) mà làm việc khi tải mẫu từ một thư mục bình thường, nhưng khi mẫu là trong Word \ STARTUP, nó mang lại cho các lỗi sau:

Run-time error '50289':

Can't perform operation since the project is protected.

Và thiết lập các khóa registry "HKEY ___ LOCAL_MACHINE \ Software \ Microsoft \ Office \ 11.0 \ Word \ Security \ AccessVBOM" tới 1 không sửa lỗi này khi mẫu là trong Word \ STARTUP


Tôi đang thực sự đấu tranh để tìm giải pháp. Nếu có ai biết cách để làm điều này, điều đó sẽ rất tuyệt.

+0

có liên quan cho MSAccess http://stackoverflow.com/questions/28977285/how-do-i-find-the-current-path-directory-of-a-ms-access-database – DaveInCaz

Trả lời

5

Bạn có thể sử dụng hàm API LoadLibrary.

Ví dụ trong các dự án của tôi mã trông như thế này:

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

Có một giải pháp thực sự thực sự xấu xí, nhưng blogger này figured it out, và tôi không thể tìm ra bất kỳ cách nào khác:

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

Về cơ bản, bạn viết thủ tục tạo mô-đun mã trong VBA trong thời gian chạy. Mô-đun này phải tạo một tham chiếu đến dll và nó phải tạo một hàm giả (hoặc thủ tục) như một phần của mô-đun này gọi dll. Sau đó, từ mã của bạn, bạn sử dụng Application.Run (dummyfunction(), arg1, arg2 ...). Điều này là cần thiết bởi vì nếu không, dự án sẽ không biên dịch vì hàm giả không phải là một hàm.

Bạn sẽ nhận thấy trong mã của mình, anh ấy sử dụng InputBox() để có được vị trí của .dll nhưng rõ ràng là bạn có thể lấy vị trí từ một phạm vi trong bảng tính. Đoạn mã sau có thể hữu ích.

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' và 'funcString' chỉ là chuỗi mà tôi đã tạo giống như chữ 'ss' của anh ấy. Đoạn mã cho thấy cách bạn có thể đổi tên mô-đun mã để bạn có thể xóa nó sau này nếu cần. Rõ ràng, điều này chỉ xóa nó ngay sau khi nó được tạo ra, và bạn có thể sẽ không muốn làm điều đó, nhưng ít nhất nó cho bạn thấy làm thế nào nó sẽ được thực hiện.

Có nói tất cả điều đó, chúng tôi chủ yếu chỉ cần viết .exe của bây giờ và vỏ ra. Nếu bạn cần VBA chờ đợi trên vỏ để kết thúc, có những giải pháp cho vấn đề đó là tốt.

7

Thành thật mà nói, tôi không biết vấn đề với việc sử dụng tất cả các mã VBA injection, lắp ráp thế hệ cho LoadLibrary() các cuộc gọi, vv kỹ thuật mà tôi đã nhìn thấy được sử dụng cho nhiệm vụ đơn giản này. Trong dự án của tôi, tôi sử dụng mã đơn giản để tải dll từ vị trí tương tự như bảng tính, như thế này:

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

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

Excel 2003 ít nhất, không có vấn đề tải dll từ đường dẫn hiện tại, Set ChDir để bất cứ điều gì con đường của bạn DLL có. Bạn cũng có thể cần phải thay đổi ổ đĩa hiện tại của bạn tách biệt với đường dẫn hiện tại. Bạn phải thực hiện nó chỉ một lần, trước khi gọi hàm đầu tiên, sau khi DLL vẫn được gắn kết bất kể đường dẫn hiện tại của bạn ở đâu, vì vậy bạn có thể làm điều đó một lần trong workbook_open và không bận tâm về đường dẫn sau này. Tôi cung cấp một chức năng giả trống trong DLL chỉ dành cho học sinh này. Tôi không nghĩ rằng MS Word là bất kỳ khác nhau về điều này.

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

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

Hà , như một giải pháp tuyệt vời thanh lịch cho một vấn đề phức tạp khác, cảm ơn! : D – CodeAndCats

+1

Điều đó sẽ không hoạt động. Thư mục hiện tại là một chặng đường dài trong danh sách các đường dẫn được tìm kiếm và trong một số trường hợp, thư mục hiện tại có thể không phải là một đường dẫn tìm kiếm. Thêm vào đó bạn đang vặn vẹo với thư mục làm việc rộng. Phương thức 'LoadLibrary' rõ ràng với đường dẫn tuyệt đối là cách tốt nhất để thực hiện điều này. –

+0

Giả sử bạn cần đường dẫn hiện tại cho tệp Access thay vì Excel, 'CurrentProject.Path' của nó – DaveInCaz

0

Đây là những gì tôi đã kết thúc làm, sử dụng phương pháp Pranav Wagh của liên kết bên trên và mã từ trang web C Pearson (http://www.cpearson.com/excel/vbe.aspx). Mã này sẽ nhắc người dùng chọn đường dẫn tới dll bằng cách sử dụng một cửa sổ Open File, xây dựng một mô-đun mới với một hàm Declare với đường dẫn đầu vào và một hàm để thực hiện một cái bắt tay với dll. Chức năng mục đích xây dựng trong dll trả về 1 nếu thành công:

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 

Tuy nhiên, khi tôi quay workbook (xlsm) vào một addin (xlam) tôi thấy rằng Excel sẽ không để vĩ mô tạo thêm các module mới vì vậy LinkToDll của tôi sẽ không hoạt động. Việc sửa chữa đã được đưa chức năng Declare trở lại vào LinkToDll chỉ với tên tập tin dll ("Geo_DLL.dll") như Lib cùng với phụ runthisfunc. Tôi thấy có người dùng chỉ cần chọn tập tin dll thông qua cửa sổ Open File là đủ để trỏ Excel vào dll ngay cả với chỉ tên tập tin trong phần Lib của tuyên bố chức năng khai báo.

Chris

Các vấn đề liên quan