最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

libreoffice basic - Is there any method to get information of dll used when clalling a function from a VBScript macro? - Stack O

programmeradmin1浏览0评论

When I run a VBScript that calls a function, is it possible to somehow get information about which .dll library the WScript engine used to implement the function?

I haven't tried anything yet due to I don't know where to start.

EDIT:

Here's more detail on what I'm trying to do:

Option VBASupport 1
Option Compatible

REM This works like a charm:
Sub CreateAndRunVBScript

    Dim dbPath$
    dbPath =  Environ("userprofile") & "\Desktop\MyAccesDb.accdb"
    Dim rtfPath$
    rtfPath = Environ("userprofile") & "\Desktop\help1.rtf"
    Dim VbsPath$
    VbsPath = Environ("userprofile") & "\Desktop\My2Script.vbs"
    Dim strScript As String
    strScript= "Const adTypeBinary = 1" & chr(13) & chr(10) & _
    "Const adInteger = 3" & chr(13) & chr(10) & _
    "Const adParamInput = 1"& chr(13) & chr(10) & _
    "Const OleObject = 205"& chr(13) & chr(10) & _
    "Dim cat" & chr(13) & chr(10) & _
    "Dim connstr" & chr(13) & chr(10) & _
    "Dim dbPath" & chr(13) & chr(10) & _
    "Dim rtfPath"& chr(13) & chr(10) & _
    "Dim fso" & chr(13) & chr(10) & _
    "Dim sql" & chr(13) & chr(10) & _
    "dbPath = " & chr(34) & dbPath & chr(34) & chr(13) & chr(10) & _
    "rtfPath = " & chr(34) & rtfPath & chr(34) & chr(13) & chr(10) & _
    "Set fso = CreateObject(" & chr(34) & "Scripting.Filesystemobject" & chr(34) & ")" & chr(13) & chr(10) & _
    "If fso.FileExists(" & chr(34) & dbPath & chr(34) & ") Then" & chr(13) & chr(10) & _
    "fso.DeleteFile " & chr(34) & dbPath & chr(34) & chr(13) & chr(10) & _
    "End If" & chr(13) & chr(10) & _
    "Set fso = Nothing" & chr(13) & chr(10) & _
    "Set cat = CreateObject(" & chr(34) & "ADOX.Catalog" & chr(34) & ")"  & chr(13) & chr(10) & _
    "connstr = " & chr(34) & "Provider=Microsoft.ACE.OLEDB.16.0;Data Source=" & dbPath & ";" &  chr(34) & chr(13) & chr(10) & _
    "cat.Create connstr" & chr(13) & chr(10) & _
    "Set cat = Nothing" & chr(13) & chr(10) & _
    "Dim conn" & chr(13) & chr(10) & _
    "Set conn = CreateObject(" & chr(34) & "ADODB.Connection" & chr(34) & ")"  & chr(13) & chr(10) & _
    "conn.Open connstr" & chr(13) & chr(10) & _      
    "sql = " & chr(34) & "CREATE TABLE [RTFTABLE] ([ID] int IDENTITY(1,1) PRIMARY KEY, [RTFDATA] OleObject);" & chr(34)  & chr(13) & chr(10) & _
    "conn.Execute sql" & chr(13) & chr(10) & _
    "sql = " & chr(34) & "SELECT ID, RTFDATA FROM RTFTABLE" & chr(34) & chr(13) & chr(10) & _
    "conn.Execute sql" & chr(13) & chr(10) & _
    "Dim strm" & chr(13) & chr(10) & _
    "Dim bytes" & chr(13) & chr(10) & _
    "Dim bsize" & chr(13) & chr(10) & _
    "Set strm = CreateObject(" & chr(34) & "ADODB.Stream" & chr(34) & ")"  & chr(13) & chr(10) & _
    "strm.Type = adTypeBinary" & chr(13) & chr(10) & _
    "strm.Open" & chr(13) & chr(10) & _
    "strm.LoadFromFile " & chr(34) & rtfPath & chr(34) & chr(13) & chr(10) & _
    "strm.Position = 0" & chr(13) & chr(10) & _
    "bytes = strm.Read()" & chr(13) & chr(10) & _
    "bsize = LenB(bytes)" & chr(13) & chr(10) & _
    "strm.Close()" & chr(13) & chr(10) & _
    "Set strm = Nothing" & chr(13) & chr(10) & _
    "Dim cmd" & chr(13) & chr(10) & _
    "Set cmd = CreateObject(" & chr(34) & "ADODB.Command" & chr(34) & ")" & chr(13) & chr(10) & _
    "cmd.ActiveConnection = conn" & chr(13) & chr(10) & _
    "cmd.CommandText = " & chr(34) & "INSERT INTO RTFTABLE (ID, RTFDATA) VALUES (?,?)" & chr(34) & chr(13) & chr(10) & _
    "cmd.Parameters.Append cmd.CreateParameter(" &chr(34) & "ID" & chr(34) & ", adInteger, adParamInput, , 1)"  & chr(13) & chr(10) & _
    "cmd.Parameters.Append cmd.CreateParameter(" & chr(34) & "RTFDATA" & chr(34) &  ", OleObject, adParamInput, bsize, bytes)"  & chr(13) & chr(10) & _
    "cmd.Execute" & chr(13) & chr(10) & _
    "Set cmd = Nothing" & chr(13) & chr(10) & _
    "conn.Close"  & chr(13) & chr(10) & _ 
    "Set conn = Nothing"
    
    Open VbsPath For Output As #1
    Print #1, strScript: Close #1
    Dim sCommand$
    sCommand ="WScript " & VbsPath
    Shell sCommand, 2, , True
    Kill VbsPath

End Sub

Another tuning which does not work as expected:

Option VBASupport 1
Option Explicit

Private Declare Function LoadLibrary Lib "kernel32" Alias "LoadLibraryA" (ByVal lpLibFileName As String) As Long
Private Declare Function FreeLibrary Lib "kernel32" (ByVal hLibModule As Long) As Long
Private Declare Function GetModuleHandle Lib "kernel32" Alias "GetModuleHandleA"  (ByVal lpModuleName As String)  As Long
Private Declare Function GetProcAddress Lib "kernel32" (ByVal hModule As Long, ByVal lpProcName As String) As Long


Sub StartToWork
    
    Dim basePath$, rtfPath$, dbPath$
    basePath = Environ("userprofile") & "\Desktop"
    rtfPath = basePath & "\" & "help1.rtf"
    dbPath = basePath & "\" &"MyAccesDb.accdb"
    CreateDatabase dbPath
    InsertRTFData dbPath, rtfPath
    'ReadFromDb dbPath, rtfPath
        
End Sub

Sub CreateDatabase(dbPath As String)

    Dim cat As Object
    Dim connstr As String

    If Dir(dbPath) <> "" Then Kill dbPath
    
    Set cat = CreateObject("ADOX.Catalog")
    connstr = "Provider=Microsoft.ACE.OLEDB.16.0;Data Source=" & dbPath & ";"
    cat.Create connstr
    Set cat = Nothing

    Dim conn As Object
    Set conn = CreateObject("ADODB.Connection")
    conn.Open connstr

    Dim sql As String
    sql = "CREATE TABLE [RTFTABLE] ([ID] int IDENTITY(1,1) PRIMARY KEY, [RTFDATA] OleObject);"
    conn.Execute sql  
    conn.Close
    Set conn = Nothing
    
End Sub

Sub InsertRTFData(dbPath As String, rtfPath As String)

    Const adTypeBinary = 1
    Const adTypeText    = 2
    Const adModeReadWrite = 3
    Const adInteger = 3
    Const adParamInput = 1
    Const OleObject= 205

    Dim conn As Object, connstr As String, sql As String
    Set conn = CreateObject("ADODB.Connection")
    connstr  = "Provider=Microsoft.ACE.OLEDB.16.0;Data Source=" & dbPath & ";"
    conn.Open connstr
    sql = "SELECT ID, RTFDATA FROM RTFTABLE"
    conn.Execute sql
    Dim bytes () As Byte, bsize As Long, mHwnd As Long
    bytes = FileToBlob(rtfPath)
    Dim lb As Long, pa As Long
    lb = LoadLibrary("C:\Program Files\Common Files\microsoft shared\OFFICE16\ACEDAO.DLL")
    'MsgBox lb
    pa = GetProcAddress(lb, "__VarLenB")
    bsize = pa(bytes) ' this is crap
    FreeLibrary lb
    Dim cmd As Object
    Set cmd = CreateObject("ADODB.Command")
    cmd.ActiveConnection = conn
    cmd.CommandText = "INSERT INTO RTFTABLE (ID, RTFDATA) VALUES (?,?)"
    cmd.Parameters.Append cmd.CreateParameter("ID", adInteger, adParamInput, , 1)
    cmd.Parameters.Append cmd.CreateParameter("RTFDATA", OleObject, adParamInput, bsize, bytes) 'excecution fails here!
    'I haven't found a way to get bsize which should be LenB(bytes).
    'LibreOffice Basic (sbasic) LENB function is in this case completely useless.
    cmd.Execute
    Set cmd = Nothing
    conn.Close
    Set conn = Nothing
    
End Sub

Function FileToBlob(FilePath As String) As Variant

    Dim bytesRead() As Byte
    Open FilePath For Binary As #1
    ReDim bytesRead(LOF(1) - 1)
    Get #1, , bytesRead : Close #1
    FileToBlob = bytesRead
    Erase bytesRead
    
End Function

Sub ReadFromDb(dbPath As String, rtfPath As String)

    Const adTypeBinary = 1
    Dim conn As Object, connstr As String, sql As String
    Set conn = CreateObject("ADODB.Connection")
    connstr  = "Provider=Microsoft.ACE.OLEDB.16.0;Data Source=" & dbPath & ";"
    conn.Open connstr
    Dim rs As Object
    Set rs = CreateObject("ADODB.Recordset")
    sql = "SELECT RTFDATA FROM RTFTABLE;"
    rs.Open sql, conn, 3, 3, 1
    If Not rs.EOF Then rs.MoveLast
    Dim bytes() As Byte
    bytes = rs.Fields.Item("RTFDATA").Value
    rs.Close
    Set rs = nothing
    conn.Close
    Set conn = Nothing
    
End Sub

I'd like to avoid using of external macros.

EDIT: Additional information.

It might be better to clarify. I'm working with LibreOffice Basic macros (VBA-Support on) on Windows 11. I have no other installations related to Ms Office/VBA than AccesDataBaseEngine 2016 (x64) on my system. I've tried to figure out what dll offers the LenB function. After further investigation I'm pretty sure that it's C:\Program Files\Common Files\microsoft shared\OFFICE16\EXPSRV.DLL which will be installed with the AccessDataBaseEngine installation. When I made a deeper dive into this, I realized that the problem can't be solved by declaring and calling the function in my LibreOffice Basic macro due to LibreOffice Basic does not have the variable LongPtr. This results in you not being able to pass the correct type of arguments to function calls. I also tried to install 32-bit version of AccessDatabaseEngine, but the problem worsened. LibreOffice then claims that e.g ADOX is missing or not registered when I'm trying to create object: Set cat = CreateObject("ADOX.Catalog")

When I run a VBScript that calls a function, is it possible to somehow get information about which .dll library the WScript engine used to implement the function?

I haven't tried anything yet due to I don't know where to start.

EDIT:

Here's more detail on what I'm trying to do:

Option VBASupport 1
Option Compatible

REM This works like a charm:
Sub CreateAndRunVBScript

    Dim dbPath$
    dbPath =  Environ("userprofile") & "\Desktop\MyAccesDb.accdb"
    Dim rtfPath$
    rtfPath = Environ("userprofile") & "\Desktop\help1.rtf"
    Dim VbsPath$
    VbsPath = Environ("userprofile") & "\Desktop\My2Script.vbs"
    Dim strScript As String
    strScript= "Const adTypeBinary = 1" & chr(13) & chr(10) & _
    "Const adInteger = 3" & chr(13) & chr(10) & _
    "Const adParamInput = 1"& chr(13) & chr(10) & _
    "Const OleObject = 205"& chr(13) & chr(10) & _
    "Dim cat" & chr(13) & chr(10) & _
    "Dim connstr" & chr(13) & chr(10) & _
    "Dim dbPath" & chr(13) & chr(10) & _
    "Dim rtfPath"& chr(13) & chr(10) & _
    "Dim fso" & chr(13) & chr(10) & _
    "Dim sql" & chr(13) & chr(10) & _
    "dbPath = " & chr(34) & dbPath & chr(34) & chr(13) & chr(10) & _
    "rtfPath = " & chr(34) & rtfPath & chr(34) & chr(13) & chr(10) & _
    "Set fso = CreateObject(" & chr(34) & "Scripting.Filesystemobject" & chr(34) & ")" & chr(13) & chr(10) & _
    "If fso.FileExists(" & chr(34) & dbPath & chr(34) & ") Then" & chr(13) & chr(10) & _
    "fso.DeleteFile " & chr(34) & dbPath & chr(34) & chr(13) & chr(10) & _
    "End If" & chr(13) & chr(10) & _
    "Set fso = Nothing" & chr(13) & chr(10) & _
    "Set cat = CreateObject(" & chr(34) & "ADOX.Catalog" & chr(34) & ")"  & chr(13) & chr(10) & _
    "connstr = " & chr(34) & "Provider=Microsoft.ACE.OLEDB.16.0;Data Source=" & dbPath & ";" &  chr(34) & chr(13) & chr(10) & _
    "cat.Create connstr" & chr(13) & chr(10) & _
    "Set cat = Nothing" & chr(13) & chr(10) & _
    "Dim conn" & chr(13) & chr(10) & _
    "Set conn = CreateObject(" & chr(34) & "ADODB.Connection" & chr(34) & ")"  & chr(13) & chr(10) & _
    "conn.Open connstr" & chr(13) & chr(10) & _      
    "sql = " & chr(34) & "CREATE TABLE [RTFTABLE] ([ID] int IDENTITY(1,1) PRIMARY KEY, [RTFDATA] OleObject);" & chr(34)  & chr(13) & chr(10) & _
    "conn.Execute sql" & chr(13) & chr(10) & _
    "sql = " & chr(34) & "SELECT ID, RTFDATA FROM RTFTABLE" & chr(34) & chr(13) & chr(10) & _
    "conn.Execute sql" & chr(13) & chr(10) & _
    "Dim strm" & chr(13) & chr(10) & _
    "Dim bytes" & chr(13) & chr(10) & _
    "Dim bsize" & chr(13) & chr(10) & _
    "Set strm = CreateObject(" & chr(34) & "ADODB.Stream" & chr(34) & ")"  & chr(13) & chr(10) & _
    "strm.Type = adTypeBinary" & chr(13) & chr(10) & _
    "strm.Open" & chr(13) & chr(10) & _
    "strm.LoadFromFile " & chr(34) & rtfPath & chr(34) & chr(13) & chr(10) & _
    "strm.Position = 0" & chr(13) & chr(10) & _
    "bytes = strm.Read()" & chr(13) & chr(10) & _
    "bsize = LenB(bytes)" & chr(13) & chr(10) & _
    "strm.Close()" & chr(13) & chr(10) & _
    "Set strm = Nothing" & chr(13) & chr(10) & _
    "Dim cmd" & chr(13) & chr(10) & _
    "Set cmd = CreateObject(" & chr(34) & "ADODB.Command" & chr(34) & ")" & chr(13) & chr(10) & _
    "cmd.ActiveConnection = conn" & chr(13) & chr(10) & _
    "cmd.CommandText = " & chr(34) & "INSERT INTO RTFTABLE (ID, RTFDATA) VALUES (?,?)" & chr(34) & chr(13) & chr(10) & _
    "cmd.Parameters.Append cmd.CreateParameter(" &chr(34) & "ID" & chr(34) & ", adInteger, adParamInput, , 1)"  & chr(13) & chr(10) & _
    "cmd.Parameters.Append cmd.CreateParameter(" & chr(34) & "RTFDATA" & chr(34) &  ", OleObject, adParamInput, bsize, bytes)"  & chr(13) & chr(10) & _
    "cmd.Execute" & chr(13) & chr(10) & _
    "Set cmd = Nothing" & chr(13) & chr(10) & _
    "conn.Close"  & chr(13) & chr(10) & _ 
    "Set conn = Nothing"
    
    Open VbsPath For Output As #1
    Print #1, strScript: Close #1
    Dim sCommand$
    sCommand ="WScript " & VbsPath
    Shell sCommand, 2, , True
    Kill VbsPath

End Sub

Another tuning which does not work as expected:

Option VBASupport 1
Option Explicit

Private Declare Function LoadLibrary Lib "kernel32" Alias "LoadLibraryA" (ByVal lpLibFileName As String) As Long
Private Declare Function FreeLibrary Lib "kernel32" (ByVal hLibModule As Long) As Long
Private Declare Function GetModuleHandle Lib "kernel32" Alias "GetModuleHandleA"  (ByVal lpModuleName As String)  As Long
Private Declare Function GetProcAddress Lib "kernel32" (ByVal hModule As Long, ByVal lpProcName As String) As Long


Sub StartToWork
    
    Dim basePath$, rtfPath$, dbPath$
    basePath = Environ("userprofile") & "\Desktop"
    rtfPath = basePath & "\" & "help1.rtf"
    dbPath = basePath & "\" &"MyAccesDb.accdb"
    CreateDatabase dbPath
    InsertRTFData dbPath, rtfPath
    'ReadFromDb dbPath, rtfPath
        
End Sub

Sub CreateDatabase(dbPath As String)

    Dim cat As Object
    Dim connstr As String

    If Dir(dbPath) <> "" Then Kill dbPath
    
    Set cat = CreateObject("ADOX.Catalog")
    connstr = "Provider=Microsoft.ACE.OLEDB.16.0;Data Source=" & dbPath & ";"
    cat.Create connstr
    Set cat = Nothing

    Dim conn As Object
    Set conn = CreateObject("ADODB.Connection")
    conn.Open connstr

    Dim sql As String
    sql = "CREATE TABLE [RTFTABLE] ([ID] int IDENTITY(1,1) PRIMARY KEY, [RTFDATA] OleObject);"
    conn.Execute sql  
    conn.Close
    Set conn = Nothing
    
End Sub

Sub InsertRTFData(dbPath As String, rtfPath As String)

    Const adTypeBinary = 1
    Const adTypeText    = 2
    Const adModeReadWrite = 3
    Const adInteger = 3
    Const adParamInput = 1
    Const OleObject= 205

    Dim conn As Object, connstr As String, sql As String
    Set conn = CreateObject("ADODB.Connection")
    connstr  = "Provider=Microsoft.ACE.OLEDB.16.0;Data Source=" & dbPath & ";"
    conn.Open connstr
    sql = "SELECT ID, RTFDATA FROM RTFTABLE"
    conn.Execute sql
    Dim bytes () As Byte, bsize As Long, mHwnd As Long
    bytes = FileToBlob(rtfPath)
    Dim lb As Long, pa As Long
    lb = LoadLibrary("C:\Program Files\Common Files\microsoft shared\OFFICE16\ACEDAO.DLL")
    'MsgBox lb
    pa = GetProcAddress(lb, "__VarLenB")
    bsize = pa(bytes) ' this is crap
    FreeLibrary lb
    Dim cmd As Object
    Set cmd = CreateObject("ADODB.Command")
    cmd.ActiveConnection = conn
    cmd.CommandText = "INSERT INTO RTFTABLE (ID, RTFDATA) VALUES (?,?)"
    cmd.Parameters.Append cmd.CreateParameter("ID", adInteger, adParamInput, , 1)
    cmd.Parameters.Append cmd.CreateParameter("RTFDATA", OleObject, adParamInput, bsize, bytes) 'excecution fails here!
    'I haven't found a way to get bsize which should be LenB(bytes).
    'LibreOffice Basic (sbasic) LENB function is in this case completely useless.
    cmd.Execute
    Set cmd = Nothing
    conn.Close
    Set conn = Nothing
    
End Sub

Function FileToBlob(FilePath As String) As Variant

    Dim bytesRead() As Byte
    Open FilePath For Binary As #1
    ReDim bytesRead(LOF(1) - 1)
    Get #1, , bytesRead : Close #1
    FileToBlob = bytesRead
    Erase bytesRead
    
End Function

Sub ReadFromDb(dbPath As String, rtfPath As String)

    Const adTypeBinary = 1
    Dim conn As Object, connstr As String, sql As String
    Set conn = CreateObject("ADODB.Connection")
    connstr  = "Provider=Microsoft.ACE.OLEDB.16.0;Data Source=" & dbPath & ";"
    conn.Open connstr
    Dim rs As Object
    Set rs = CreateObject("ADODB.Recordset")
    sql = "SELECT RTFDATA FROM RTFTABLE;"
    rs.Open sql, conn, 3, 3, 1
    If Not rs.EOF Then rs.MoveLast
    Dim bytes() As Byte
    bytes = rs.Fields.Item("RTFDATA").Value
    rs.Close
    Set rs = nothing
    conn.Close
    Set conn = Nothing
    
End Sub

I'd like to avoid using of external macros.

EDIT: Additional information.

It might be better to clarify. I'm working with LibreOffice Basic macros (VBA-Support on) on Windows 11. I have no other installations related to Ms Office/VBA than AccesDataBaseEngine 2016 (x64) on my system. I've tried to figure out what dll offers the LenB function. After further investigation I'm pretty sure that it's C:\Program Files\Common Files\microsoft shared\OFFICE16\EXPSRV.DLL which will be installed with the AccessDataBaseEngine installation. When I made a deeper dive into this, I realized that the problem can't be solved by declaring and calling the function in my LibreOffice Basic macro due to LibreOffice Basic does not have the variable LongPtr. This results in you not being able to pass the correct type of arguments to function calls. I also tried to install 32-bit version of AccessDatabaseEngine, but the problem worsened. LibreOffice then claims that e.g ADOX is missing or not registered when I'm trying to create object: Set cat = CreateObject("ADOX.Catalog")

Share Improve this question asked Mar 11 at 13:01 PertsaPertsa 13 bronze badges 9
  • LenB is not an API. It's a function internal to Visual Basic. – Raymond Chen Commented Mar 11 at 14:33
  • Maybe you should check this: github/VBGAMER45/Semi-VB-Decompiler/blob/master/… – Pertsa Commented Mar 11 at 18:36
  • Then you can check EXPSRV.DLL with nirsoft DLL Export Viewer: __vbaLenBstrB 0x000000018001f088 0x0001f088 379 (0x17b) EXPSRV.DLL C:\Program Files\Common Files\microsoft shared\OFFICE16\EXPSRV.DLL Exported Function – Pertsa Commented Mar 11 at 18:42
  • Again, I don't think you have told us what real question you are trying to answer. Are you trying to find out how many bytes long is the RTFDATA field that you fetched? Is that the real question? If so, shouldn't you have asked that? There are probably OLEDB functions, or even an SQL function, to tell you that. – Tim Roberts Commented Mar 11 at 23:27
  • And again, It's not about the length of the RTFDATA field. The max space is automatically reserved when creating an OleObject field i.e. you cannot specify the length in a SQL statement. The question is about length of the binary array data in memory, LenB(binaryarray), i.e the data which should be copied to the OleObject field. – Pertsa Commented Mar 12 at 8:26
 |  Show 4 more comments

1 Answer 1

Reset to default 0

I managed to get this to work a little differently, still using the Access DB Engine and some NETFX tools.

Instructions, a test file (a simple .rtf with one text line and an image) used in my tuning and my LibreOffice Basic project file

与本文相关的文章

发布评论

评论列表(0)

  1. 暂无评论