Introduction
Code Project is not only distributing millions of programming ideas but it also is reducing coding time. There are a number of classes ready in sample applications which can be used directly in your new application with or without modification, thus it is reducing the time in coding.
So, I thought let me contribute my code also. Even though it is simple and nothing new, may be it will be useful for others.
How to hook into debug shared memory
Trace
statement writes in DBWIN_BUFFER
shared file. It also uses DBWIN_DATA_READY
and DBWIN_BUFFER_READY
events to sync read and write operations in shared memory. To read from this shared memory file and signal event, followings function are required.
SetEvent
ResetEvent
CreateEvent
CloseHandle
CreateFileMapping
MapViewOfFile
UnmapViewOfFile
WaitForSingleObject
These functions are in kernel32.dll. There are two options to use this function in managed code.
- COM wrapper - around 20 machine instructions overhead.
- P/Invoke - around 5 machine instructions overhead.
I chose P/Invoke because it is faster compared to COM wrapper.
DLLImports
Here are all the import signatures.
[DllImport("Kernel32.dll",CharSet=CharSet.Auto)]
private static extern Boolean SetEvent(IntPtr hEvent);
[DllImport("Kernel32.dll",CharSet=CharSet.Auto)]
private static extern Boolean ResetEvent(IntPtr hEvent);
[DllImport("Kernel32.dll",CharSet=CharSet.Auto)]
private static extern IntPtr OpenEvent(UInt32
dwDesiredAccess,Boolean bInheritHandle,String lpName);
[DllImport("Kernel32.dll",CharSet=CharSet.Auto)]
private static extern UInt32 GetLastError();
[DllImport("Kernel32.dll",CharSet=CharSet.Auto)]
private static extern IntPtr CreateEvent(IntPtr
lpEventAttributes,Boolean bManualReset,Boolean bInitialState,String lpName);
[DllImport("Kernel32.dll",CharSet=CharSet.Auto)]
private static extern Boolean CloseHandle(IntPtr hObject);
[DllImport("Kernel32")]
private static extern IntPtr CreateFileMapping(IntPtr hFile,
IntPtr pAttributes, UInt32 flProtect,UInt32 dwMaximumSizeHigh,
UInt32 dwMaximumSizeLow, String pName);
[DllImport("Kernel32.dll",CharSet=CharSet.Auto)]
private static extern IntPtr
MapViewOfFile(IntPtr hFileMappingObject,
UInt32 dwDesiredAccess,UInt32 dwFileOffsetHigh,
UInt32 dwFileOffsetLow,UInt32 dwNumberOfBytesToMap);
[DllImport("Kernel32.dll",CharSet=CharSet.Auto)]
private static extern Boolean UnmapViewOfFile(IntPtr lpBaseAddress);
[DllImport("Kernel32.dll",CharSet=CharSet.Auto)]
private static extern UInt32 WaitForSingleObject(IntPtr hHandle,
Int32 dwMilliseconds);
Hook
Here is the code to create sync events and to map memory file:
public bool Initialize(out String szError){
bool bResult = false;
szError = "";
m_hReady = m_oNative.win32CreateEvent(IntPtr.Zero,
false,false,"DBWIN_DATA_READY");
if(m_hReady != IntPtr.Zero)
{
m_hAck = m_oNative.win32CreateEvent(IntPtr.Zero,
false,false,"DBWIN_BUFFER_READY");
if(m_hAck != IntPtr.Zero)
{
m_hSharedFile =
m_oNative.win32CreateFileMapping(CWin32.InvalidHandleValue,
IntPtr.Zero,CWin32.PAGE_READWRITE,0,1024,"DBWIN_BUFFER");
if(m_hSharedFile != IntPtr.Zero)
{
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;
}
Wait for Data
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);
}
}
UnHook
public bool DeInitialize()
{
bool bResult = false;
if(m_oNative.win32CloseHandle(m_hReady))
{
if(m_oNative.win32CloseHandle(m_hAck))
{
if(m_oNative.win32UnmapViewOfFile(m_hShareAddress))
{
bResult = true;
}
}
}
return bResult;
}
Testing
There are three test applications included with this.
- ConDms.exe - console version of debug monitor string.
- WinDms.exe - windows version of debug monitor string.
- Test.exe - test program to send trace string.