Subclassing a external window in C# .NET - c#

I'm trying to subclass an external window in C#.
I have used something similar before in VB6 without any problem BUT the below code just won't work. Can anybody help me out?
//API
[DllImport("user32")]
private static extern IntPtr SetWindowLong(IntPtr hWnd, int nIndex, IntPtr newProc);
[DllImport("user32")]
private static extern IntPtr SetWindowLong(IntPtr hWnd, int nIndex, WinProc newProc);
[DllImport("user32.dll")]
private static extern IntPtr DefWindowProc(IntPtr hWnd, int uMsg, int wParam, int lParam);
[DllImport("user32")]
private static extern IntPtr CallWindowProc(IntPtr lpPrevWndFunc, IntPtr hWnd, int Msg, int wParam, int lParam);
private delegate IntPtr WinProc(IntPtr hWnd, int Msg, int wParam, int lParam);
private const int GWL_WNDPROC = -4;
private enum winMessage : int
{
WM_GETMINMAXINFO = 0x024,
WM_ENTERSIZEMOVE = 0x231,
WM_EXITSIZEMOVE = 0x232
}
private WinProc newWndProc = null;
private IntPtr oldWndProc = IntPtr.Zero;
private IntPtr winHook = IntPtr.Zero;
//Implementation
public void hookWindow(IntPtr winHandle)
{
if (winHandle != IntPtr.Zero)
{
winHook = winHandle;
newWndProc = new WinProc(newWindowProc);
oldWndProc = SetWindowLong(winHook, GWL_WNDPROC,newWndProc);
}
}
public void unHookWindow()
{
if (winHook != IntPtr.Zero)
{
SetWindowLong(winHook, GWL_WNDPROC, oldWndProc);
winHook = IntPtr.Zero;
}
}
private IntPtr newWindowProc(IntPtr hWnd, int Msg, int wParam, int lParam)
{
switch (Msg)
{
case (int)winMessage.WM_GETMINMAXINFO:
MessageBox.Show("Moving");
return DefWindowProc(hWnd, Msg, wParam, lParam);
}

ok im done with the coding, but in your solution you have to have your form solution and a dll solution and it can work, if you want that code let me know. but you cannot subclass within a same exe. so it can all be done in c# but you do need that dll, when i got down to converting my c++ project
all because of
BOOL WINAPI DllMain(HANDLE hinstDLL, DWORD fdwReason, LPVOID lpvReserved )
{
switch(fdwReason)
{
case DLL_PROCESS_ATTACH:
{
hInstance=(HINSTANCE)hinstDLL;
}
break;
case DLL_PROCESS_DETACH:
{
if((int)hndll>1)
{
SetWindowLong(hndll,GWL_WNDPROC,OldWndHndl); //Set back the old window procedure
return 1;
}
}
}
}

It's impossible with C#. Only unmanaged C/C++ can do it..
oldWndProc = SetWindowLong(winHook, GWL_WNDPROC,newWndProc); will always return 0(which means failed) if winHook is from another process.
Reference: https://social.msdn.microsoft.com/Forums/vstudio/en-US/8dd657b5-647b-443b-822d-ebe03ca4033c/change-wndproc-of-another-process-in-c

Related

Select CheckBoxes in Listbox via user32.dll? (

I have a Handle for a ListBox from an external application.
Now I have a Listbox with x Items which I want to select with the WinApi.
I tried this with SETCURSEL but its unfortunatly doesnt work:
private void button2_Click(object sender, EventArgs e)
{
IntPtr chldWnd = NativeMethods.FindWindow("#32770", "Ansichten einfügen");
IntPtr ListBoxHandle = NativeMethods.FindWindowEx(chldWnd, IntPtr.Zero, "ListBox", null);
//MessageBox.Show(ButtonHandle.ToString());
NativeMethods.SendMessageInt(ListBoxHandle, NativeMethods.CB_SETCURSEL, 1, 2);
}
static class NativeMethods
{
public const int BM_CLICK = 0x00F5;
public const int WM_SETTEXT = 0x000C;
public const int VK_DOWN = 0x28;
public const int WM_KEYDOWN = 0x100;
public const int LB_SETSEL = 0x0185;
public const int CB_SETCURSEL = 0x014E;
[DllImport("user32.dll", CharSet = CharSet.Unicode)]
public static extern IntPtr SendMessage(IntPtr hwnd, int wMsg, IntPtr wParam, string lParam);
[DllImport("user32.dll", EntryPoint="PostMessage" ,CharSet = CharSet.Unicode)]
public static extern IntPtr SendMessageInt(IntPtr hWnd, uint Msg, int wParam, int lParam);
[DllImport("user32.dll", CharSet = CharSet.Unicode)]
public static extern IntPtr PostMessage(IntPtr hwnd, int wsg, IntPtr wParam, String lParam);
[DllImport("user32.dll", CharSet = CharSet.Unicode)]
public static extern IntPtr FindWindowEx(IntPtr parentHandle, IntPtr childAfter, string className, string windowTitle);
[DllImport("user32.dll", SetLastError = true)]
public static extern IntPtr FindWindow(string lpClassName, string lpWindowName);
}
I believe that the way I use it will meet your need to select an item with a mouse click on the ListBox, Please, try it.
[DllImport("user32.dll")]
private static extern IntPtr SendMessage(IntPtr hWnd, int Msg, IntPtr wParam, IntPtr lParam);
public void SetListItem(string windowTitle, int index, int item)
{
try
{
var windowHWnd = FindWindowByCaption(IntPtr.Zero, windowTitle);
var childWindows = GetChildWindows(windowHWnd);
const int LB_SETCURSEL = 0x0186;
const int downCode = 0x201;
const int upCode = 0x202;
IntPtr lParam = (IntPtr)9999; // The coordinates
IntPtr wParam = IntPtr.Zero;
SendMessage(childWindows.ToArray()[index], LB_SETCURSEL, item, "0");
SendMessage(childWindows.ToArray()[index], downCode, wParam, lParam); // Mouse button down
SendMessage(childWindows.ToArray()[index], upCode, wParam, lParam);
}
catch (Exception)
{
throw;
}
}

The instructions at 0xXXXXXXXX referenced memory at 0xXXXXXXXX, The memory could not be written

I get this error when trying to implement a windows hook using SetWindowsHookEx and CallWndProc. I'm wondering if i implemented the hook correctly. Here is the code: This code will work as a keyboard hook if its replaced with LowLevelKeyboardProc
[DllImport("user32.dll")]
static extern IntPtr SetWindowsHookEx(int idHook, CallWndProc callback, IntPtr hInstance, uint threadId);
[DllImport("user32.dll")]
static extern bool UnhookWindowsHookEx(IntPtr hInstance);
[DllImport("user32.dll")]
static extern IntPtr CallNextHookEx(IntPtr idHook, int nCode, int wParam, IntPtr lParam);
[DllImport("kernel32.dll")]
static extern IntPtr LoadLibrary(string lpFileName);
private delegate IntPtr CallWndProc(int nCode, IntPtr wParam, IntPtr lParam);
const int WH_CALLWNDPROC = 4;
const int WM_PASTE = 0x302;
private CallWndProc _proc = hookProc;
private static IntPtr hhook = IntPtr.Zero;
public void SetHook()
{
IntPtr hInstance = LoadLibrary("User32");
hhook = SetWindowsHookEx(WH_CALLWNDPROC, _proc, hInstance, 0);
}
public static void UnHook()
{
UnhookWindowsHookEx(hhook);
}
public static IntPtr hookProc(int code, IntPtr wParam, IntPtr lParam)
{
if (code >= 0 && wParam == (IntPtr)WM_PASTE)
{
MessageBox.Show("Paste");
return (IntPtr)1;
}
else
return CallNextHookEx(hhook, code, (int)wParam, lParam);
}
private void Form1_Closing(object sender, System.ComponentModel.CancelEventArgs e)
{
UnHook();
}
private void Form1_Load(object sender, EventArgs e)
{
SetHook();
}
The module handle passed to SetWindowsHookEx should be the handle for your dll, not "user32".

Global Key/MouseHook with UI

I want to make a C# Application with a Keyboard and Mouse on screen.
Every Key or Button that is clicked should be seen in this Application by for example coloring one of the keys ( i know how to do that ). This should also work if the Application is not focused. Currently i am using a global Key- and Mousehook which works fine.
The problem is, the Keyhook does only intercept one Key at a time which means i can only show on Key at a time. I want to be able to show multiple keys at a time on screen.
KeyListeners are unfortunately no option because they dont work outside the Application.
Does anyone has an idea how to make this possible?
Here's the KeyHook i am using:
public class KeyHook
{
private delegate int HookProc(int nCode, IntPtr wParam, IntPtr lParam);
static int hHook = 0;
public static List<Keys> KeyCodes = new List<Keys>();
const int WH_KEYBOARD_LL = 13;
HookProc KeyboardHookProcedure;
[StructLayout(LayoutKind.Sequential)]
private class keyboardHookStruct
{
public int vkCode;
public int scanCode;
public int flags;
public int time;
public int dwExtraInfo;
}
[DllImport("user32.dll", CharSet = CharSet.Auto,
CallingConvention = CallingConvention.StdCall)]
private static extern int SetWindowsHookEx(int idHook, HookProc lpfn,
IntPtr hInstance, int threadId);
[DllImport("user32.dll", CharSet = CharSet.Auto,
CallingConvention = CallingConvention.StdCall)]
private static extern bool UnhookWindowsHookEx(int idHook);
[DllImport("user32.dll", CharSet = CharSet.Auto,
CallingConvention = CallingConvention.StdCall)]
private static extern int CallNextHookEx(int idHook, int nCode,
IntPtr wParam, IntPtr lParam);
[DllImport("kernel32.dll")]
static extern IntPtr LoadLibrary(string lpFileName);
public KeyHook()
{
Hook();
}
~KeyHook()
{
UnHook();
}
public int Hook()
{
KeyboardHookProcedure = new HookProc(KeyHook.KeyboardHookProc);
hHook = SetWindowsHookEx(WH_KEYBOARD_LL, KeyboardHookProcedure, (IntPtr)LoadLibrary("User32"), 0);
return hHook;
}
public bool UnHook()
{
bool ret = UnhookWindowsHookEx(hHook);
if (ret)
hHook = 0;
return ret;
}
private static int KeyboardHookProc(int nCode, IntPtr wParam, IntPtr lParam)
{
if (nCode < 0)
{
return CallNextHookEx(hHook, nCode, wParam, lParam);
}
else
{
if (((int)wParam == 256) || ((int)wParam == 260))
{
keyboardHookStruct MyKeyboardHookStruct = (keyboardHookStruct)Marshal.PtrToStructure(lParam, typeof(keyboardHookStruct));
//Adding Key to a log i use for other stuff
KeyCodes.Add((Keys)MyKeyboardHookStruct.vkCode);
//Code for coloring Key in the UI for pressed Key
}
return CallNextHookEx(hHook, nCode, wParam, lParam);
}
}
}

Read specific key from another application textbox

I need to know when the enter key is pressed on a specific textbox in another application. I'm able to find the textbox and write/read text from it using the user32.dll. But how do I get one specific key?
The application is just a chat. The goal is to when I type on this application textbox something like '/time' and hit enter I want my application to read this command and output the current time, for exemple.
Here is the code I have to retrieve the handle of the application and its textfield child and writing/reading it.
[DllImport("user32.dll")]
public static extern int SendMessage(IntPtr hWnd, int uMsg, IntPtr wParam, string lParam);
[DllImport("user32.dll")]
public static extern int SendMessage(IntPtr hWnd, int msg, int Param, System.Text.StringBuilder text);
[DllImport("user32.dll")]
private static extern IntPtr PostMessage(IntPtr hWnd, uint Msg, IntPtr wParam, IntPtr lParam);
public delegate bool Win32Callback(IntPtr hwnd, IntPtr lParam);
[DllImport("user32.Dll")]
public static extern bool EnumChildWindows(IntPtr parentHandle, Win32Callback callback, IntPtr lParam);
[DllImport("user32.dll")]
static extern int GetClassName(IntPtr hWnd, StringBuilder lpClassName, int nMaxCount);
[DllImport("user32.dll")]
public static extern IntPtr FindWindow(string strClassName, string strWindowName);
private IntPtr handle = IntPtr.Zero;
private string childClassName = "TComboEdit";
public bool findChildHandle(IntPtr hwnd, IntPtr lParam)
{
StringBuilder className = new StringBuilder();
GetClassName(hwnd, className, 120);
if (className.ToString() == childClassName)
{
handle = hwnd;
return false;
}
return true;
}
private void findControl(string className, string title)
{
IntPtr application = IntPtr.Zero;
application = FindWindow(className, title);
if (application == IntPtr.Zero)
MessageBox.Show("Aplicativo não encontrado");
else
EnumChildWindows(application, findChildHandle, IntPtr.Zero);
}
private void setTextToHandle(string msg)
{
SendMessage(handle, 0x000c, IntPtr.Zero, msg); //set text
PostMessage(handle, 0x0100, new IntPtr(0x0D), IntPtr.Zero); // key down (enter)
}
private void getTextFromHandle()
{
StringBuilder t = new StringBuilder();
SendMessage(handle, 0x0D, 100, t); //get text
MessageBox.Show(t.ToString());
}

c# - Keyboardhook on an Outlook Ribbon Control

I want to Hook a specific control (a combobox) and receive all keys typed in that control. The Combobox is part of an Outlook Ribbon an has no events like keypress or something (just onChange which behaves really weird).
Here is the Code:
private const int WH_KEYBOARD_LL = 13;
private const int WM_KEYDOWN = 0x0100;
private LowLevelKeyboardProc _proc;
private IntPtr _hookID = IntPtr.Zero;
private void SetHook(IntPtr handle)
{
uint PID; //not needed
_proc = HookCallback;
uint threadid = GetWindowThreadProcessId(handle, out PID);
_hookID = SetWindowsHookEx(WH_KEYBOARD_LL, _proc, IntPtr.Zero, threadid );
}
private delegate IntPtr LowLevelKeyboardProc(
int nCode, IntPtr wParam, IntPtr lParam);
private IntPtr HookCallback(int nCode, IntPtr wParam, IntPtr lParam)
{
if (nCode >= 0 && wParam == (IntPtr)WM_KEYDOWN)
{
int vkCode = Marshal.ReadInt32(lParam);
System.Diagnostics.Debug.WriteLine("Key: " + (Keys)vkCode);
}
return CallNextHookEx(_hookID, nCode, wParam, lParam);
}
The handle i have and the ThreadID i get are correct (verified via Spy++) but no key is captured. Works fine with "0" as the last parameter of the SetWindowsHookEx function but then its a global hook ofcourse.
I add this for anyone who has the same problem. Keyboardhooks are global, one cannot hook to a specific control. What you need to do is capture the messages of the given handle. To do so, you have to subclass your window/handle.
[DllImport("user32")]
private static extern IntPtr SetWindowLong(IntPtr hWnd, int nIndex, Win32WndProc newProc);
[DllImport("user32")]
private static extern int CallWindowProc(IntPtr lpPrevWndFunc, IntPtr hWnd, int Msg, int wParam, int lParam);
// A delegate that matches Win32 WNDPROC:
private delegate int Win32WndProc(IntPtr hWnd, int Msg, int wParam, int lParam);
// from winuser.h:
private const int GWL_WNDPROC = -4;
private const int WM_KEYDOWN = 0x0100;
// program variables
private IntPtr oldWndProc = IntPtr.Zero;
private Win32WndProc newWndProc = null;
private void SubclassHWnd(IntPtr hWnd)
{
// hWnd is the window you want to subclass..., create a new
// delegate for the new wndproc
newWndProc = new Win32WndProc(MyWndProc);
// subclass
oldWndProc = SetWindowLong(hWnd, GWL_WNDPROC, newWndProc);
}
private const int ENTER_KEY = 1835009;
// this is the new wndproc, just show a messagebox on left button down:
private int MyWndProc(IntPtr hWnd, int Msg, int wParam, int lParam)
{
switch (Msg)
{
case WM_KEYDOWN:
int vkCode = lParam;
if (vkCode == ENTER_KEY)
doSomething();
return 0;
default:
break;
}
return CallWindowProc(oldWndProc, hWnd, Msg, wParam, lParam);
}

Categories

Resources