1

我正在使用解决方案从非托管 C++ 库中检索方法名称,该解决方案使用SymEnumerateSymbols64函数,但 MSDN在这里说应用程序必须SymEnumSymbols改为使用,所以我找到另一个解决方案,但是当我尝试调整和翻译C#将代码转换为VB.NET代码该SYMBOL_INFO.Name属性只包含方法名的第一个字母。

问题出在哪里以及如何解决?

我认为问题可能是结构内的声明:

<MarshalAs(UnmanagedType.ByValTStr, SizeConst:=1024I)>
Public Name As String

...但是如果我删除编组,应用程序就会自行关闭,没有任何异常。

这是完整的代码:

<DllImport("dbghelp.dll", SetLastError:=True, CharSet:=CharSet.Unicode)>
Public Shared Function SymInitialize(
       ByVal hProcess As IntPtr,
       ByVal UserSearchPath As String,
      <MarshalAs(UnmanagedType.Bool)> ByVal fInvadeProcess As Boolean
) As <MarshalAs(UnmanagedType.Bool)> Boolean
End Function

<DllImport("dbghelp.dll", SetLastError:=True, CharSet:=CharSet.Unicode)>
Public Shared Function SymCleanup(
       ByVal hProcess As IntPtr
) As <MarshalAs(UnmanagedType.Bool)> Boolean
End Function

<DllImport("dbghelp.dll", SetLastError:=True, CharSet:=CharSet.Unicode)>
Public Shared Function SymLoadModuleEx(
       ByVal hProcess As IntPtr,
       ByVal hFile As IntPtr,
       ByVal ImageName As String,
       ByVal ModuleName As String,
       ByVal BaseOfDll As Long,
       ByVal DllSize As Integer,
       ByVal Data As IntPtr,
       ByVal Flags As SymLoadModuleFlags
) As ULong
End Function

<DllImport("dbghelp.dll", SetLastError:=True, CharSet:=CharSet.Unicode)>
Public Shared Function SymEnumSymbols(
   ByVal hProcess As IntPtr,
   ByVal BaseOfDll As ULong,
   ByVal Mask As String,
   ByVal EnumSymbolsCallback As SymEnumSymbolsProc,
   ByVal UserContext As IntPtr
) As Boolean '  As <MarshalAs(UnmanagedType.Bool)> Boolean
End Function

Public Delegate Function SymEnumSymbolsProc(
       ByRef pSymInfo As SYMBOL_INFO,
       ByVal SymbolSize As UInteger,
       ByVal UserContext As IntPtr
) As Boolean

<StructLayout(LayoutKind.Sequential)>
Public Structure SYMBOL_INFO

    Public SizeOfStruct As UInteger
    Public TypeIndex As UInteger
    Public Reserved1 As ULong
    Public Reserved2 As ULong
    Public Reserved3 As UInteger
    Public Size As UInteger
    Public ModBase As ULong
    Public Flags As SymFlag
    Public Value As ULong
    Public Address As ULong
    Public Register As UInteger
    Public Scope As UInteger
    Public Tag As SymTagEnum
    Public NameLen As Integer
    Public MaxNameLen As Integer
    <MarshalAs(UnmanagedType.ByValTStr, SizeConst:=1024)>
    Public Name As String

End Structure

<FlagsAttribute>
Public Enum SymFlag As UInteger

    VALUEPRESENT = &H1
    REGISTER = &H8
    REGREL = &H10
    FRAMEREL = &H20
    PARAMETER = &H40
    LOCAL = &H80
    CONSTANT = &H100
    EXPORT = &H200
    FORWARDER = &H400
    [FUNCTION] = &H800
    VIRTUAL = &H1000
    THUNK = &H2000
    TLSREL = &H4000

End Enum

<FlagsAttribute>
Public Enum SymTagEnum As UInteger
    Null
    Exe
    Compiland
    CompilandDetails
    CompilandEnv
    [Function]
    Block
    Data
    Annotation
    Label
    PublicSymbol
    UDT
    [Enum]
    FunctionType
    PointerType
    ArrayType
    BaseType
    Typedef
    BaseClass
    [Friend]
    FunctionArgType
    FuncDebugStart
    FuncDebugEnd
    UsingNamespace
    VTableShape
    VTable
    [Custom]
    Thunk
    CustomType
    ManagedType
    Dimension
End Enum

<Description("Enum used as 'Flags' parameter of 'SymLoadModuleEx' function")>
<FlagsAttribute()>
Public Enum SymLoadModuleFlags As Integer

    Module_And_Symbols = &H0I
    Only_Module = &H4I
    Virtual = &H1I

End Enum

Public Shared Function EnumSyms(ByRef pSymInfo As SYMBOL_INFO,
                                ByVal SymbolSize As UInteger,
                                ByVal UserContext As IntPtr) As Boolean

    '  Debug.WriteLine(pSymInfo.Name)
    Debug.WriteLine(pSymInfo.Address & " " & SymbolSize & " " & pSymInfo.Name)
    Return True

End Function

这是一个真实的示例用法:

Private Sub Test() Handles MyBase.Shown

    Dim hCurrentProcess As IntPtr = Process.GetCurrentProcess().Handle
    Dim baseOfDll As ULong
    Dim status As Boolean

    ' Initialize sym.
    ' Please read the remarks on MSDN for the hProcess
    ' parameter.
    status = SymInitialize(hCurrentProcess, Nothing, False)

    If status = False Then
        MsgBox("Failed to initialize sym.")
        Exit Sub
    End If

    ' Load dll.
    baseOfDll = SymLoadModuleEx(hCurrentProcess,
                                IntPtr.Zero,
                                "C:\Users\Administrador\Desktop\x64.dll",
                                Nothing,
                                0,
                                0,
                                IntPtr.Zero,
                                SymLoadModuleFlags.Module_And_Symbols)

    If baseOfDll = 0 Then
        MsgBox("Failed to load module.")
        SymCleanup(hCurrentProcess)
        Exit Sub
    End If

    ' Enumerate symbols. For every symbol the 
    ' callback method EnumSyms is called.
    If Not SymEnumSymbols(hCurrentProcess,
                          baseOfDll,
                          "*",
                          AddressOf EnumSyms,
                          IntPtr.Zero
    ) Then

        MsgBox("Failed to enum symbols.")

    End If

    ' Cleanup.
    SymCleanup(hCurrentProcess)

End Sub
4

1 回答 1

1

我发现您的代码存在一些问题。

SYMBOL_INFO

应定义为Class。vb.net 结构C++ 结构不同。

Public Reserved1 As ULong
Public Reserved2 As ULong
Public Reserved3 As UInteger

只有两个保留字,不是三个。

ULONG64 Reserved[2];

SymEnumSymbolsProc

ByRef pSymInfo As SYMBOL_INFO

应该是指向传递ByVal的SYMBOL_INFO结构的指针。

_In_ PSYMBOL_INFO pSymInfo,



样本表格

Imports System.Runtime.InteropServices
Imports System.ComponentModel

Public Class Form1

    Private Sub HandleLoad(sender As Object, e As EventArgs) Handles MyBase.Load

        Dim [error] As Exception = Nothing
        Dim initialized As Boolean = False
        Dim hProcess As IntPtr = Nothing

        Try

            SymSetOptions(2 Or 4)
            hProcess = Process.GetCurrentProcess().Handle

            If (SymInitialize(hProcess, Nothing, True)) Then
                initialized = True
            Else
                Throw New Win32Exception(Marshal.GetLastWin32Error())
            End If

            Dim baseOfDll As IntPtr = SymLoadModuleEx(hProcess, IntPtr.Zero, (Environment.SystemDirectory & "\gdi32.dll"), Nothing, 0, 0, IntPtr.Zero, &H0I)

            If (baseOfDll = IntPtr.Zero) Then
                Throw New Win32Exception(Marshal.GetLastWin32Error())
            End If

            If Not SymEnumSymbols(
                hProcess,
                baseOfDll,
                "*",
                Function(pSymInfo As IntPtr, SymbolSize As UInteger, UserContext As IntPtr)
                    Dim struct As New SYMBOL_INFO
                    struct.SizeOfStruct = Marshal.SizeOf(GetType(SYMBOL_INFO))
                    Marshal.PtrToStructure(pSymInfo, struct)
                    Debug.WriteLine(struct.Name)
                    Return True
                End Function, IntPtr.Zero
            ) Then
                Throw New Win32Exception(Marshal.GetLastWin32Error())
            End If

        Catch ex As Exception
            Debug.WriteLine(ex.Message)
        Finally
            If (initialized) Then
                SymCleanup(hProcess)
            End If
        End Try

    End Sub

    <DllImport("dbghelp.dll", SetLastError:=True, CharSet:=CharSet.Auto)>
    Private Shared Function SymSetOptions(ByVal SymOptions As Integer) As Integer
    End Function

    <DllImport("dbghelp.dll", SetLastError:=True, CharSet:=CharSet.Auto)>
    Private Shared Function SymInitialize(ByVal hProcess As IntPtr, ByVal UserSearchPath As String, <MarshalAs(UnmanagedType.Bool)> ByVal fInvadeProcess As Boolean) As <MarshalAs(UnmanagedType.Bool)> Boolean
    End Function

    <DllImport("dbghelp.dll", SetLastError:=True, CharSet:=CharSet.Auto)>
    Private Shared Function SymCleanup(ByVal hProcess As IntPtr) As <MarshalAs(UnmanagedType.Bool)> Boolean
    End Function

    <DllImport("dbghelp.dll", SetLastError:=True, CharSet:=CharSet.Auto)>
    Private Shared Function SymLoadModuleEx(ByVal hProcess As IntPtr, ByVal hFile As IntPtr, ByVal ImageName As String, ByVal ModuleName As String, ByVal BaseOfDll As Long, ByVal DllSize As Integer, ByVal Data As IntPtr, ByVal Flags As Integer) As ULong
    End Function

    <DllImport("dbghelp.dll", SetLastError:=True, CharSet:=CharSet.Auto)>
    Private Shared Function SymEnumSymbols(ByVal hProcess As IntPtr, ByVal BaseOfDll As ULong, ByVal Mask As String, ByVal EnumSymbolsCallback As SymEnumSymbolsProc, ByVal UserContext As IntPtr) As Boolean '  As <MarshalAs(UnmanagedType.Bool)> Boolean
    End Function

    Private Delegate Function SymEnumSymbolsProc(pSymInfo As IntPtr, ByVal SymbolSize As UInteger, ByVal UserContext As IntPtr) As Boolean

    <StructLayout(LayoutKind.Sequential, CharSet:=CharSet.Auto)>
    Private Class SYMBOL_INFO
        Public SizeOfStruct As UInteger
        Public TypeIndex As UInteger
        Public Reserved1 As ULong
        Public Reserved2 As ULong
        Public Index As UInteger
        Public Size As UInteger
        Public ModBase As ULong
        Public Flags As UInteger
        Public Value As ULong
        Public Address As ULong
        Public Register As UInteger
        Public Scope As UInteger
        Public Tag As UInteger
        Public NameLen As UInteger
        Public MaxNameLen As UInteger
        <MarshalAs(UnmanagedType.ByValTStr, SizeConst:=1024)> Public Name As String
    End Class

End Class
于 2014-07-17T15:28:38.973 回答