P/Invoke 32 bit version of a function - c#

I am writing code in C# that employs P/Invoke functions such as NtQuerySystemInformation. However, I notice that this function only returns information pertaining to processes of the same bitness as mine, and I want to get this information from every process on the system. Is there a way that I can invoke both the 32 bit and 64 bit versions of the function, found in ntdll.dll, from the same method?
[DllImport("ntdll.dll")]
private static extern NTStatus NtQueryObject(
IntPtr objectHandle,
ObjectInformationClass informationClass,
IntPtr informationPtr,
uint informationLength,
ref uint returnLength);

Related

Are there any dangers of using Windows API calls in C#

I want to watermark a textbox, and found several different ways of doing it, but one that I liked uses SendMessage and an external DLL. However, I think I heard somewhere that doing it this way can cause BSOD since it isn't managed. Is this true, or is it just hear-say.
http://vidmar.net/weblog/archive/2008/11/05/watermarked-textbox-in-windows-forms-on-.net.aspx
private const uint ECM_FIRST = 0x1500;
private const uint EM_SETCUEBANNER = ECM_FIRST + 1;
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = false)]
static extern IntPtr SendMessage(IntPtr hWnd, uint Msg, uint wParam, [MarshalAs(UnmanagedType.LPWStr)] string lParam);
The short answer is no. It won't cause a BSOD, although it could crash your program.
WinForms is basically built on top of Windows API calls, so when done right, custom API calls should work good as well.
One other thing to keep in mind is that if you do call the Windows API, it may create portability issues, such as when porting to Mono, as those DLLs will most likely not be available.

How to get value from the GetExitCodeProcess

What is the difference between Exitcode and GetExitcodeprocess .Please provide a sample code in C# using GetExitcodeprocess
how can we convert this C++ code to C#
BOOL WINAPI GetExitCodeProcess(
_In_ HANDLE hProcess,
_Out_ LPDWORD lpExitCode
);
GetExitCodeProcess is a Win32 function that retrieves the exit code of a process that is identified by a process handle. You can pinvoke the Win32 function if you have a raw Win32 process handle:
[DllImport("kernel32.dll", SetLastError = true)]
public static extern bool GetExitCodeProcess(IntPtr hProcess, out uint ExitCode);
The managed equivalent in the .net framework is Process.ExitCode.
Unless you have a particular reason to pinvoke the raw Win32 API it is preferable to use Process.ExitCode.

Determining the bitness of an IntPtr instance using EnumChildWindows

I posted a similar question here but decided to re-post focusing on part of the question.
I am enumerating windows using EnumWindows and EnumChildWindows on a 64 bit Windows 7 from a 32 bit WinForms application. Here is the declaration:
public delegate int EnumWindowsCallback (System.IntPtr hWnd, System.IntPtr lParam);
[DllImport("user32.Dll")]
public static extern bool EnumWindows (EnumWindowsCallback lpEnumCallbackFunc, IntPtr lParam);
[DllImport("user32")]
public static extern bool EnumChildWindows (IntPtr hWnd, EnumWindowsCallback lpEnumCallbackFunc, IntPtr lParam);
I send [Process.GetProcesses()[i].MainWindowHandle] as a parameter to [EnumWindows] to enumerate all child windows of all processes.
When [EnumChildWindows] is called, the [hWnd] parameter could be a handle to a window running in a 32 or 64 bit process. Since my app is 32 bit, how can I tell whether to call [hWnd.ToInt32()] or [hWnd.ToInt64()]. I need to call one of the two functions to compare one IntPtr to another.
Context: Windows 7 (64 bit), VS 2010, WinForms (32 bit).
You should not need to do anything special, a hwnd is not a pointer its a HANDLE and for this type 64 bit Windows guarantees that only the lower 32 bits are significant so they can be freely shared.

c# PostMessage not sending and no error

First off,
I'm trying to send keyboard input to a background application(A window that does'nt have focus or might not even appear visible to the user).
I've verified that the winHandle and constants are correct.
Problem is the background application doesn't seem to get the message, UNLESS,
I set a breakpoint on the PostMessage() line, and press F10(step over) or F5(Continue) when it gets there,
then the keystroke magically gets sent.
What gives?
Relevant code:
[DllImport("User32.Dll", EntryPoint = "PostMessageA", SetLastError = true)]
public static extern bool PostMessage(IntPtr hWnd, uint msg, int wParam, int lParam);
PostMessage(winHandle, (uint)WM_KEYDOWN, 66, 0);
Using Win7 64 and MS Visual studio 2008 pro, Console application. And the above code is on a Thread if that helps.
Using Win7 64
That's somewhat relevant, the declaration is wrong. Works in 32-bit mode, but troublesome in 64-bit mode. The last two arguments are pointers, not ints. 8 bytes, not 4. Fix:
[DllImport("User32.Dll", EntryPoint = "PostMessageA", SetLastError = true)]
public static extern bool PostMessage(IntPtr hWnd, uint msg, IntPtr wParam, IntPtr lParam);
PostMessage(winHandle, (uint)WM_KEYDOWN, (IntPtr)66, IntPtr.Zero);
However, this may not actually solve your problem. In x64 mode, the first 4 arguments of a non-instance method are passed in registers, not the stack. It just so happens that this method has 4 arguments, you won't get the PInvokeStackImbalance MDA warning. And the upper 32-bits of the 64-bit register values are often zero by accident so it doesn't matter whether the P/Invoke marshaller generates a 32-bit or a 64-bit argument value.
Beware that this approach is quite troublesome in practice. You cannot control the state of the keyboard in the target process. You are sending the keystroke for B. That may turn into B, b, Alt+B or Ctrl+B, depending on the state of the modifier keys. Only SendInput() can work reliably. Well, short from the window focus problem.

System wide Windows CBT hook not working properly

I'm trying to hook a CBT hook on Windows OSes. I'm currently using Windows 7 x64.
I've read many threads talking about this issue, but none has solved my problem. The application runs well; the hook is installed and I can see some notifications coming.
Actually the problems arised is that the application is not notified about CBT hook of other processes running on the same machine.
The application is written in C# (using Microsoft .NET). Here is a running sample:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.Text;
using System.Threading;
using System.Reflection;
using System.Runtime.InteropServices;
using System.Windows.Forms;
namespace WindowsHook
{
class Program
{
[STAThread]
static void Main(string[] args)
{
uint thid = (uint)AppDomain.GetCurrentThreadId();
bool global = true;
mHookDelegate = Marshal.GetFunctionPointerForDelegate(new HookProc(ManagedCallback));
if (global == true) {
mNativeWrapperInstance = LoadLibrary("Native_x64.dll");
thid = 0;
} else {
using (Process curProcess = Process.GetCurrentProcess())
using (ProcessModule curModule = curProcess.MainModule)
{
mNativeWrapperInstance = GetModuleHandle(curModule.ModuleName);
}
}
mNativeWrappedDelegate = AllocHookWrapper(mHookDelegate);
mHookHandle = SetWindowsHookEx(/*WH_CBT*/5, mNativeWrappedDelegate, mNativeWrapperInstance, thid);
if (mHookHandle == IntPtr.Zero)
throw new Win32Exception(Marshal.GetLastWin32Error());
Application.Run(new Form());
if (FreeHookWrapper(mNativeWrappedDelegate) == false)
throw new Win32Exception("FreeHookWrapper has failed");
if (FreeLibrary(mNativeWrapperInstance) == false)
throw new Win32Exception("FreeLibrary has failed");
if (UnhookWindowsHookEx(mHookHandle) == false)
throw new Win32Exception(Marshal.GetLastWin32Error());
}
static int ManagedCallback(int code, IntPtr wParam, IntPtr lParam)
{
Trace.TraceInformation("Code: {0}", code);
if (code >= 0) {
return (0);
} else {
return (CallNextHookEx(mHookHandle, code, wParam, lParam));
}
}
delegate int HookProc(int code, IntPtr wParam, IntPtr lParam);
static IntPtr mHookHandle;
static IntPtr mHookDelegate;
static IntPtr mNativeWrapperInstance = IntPtr.Zero;
static IntPtr mNativeWrappedDelegate = IntPtr.Zero;
[DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
public static extern IntPtr GetModuleHandle(string lpModuleName);
[DllImport("user32.dll", SetLastError = true)]
private static extern IntPtr SetWindowsHookEx(int hook, IntPtr callback, IntPtr hMod, uint dwThreadId);
[DllImport("user32.dll", SetLastError = true)]
internal static extern bool UnhookWindowsHookEx(IntPtr hhk);
[DllImport("user32.dll")]
internal static extern int CallNextHookEx(IntPtr hhk, int nCode, IntPtr wParam, IntPtr lParam);
[DllImport("kernel32.dll")]
private static extern IntPtr LoadLibrary(string lpFileName);
[DllImport("kernel32.dll", SetLastError = true)]
private static extern bool FreeLibrary(IntPtr hModule);
[DllImport("Native_x64.dll")]
private static extern IntPtr AllocHookWrapper(IntPtr callback);
[DllImport("Native_x64.dll")]
private static extern bool FreeHookWrapper(IntPtr wrapper);
[DllImport("Native_x64.dll")]
private static extern int FreeHooksCount();
}
}
AllocHookWrapper and FreeHookWrapper are imported routines from a DLL (Native_x64.dll) compiler for x64 platform, located at the same directory of the application. AllocHookWrapper stores the function pointer (of the managed routine) and returns the DLL routine calling the function pointer).
Here is the code of the DLL:
#include "stdafx.h"
#include "iGecko.Native.h"
#ifdef _MANAGED
#pragma managed(push, off)
#endif
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#define WRAPPER_NAME(idx) Wrapper ## idx
#define WRAPPER_IMPLEMENTATION(idx) \
LRESULT WINAPI WRAPPER_NAME(idx)(int code, WPARAM wparam, LPARAM lparam) \
{ \
if (sHooksWrapped[idx] != NULL) \
return (sHooksWrapped[idx])(code, wparam, lparam); \
else \
return (0); \
}
#define WRAPPER_COUNT 16
HOOKPROC sHooksWrapped[WRAPPER_COUNT] = { NULL };
WRAPPER_IMPLEMENTATION(0x00);
WRAPPER_IMPLEMENTATION(0x01);
WRAPPER_IMPLEMENTATION(0x02);
WRAPPER_IMPLEMENTATION(0x03);
WRAPPER_IMPLEMENTATION(0x04);
WRAPPER_IMPLEMENTATION(0x05);
WRAPPER_IMPLEMENTATION(0x06);
WRAPPER_IMPLEMENTATION(0x07);
WRAPPER_IMPLEMENTATION(0x08);
WRAPPER_IMPLEMENTATION(0x09);
WRAPPER_IMPLEMENTATION(0x0A);
WRAPPER_IMPLEMENTATION(0x0B);
WRAPPER_IMPLEMENTATION(0x0C);
WRAPPER_IMPLEMENTATION(0x0D);
WRAPPER_IMPLEMENTATION(0x0E);
WRAPPER_IMPLEMENTATION(0x0F);
const HOOKPROC sHookWrappers[] = {
WRAPPER_NAME(0x00),
WRAPPER_NAME(0x01),
WRAPPER_NAME(0x02),
WRAPPER_NAME(0x03),
WRAPPER_NAME(0x04),
WRAPPER_NAME(0x05),
WRAPPER_NAME(0x06),
WRAPPER_NAME(0x07),
WRAPPER_NAME(0x08),
WRAPPER_NAME(0x09),
WRAPPER_NAME(0x0A),
WRAPPER_NAME(0x0B),
WRAPPER_NAME(0x0C),
WRAPPER_NAME(0x0D),
WRAPPER_NAME(0x0E),
WRAPPER_NAME(0x0F)
};
BOOL APIENTRY DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved)
{
return (TRUE);
}
#ifdef _MANAGED
#pragma managed(pop)
#endif
extern "C" IGECKONATIVE_API HOOKPROC WINAPI AllocHookWrapper(HOOKPROC wrapped)
{
for(int i = 0; i < WRAPPER_COUNT; i++) {
if (sHooksWrapped[i] == NULL) {
sHooksWrapped[i] = wrapped;
return sHookWrappers[i];
}
}
return (NULL);
}
extern "C" IGECKONATIVE_API BOOL WINAPI FreeHookWrapper(HOOKPROC wrapper)
{
for(int i = 0; i < WRAPPER_COUNT; i++) {
if (sHookWrappers[i] == wrapper) {
sHooksWrapped[i] = NULL;
return TRUE;
}
}
return (FALSE);
}
extern "C" IGECKONATIVE_API INT WINAPI FreeHooksCount()
{
int c = 0;
for(int i = 0; i < WRAPPER_COUNT; i++) {
if (sHooksWrapped[i] == NULL)
c++;
}
return (c);
}
Actually I'm interested about window related events (creation, destruction) on a certain system, but I'm actually unable to being notified by the OS...
What's going on? What have I missed?
Note that I'm running with the Administratos group.
I've found this interesting section in this page
Global hooks are not supported in the .NET Framework
You cannot implement global hooks in Microsoft .NET Framework. To install a global hook, a hook must have a native DLL export to insert itself in another process that requires a valid, consistent function to call into. This behavior requires a DLL export. The .NET Framework does not support DLL exports. Managed code has no concept of a consistent value for a function pointer because these function pointers are proxies that are built dynamically.
I thought to do the trick by implementing a native DLL containing the hook callback, which calls the managed callback. However, the managed callback is called only in the process which calls the SetWindowsHookEx routine and not called by other processes.
What are the possible workarounds?
Maybe allocating heap memory storing a process id (the managed one), and sending user messages describing the hooked functions?
What I'm trying to achieve is a system wide monitor, which detect new processes executed, detect created windows position and size, as well closed windows, moved windows, minimized/maximized windows. Successively the monitor shall detect mouse and keyboard events (always system-wide) and also it has to "emulate" mouse and keyboard events.
Every process in the same desktop has to be monitored, indepently by the archiveture (32 or 64 bit) and by the underlying framework (native or managed).
The monitor shall force process windows position, size and movements, and shall be able to act as local user in order to allow remote user to act as a local user (something like VNC).
Sorry but I don't understand the sense of "wrapping" unmanaged DLL and usage of ManagedCallback as the hook inside of managed EXE.
You should understand, that the method which you use as the callback of system wide CBT hook (parameter of SetWindowsHookEx) must be loaded in the address space of all process (it will be done a DLL injection of the module where hook function is implemented). In Windows SDK (MSDN) you can read following (see remark on http://msdn.microsoft.com/en-us/library/ms644990(VS.85).aspx):
SetWindowsHookEx can be used to inject
a DLL into another process. A 32-bit
DLL cannot be injected into a 64-bit
process, and a 64-bit DLL cannot be
injected into a 32-bit process. If an
application requires the use of hooks
in other processes, it is required
that a 32-bit application call
SetWindowsHookEx to inject a 32-bit
DLL into 32-bit processes, and a
64-bit application call
SetWindowsHookEx to inject a 64-bit
DLL into 64-bit processes. The 32-bit
and 64-bit DLLs must have different
names.
Moreover you write in your question about system wide hook and use not 0 as the last parameter of SetWindowsHookEx. One more problem: as the third parameter of SetWindowsHookEx (HINSTANCE hMod) you use an instance of not the dll with the code of hook (the code of hook you have currently in the EXE).
So my suggestion: you have to write a new native code for implementation of system wide CBT hook and place it inside a DLL. I recommend you also to choose a base address (linker switch) for the DLL, which is not a standard value to reduce DLL rebasing. It is not mandatory but this will save memory resources.
Sorry for the bad news, but in my opinion your current code should be full rewritten.
UPDATED based on update in the question: One more time I repeat, that if you call in one process SetWindowsHookEx to set a CBT hook, you should give as a parameter the module instance (the start address) of a DLL and the address of a function in the DLL which implement the hook. It is not important from which process you call SetWindowsHookEx function. The DLL used as a parameter will be loaded (injected) in all processes of the same windows station which use User32.dll. So you have some native restrictions. If you want support both 32-bit and 64-bit platforms you have to implement two dlls: one 32-bit and 64-bit DLL. Moreover there are a problem with the usage of different .NET versions in the same process. It should be theoretically possible to do this only with .NET 4.0. In general it is very complex problem. And you should understand it I write about a DLL I mean not only the DLL, but all its dependencies. So if you implement a native DLL which call a managed DLL (.NET DLL) it would be not possible.
So if you want use global CBT hook you have to implement if as a two native DLLs (one 32-bit and 64-bit) and set install the hook inside of two processes (one 32-bit and 64-bit). So do exact what is described in the remark of the SetWindowsHookEx documentation http://msdn.microsoft.com/en-us/library/ms644990(VS.85).aspx (see above quote). I see no more easier ways.

Categories