65.9K
CodeProject 正在变化。 阅读更多。
Home

调试监视器字符串

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.88/5 (14投票s)

2004年1月1日

1分钟阅读

viewsIcon

79612

downloadIcon

896

挂钩调试共享内存。

Sample screenshot

Sample screenshot

引言

Code Project不仅发布了数百万个编程创意,而且还在减少编码时间。在示例应用程序中已经准备好许多类,可以直接在新的应用程序中使用,可以修改也可以不修改,从而减少了编码时间。

所以,我想贡献我的代码。即使它很简单,也没有什么新意,也许对其他人有用。

如何挂钩调试共享内存

Trace 语句写入 DBWIN_BUFFER 共享文件。它还使用 DBWIN_DATA_READYDBWIN_BUFFER_READY 事件来同步共享内存中的读写操作。要从该共享内存文件读取数据并发出信号,需要以下函数:

  1. SetEvent
  2. ResetEvent
  3. CreateEvent
  4. CloseHandle
  5. CreateFileMapping
  6. MapViewOfFile
  7. UnmapViewOfFile
  8. WaitForSingleObject

这些函数位于 kernel32.dll 中。在托管代码中使用这些函数有两种选择:

  • COM 包装器 - 大约 20 条机器指令的开销。
  • P/Invoke - 大约 5 条机器指令的开销。

我选择了 P/Invoke,因为它比 COM 包装器更快。

DLLImports

这里是所有的导入签名。

//SET EVENT
[DllImport("Kernel32.dll",CharSet=CharSet.Auto)]
private static extern Boolean SetEvent(IntPtr hEvent);

//RESET EVENT
[DllImport("Kernel32.dll",CharSet=CharSet.Auto)]
private static extern Boolean ResetEvent(IntPtr hEvent);

//OPEN EVENT
[DllImport("Kernel32.dll",CharSet=CharSet.Auto)]
private static extern IntPtr OpenEvent(UInt32 
dwDesiredAccess,Boolean bInheritHandle,String lpName);

//GET LAST ERROR
[DllImport("Kernel32.dll",CharSet=CharSet.Auto)]
private static extern UInt32 GetLastError();

//CREATE EVENT
[DllImport("Kernel32.dll",CharSet=CharSet.Auto)]
private static extern IntPtr CreateEvent(IntPtr 
lpEventAttributes,Boolean bManualReset,Boolean bInitialState,String lpName);

//CLOSE HANDLE
[DllImport("Kernel32.dll",CharSet=CharSet.Auto)]
private static extern Boolean CloseHandle(IntPtr hObject);

//CREATE FILE MAPPING
[DllImport("Kernel32")]
private static extern IntPtr CreateFileMapping(IntPtr hFile, 
  IntPtr pAttributes, UInt32 flProtect,UInt32 dwMaximumSizeHigh, 
  UInt32 dwMaximumSizeLow, String pName);

//MAP VIEW FILE
[DllImport("Kernel32.dll",CharSet=CharSet.Auto)]
private static extern IntPtr 
  MapViewOfFile(IntPtr hFileMappingObject, 
  UInt32 dwDesiredAccess,UInt32 dwFileOffsetHigh, 
  UInt32 dwFileOffsetLow,UInt32 dwNumberOfBytesToMap);

//UNMAP VIEW FILE
[DllImport("Kernel32.dll",CharSet=CharSet.Auto)]
private static extern Boolean UnmapViewOfFile(IntPtr lpBaseAddress);

//WAIT FOR SINGLE OBJECT
[DllImport("Kernel32.dll",CharSet=CharSet.Auto)]
private static extern UInt32 WaitForSingleObject(IntPtr hHandle,
  Int32 dwMilliseconds);

Hook

这是创建同步事件和映射内存文件的代码

public bool Initialize(out String szError){
    bool bResult = false;
    szError = "";
     
    //create ready event
    m_hReady = m_oNative.win32CreateEvent(IntPtr.Zero,
                    false,false,"DBWIN_DATA_READY");
    if(m_hReady != IntPtr.Zero)
    {
        //create ack event
        m_hAck = m_oNative.win32CreateEvent(IntPtr.Zero,
                    false,false,"DBWIN_BUFFER_READY");
        if(m_hAck != IntPtr.Zero)
        {
            //create shared file
            m_hSharedFile = 
              m_oNative.win32CreateFileMapping(CWin32.InvalidHandleValue,
              IntPtr.Zero,CWin32.PAGE_READWRITE,0,1024,"DBWIN_BUFFER");
            if(m_hSharedFile != IntPtr.Zero)
            {
                //map shared file
                m_hShareAddress = 
                  m_oNative.win32MapViewOfFile(m_hSharedFile,
                  CWin32.FILE_MAP_READ,0,0,512);
                if(m_hShareAddress != IntPtr.Zero)
                {
                    bResult = true;
                }
                else
                {
                    szError = "Error to map file";
                }
            }
            else
            {
                szError = "Error to create memory map file DBWIN_BUFFER";
            }
        }
        else
        {
            szError = "Error to create event DBWIN_BUFFER_READY";
        }
    }
    else
    {
        szError = "Error to create event DBWIN_DATA_READY";
    }
    return bResult;
}

等待数据

public staticvoid Run()
{
    m_oNative.win32SetEvent(m_hAck);
    while(fRunning)
    {
        m_oNative.win32WaitForSingleObject(m_hReady,-1);
        UInt32 nApp = (UInt32)Marshal.ReadInt32(m_hShareAddress);
        Byte[] data = new Byte[2000];
        for(int i =0; i < 2000; i++)
        {
            Byte temp = Marshal.ReadByte(m_hShareAddress,i+4);
            if(temp == 13 || temp == 0)
                break;
            data[i] = temp;
        }
        System.Text.Encoding myASCII = System.Text.Encoding.ASCII;
        String szData = myASCII.GetString(data);
        int nIndex = szData.IndexOf("\0");
        if(nIndex != -1)
            szData = szData.Substring(0,nIndex);
        szData = szData.Trim();
        DebugDataEventArgs args = new DebugDataEventArgs(nApp,szData);
        CDebugHelper.DbgHandler(args);
        m_oNative.win32SetEvent(m_hAck);
    }
}

取消挂钩

public bool DeInitialize()
{
    bool bResult = false;
    //Close ready event handle
    if(m_oNative.win32CloseHandle(m_hReady))
    {
        //Close ack event handle
        if(m_oNative.win32CloseHandle(m_hAck))
        {
            //Unmap view file
            if(m_oNative.win32UnmapViewOfFile(m_hShareAddress))
            {
                bResult = true;
            }
        }
    }
    return bResult; 
}

测试

包含三个测试应用程序。

  • ConDms.exe - 调试监视器字符串的控制台版本。
  • WinDms.exe - 调试监视器字符串的 Windows 版本。
  • Test.exe - 发送跟踪字符串的测试程序。
© . All rights reserved.