VB6 - 使用指针声明和调用C DLL

3
我有一个旧的C DLL,我用它来从Ruby调用函数,但现在我需要从VB6中调用它,但是我无法弄清楚正确的调用方式。
下面是我需要的函数头文件: int Decrunch(const BYTE *src, BYTE *dest, DWORD src_length) *src是需要被该函数解密的字节序列。
*dest是接收解密数据的缓冲区。如果我将dest设置为NULL并调用函数,它将返回解密数据的大小,因此我可以使用它来创建具有正确大小的缓冲区。
我尝试将src和dest都声明为字符串(就像我在Ruby中做的那样),但是它无法工作。我也尝试将它们声明为字节,并像一些教程所指示的那样传递字节数组的第一个元素,但我认为我没有正确地执行它。
有人能帮我吗?
谢谢!
3个回答

3
空气编码
Private Declare DecrunchGetLength Alias "Decrunch" Lib "somedll.DLL" (ByRef src As Byte, ByVal nullptr As Long, ByVal SrcLength As Long) As Long 

Private Declare Decrunch Alias "Decrunch" Lib "somedll.DLL" (ByRef src As Byte, ByRef dest As Byte, ByVal SrcLength As Long) As Long 

Dim destLen As Long
 Dim src(0 To 9) As Byte 
Dim dest() As Byte 

' get bytes into src somehow 

' get dest length 
destLen = DecrunchGetLen( src(0), 0, 10) 

ReDim dest(0 To destLen - 1) 
destLen = Decrunch( src(0), dest(0), 10) 

有用的链接


谢谢!但是在调用DecrunchGetLen时我仍然遇到了“Bad DLL calling convention”的问题。还有其他的建议吗?也感谢您提供的链接。 - user1780279
我不知道。我得检查一下开发者是否记得这个。我有函数算法,也许直接翻译代码或者构建另一个DLL会更容易些。 - user1780279
抱歉,刚刚才注意到链接。我会按照说明进行操作,希望能有所帮助 =) 谢谢。 - user1780279
Dumpbin不会获取任何修饰过的名称,只有普通名称。我会问开发人员。 - user1780279
2
编译后的应用程序尝试在调用您的API函数后“修复”堆栈。很明显,将此留在生产代码中是多么危险,这并不总是成功的。 - wqw
显示剩余2条评论

3
您可以像这样使用CDECL调用的thunk。
Option Explicit

'--- for VirtualProtect'
Private Const PAGE_EXECUTE_READWRITE    As Long = &H40

Private Declare Function VirtualProtect Lib "kernel32" (lpAddress As Any, ByVal dwSize As Long, ByVal flNewProtect As Long, lpflOldProtect As Long) As Long
Private Declare Function LoadLibrary Lib "kernel32" Alias "LoadLibraryA" (ByVal lpLibFileName As String) As Long
Private Declare Function GetProcAddress Lib "kernel32" (ByVal hModule As Long, ByVal lpProcName As String) As Long
Private Declare Function CallWindowProc Lib "user32" Alias "CallWindowProcA" (ByVal lpPrevWndFunc As Long, ByVal hWnd As Long, ByVal Msg As Long, ByVal wParam As Long, ByVal lParam As Long) As Long

Private Const STR_MYDLL         As String = "my.dll"

Private Type UcsParamThunk
    pfn                     As Long
    Call_(0 To 7)           As Long
End Type

Private m_hModule           As Long
Private m_uCallThunk        As UcsParamThunk

Private Sub Form_Load()
    Dim baSrc()         As Byte
    Dim baDst()         As Byte

    On Error GoTo EH
    ReDim baSrc(0 To 10000) As Byte
    ReDim baDst(0 To 20000) As Byte
    pvCallFunc "Decrunch", VarPtr(baSrc(0)), VarPtr(baDst(0)), UBound(baSrc) + 1
    Exit Sub
EH:
    MsgBox Error$, vbCritical
End Sub

Private Function pvCallFunc(sFunc As String, ParamArray A()) As Long
    Dim pfn             As Long
    Dim lIdx            As Long
    Dim aParams()       As Long

    If m_hModule = 0 Then
        m_hModule = LoadLibrary(STR_MYDLL)
        If m_hModule = 0 Then
            Err.Raise vbObjectError, , STR_MYDLL & " not found"
        End If
        pvInitCallCdeclThunk m_uCallThunk
    End If
    pfn = GetProcAddress(m_hModule, sFunc)
    If pfn = 0 Then
        Err.Raise vbObjectError, , "Export not found: " & sFunc
    End If
    ReDim aParams(0 To UBound(A) + 1) As Long
    For lIdx = 0 To UBound(A)
        aParams(lIdx) = CLng(A(lIdx))
    Next
    pvCallFunc = CallWindowProc(m_uCallThunk.pfn, pfn, UBound(aParams), VarPtr(aParams(0)), 0)
End Function

Private Sub pvInitCallCdeclThunk(Thunk As UcsParamThunk)
'void _stdcall thunk(int pfn, int count, int args, int dummy)
'        push    ebp
'        mov     ebp, esp
'        mov     ecx, count
'        jecxz   _skip_params
'        mov     edx, args
'_params_loop:
'        push    dword ptr [edx + ecx * 4 - 4]
'        loop    _params_loop
'_skip_params:
'        call pfn
'        mov     esp,ebp
'        pop     ebp
'        ret     10h
'        nop
'        nop
    With Thunk
        .Call_(0) = &H8BEC8B55
        .Call_(1) = &H9E30C4D
        .Call_(2) = &HFF10558B
        .Call_(3) = &HE2FC8A74
        .Call_(4) = &H855FFFA
        .Call_(5) = &HC25DE58B
        .Call_(6) = &H90900010
        .pfn = VarPtr(.Call_(0))
        Call VirtualProtect(Thunk, Len(Thunk), PAGE_EXECUTE_READWRITE, 0)
    End With
End Sub

0
作为一个很好的经验法则,如果你遇到来自其他语言(例如C++)的指针,在VB6中应该将它们声明为“Any”。
Private Declare Decrunch Alias "Decrunch" Lib "somedll.DLL" (cpbSrc As Any, pbDest As Any, dwDataLength As Long) As Long
Dim cpbSrc(0 to 10) as byte, pbDest() as byte, dwDataLength as long
Call Decrunch(cpbSrc(0), Byval 0, dwDataLength)    ' Pass NULL pointer to return the length
Redim pbDest(0 to dwDataLength - 1)    ' initialize the pbDest array
Debug.Print Decrunch(cpbSrc(0), pbDest(0), dwDataLength)

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接