S
Sean Setter
I am trying my hand at subclassing the WndProc of an unmanaged form in
order to trap its window messages, and do my own processing. Using
the code below, it will successfully subclass my own WndProc, but
anytime use a handle for any form or control outside of my own app,
SetWindowLongPtr fails. FWIW, I am testing this on 64bit Windows 7.
private void button1_Click(object sender, EventArgs e)
{
//enumerate thru Windows collection
//Windows wndList = new Windows(null, "FTCChat");
//foreach (Window wnd in wndList)
//{
// Console.WriteLine("hWnd[{0}] Class[{1}] Title[{2}]",
(int)wnd.hWnd, wnd.Class, wnd.Title);
//}
string targetTitle = "Untitled - Notepad";
IntPtr targethWnd = FindWindow(targetTitle);
IntPtr target = FindWindowEx(targethWnd, IntPtr.Zero,
"Edit", IntPtr.Zero);
SubclassHWnd(target);
SubclassHWnd(this.console.Handle);
}
// Win32 API needed
// This static method is required because legacy OSes do not
support
// SetWindowLongPtr
private static IntPtr SetWindowLongPtr(IntPtr hWnd, int
nIndex, IntPtr dwNewLong)
{
if (IntPtr.Size == 8)
return SetWindowLongPtr64(hWnd, nIndex, dwNewLong);
else
return new IntPtr(SetWindowLong32(hWnd, nIndex,
dwNewLong.ToInt32()));
}
[DllImport("user32.dll", EntryPoint = "SetWindowLong")]
private static extern int SetWindowLong32(IntPtr hWnd, int
nIndex, int dwNewLong);
[DllImport("user32.dll", EntryPoint = "SetWindowLongPtr")]
private static extern IntPtr SetWindowLongPtr64(IntPtr hWnd,
int nIndex, IntPtr dwNewLong);
[DllImport("user32")]
private static extern IntPtr CallWindowProc(IntPtr
lpPrevWndFunc, IntPtr hWnd, int Msg, int wParam, int lParam);
[DllImport("user32.dll", SetLastError = true)]
public static extern IntPtr FindWindowEx(IntPtr parentHandle,
IntPtr childAfter, string className, IntPtr windowTitle);
// from winuser.h:
private const int GWL_WNDPROC = -4;
private const int WM_LBUTTONDOWN = 0x0201;
// program variables
private IntPtr oldWndProc = IntPtr.Zero;
private Win32WndProc newWndProc = null;
// this is the new wndproc, just show a messagebox on left
button down:
private IntPtr MyWndProc(IntPtr hWnd, int Msg, int wParam, int
lParam)
{
switch (Msg)
{
case WM_LBUTTONDOWN:
MessageBox.Show("Clicked");
return IntPtr.Zero;
default:
break;
}
return CallWindowProc(oldWndProc, hWnd, Msg, wParam,
lParam);
}
// A delegate that matches Win32 WNDPROC:
private delegate IntPtr Win32WndProc(IntPtr hWnd, int Msg, int
wParam, int lParam);
void SubclassHWnd(IntPtr hWnd)
{
// create a delegate for the new wndproc
newWndProc = new Win32WndProc(MyWndProc);
// subclass
oldWndProc = SetWindowLongPtr(hWnd, GWL_WNDPROC,
Marshal.GetFunctionPointerForDelegate(newWndProc));
int err = Marshal.GetLastWin32Error();
Console.WriteLine("[err = {0}] oldWndProc = {1}", err,
oldWndProc);
}
public static IntPtr FindWindow(string name)
{
Process[] procs = Process.GetProcesses();
foreach (Process proc in procs)
{
if (proc.MainWindowTitle == name)
return proc.MainWindowHandle;
}
return IntPtr.Zero;
}
order to trap its window messages, and do my own processing. Using
the code below, it will successfully subclass my own WndProc, but
anytime use a handle for any form or control outside of my own app,
SetWindowLongPtr fails. FWIW, I am testing this on 64bit Windows 7.
private void button1_Click(object sender, EventArgs e)
{
//enumerate thru Windows collection
//Windows wndList = new Windows(null, "FTCChat");
//foreach (Window wnd in wndList)
//{
// Console.WriteLine("hWnd[{0}] Class[{1}] Title[{2}]",
(int)wnd.hWnd, wnd.Class, wnd.Title);
//}
string targetTitle = "Untitled - Notepad";
IntPtr targethWnd = FindWindow(targetTitle);
IntPtr target = FindWindowEx(targethWnd, IntPtr.Zero,
"Edit", IntPtr.Zero);
SubclassHWnd(target);
SubclassHWnd(this.console.Handle);
}
// Win32 API needed
// This static method is required because legacy OSes do not
support
// SetWindowLongPtr
private static IntPtr SetWindowLongPtr(IntPtr hWnd, int
nIndex, IntPtr dwNewLong)
{
if (IntPtr.Size == 8)
return SetWindowLongPtr64(hWnd, nIndex, dwNewLong);
else
return new IntPtr(SetWindowLong32(hWnd, nIndex,
dwNewLong.ToInt32()));
}
[DllImport("user32.dll", EntryPoint = "SetWindowLong")]
private static extern int SetWindowLong32(IntPtr hWnd, int
nIndex, int dwNewLong);
[DllImport("user32.dll", EntryPoint = "SetWindowLongPtr")]
private static extern IntPtr SetWindowLongPtr64(IntPtr hWnd,
int nIndex, IntPtr dwNewLong);
[DllImport("user32")]
private static extern IntPtr CallWindowProc(IntPtr
lpPrevWndFunc, IntPtr hWnd, int Msg, int wParam, int lParam);
[DllImport("user32.dll", SetLastError = true)]
public static extern IntPtr FindWindowEx(IntPtr parentHandle,
IntPtr childAfter, string className, IntPtr windowTitle);
// from winuser.h:
private const int GWL_WNDPROC = -4;
private const int WM_LBUTTONDOWN = 0x0201;
// program variables
private IntPtr oldWndProc = IntPtr.Zero;
private Win32WndProc newWndProc = null;
// this is the new wndproc, just show a messagebox on left
button down:
private IntPtr MyWndProc(IntPtr hWnd, int Msg, int wParam, int
lParam)
{
switch (Msg)
{
case WM_LBUTTONDOWN:
MessageBox.Show("Clicked");
return IntPtr.Zero;
default:
break;
}
return CallWindowProc(oldWndProc, hWnd, Msg, wParam,
lParam);
}
// A delegate that matches Win32 WNDPROC:
private delegate IntPtr Win32WndProc(IntPtr hWnd, int Msg, int
wParam, int lParam);
void SubclassHWnd(IntPtr hWnd)
{
// create a delegate for the new wndproc
newWndProc = new Win32WndProc(MyWndProc);
// subclass
oldWndProc = SetWindowLongPtr(hWnd, GWL_WNDPROC,
Marshal.GetFunctionPointerForDelegate(newWndProc));
int err = Marshal.GetLastWin32Error();
Console.WriteLine("[err = {0}] oldWndProc = {1}", err,
oldWndProc);
}
public static IntPtr FindWindow(string name)
{
Process[] procs = Process.GetProcesses();
foreach (Process proc in procs)
{
if (proc.MainWindowTitle == name)
return proc.MainWindowHandle;
}
return IntPtr.Zero;
}