Related
So I'm trying to make a winapi application by using PInvoke. So far I've been able to open a window, but from there, I can't seem to make the WndProc work. Right now, the application starts, but it won't respond neither to resize, nor to movement or anything, except the hovering above the control buttons.
WindowLL.cs:
public delegate long WndProc(IntPtr hWnd, uint message, byte wParam, long lParam);
public static unsafe class WindowLL
{
[DllImport("user32.dll", CallingConvention = CallingConvention.StdCall, SetLastError = true)]
public static extern ushort RegisterClassExA(ref WNDCLASSEX _class);
[DllImport("user32.dll", CallingConvention = CallingConvention.StdCall, SetLastError = true)]
public static extern IntPtr CreateWindowExA(
uint extraStyle,
ushort className,
//[MarshalAs(UnmanagedType.LPWStr)]
//string className,
[MarshalAs(UnmanagedType.LPStr)]
string title,
uint style,
int x,
int y,
int width,
int height,
IntPtr parent,
IntPtr menu,
IntPtr instance,
IntPtr parameter
);
[DllImport("user32.dll", CallingConvention = CallingConvention.StdCall)]
public static extern bool DestroyWindow(IntPtr hWnd);
[DllImport("user32.dll", CallingConvention = CallingConvention.StdCall, SetLastError = true)]
public static extern bool ShowWindow(IntPtr hWnd, int cmdShow);
[DllImport("user32.dll", CallingConvention = CallingConvention.StdCall)]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool GetMessage(
out MSG lpMsg,
IntPtr hWnd,
uint wMsgFilterMin,
uint wMsgFilterMax
);
[DllImport("user32.dll", CallingConvention = CallingConvention.StdCall)]
public static extern uint DispatchMessage(ref MSG lpMsg);
[DllImport("user32.dll", CallingConvention = CallingConvention.StdCall)]
public static extern uint TranslateMessage(ref MSG lpMsg);
[DllImport("user32.dll", CallingConvention = CallingConvention.StdCall)]
public static extern long DefWindowProcA(
IntPtr hWnd,
uint Msg,
byte wParam,
long lParam
);
}
Structures (split into different files):
[StructLayout(LayoutKind.Sequential)]
public struct MSG
{
public IntPtr hwnd;
public uint message;
public byte wParam;
public long lParam;
public short time;
public POINT pt;
public short lPrivate;
}
[StructLayout(LayoutKind.Sequential)]
public struct POINT
{
public long X;
public long Y;
}
[StructLayout(LayoutKind.Sequential)]
public struct WNDCLASSEX
{
public uint cbSize;
public uint style;
public WndProc lpfnWndProc;
public int cbClsExtra;
public int cbWndExtra;
public IntPtr hInstance;
public IntPtr hIcon;
public IntPtr hCursor;
public IntPtr hbrBackground;
[MarshalAs(UnmanagedType.LPStr)]
public string lpszMenuName;
[MarshalAs(UnmanagedType.LPStr)]
public string lpszClassName;
public IntPtr hIconSm;
}
Program.cs:
class Program
{
static long WndProc(IntPtr hWnd, uint message, byte wParam, long lParam)
{
return WindowLL.DefWindowProcA(hWnd, message, wParam, lParam);
}
static void Main(string[] args)
{
var winCalss = new WNDCLASSEX() {
lpszClassName = "test",
lpfnWndProc = WndProc,
cbSize = (uint)Marshal.SizeOf(typeof(WNDCLASSEX)),
};
var classId = WindowLL.RegisterClassExA(ref winCalss);
var overlapped =
WindowStyle.Overlapped |
WindowStyle.Caption |
WindowStyle.SysMenu |
WindowStyle.ThickFrame |
WindowStyle.MinimizeBox |
WindowStyle.MaximizeBox;
IntPtr hWnd = WindowLL.CreateWindowExA(0,
classId, "test",
(uint)overlapped,
0, 0,
1280, 720,
IntPtr.Zero, IntPtr.Zero,
IntPtr.Zero, IntPtr.Zero
);
WindowLL.ShowWindow(hWnd, (int)NCmdShow.Show);
while (WindowLL.GetMessage(out var msg, hWnd, 0, 0)) {
WindowLL.TranslateMessage(ref msg);
WindowLL.DispatchMessage(ref msg);
}
}
}
Your structures are mostly wrong.
wParam / lParam should both be IntPtr, time should be uint, point x/y should be int.
You don't even need to write them yourself, copy-paste from the framework, MIT license allow that:
https://source.dot.net/#WindowsBase/System/Windows/Interop/MSG.cs,8a0b462145bdb8d8
https://source.dot.net/#PresentationFramework/System/Windows/Standard/NativeMethods.cs,527982c752231945
One more thing. You should not be using A-functions and structures like CreateWindowExA. These are compatibility shims for Windows 95, 98 and Me, all 3 discontinued decades ago. Modern software should only use W-versions. As a nice side effect strings marshalling is way cheaper, C# strings are stored as UTF-16 which matches the encoding expected by W WinApi functions.
I have created a new desktop using CreateDesktop and would like to be able to enumerate all processes within that desktop.
I have tried this:
foreach (Process process in Process.GetProcesses())
{
foreach (ProcessThread processThread in process.Threads)
{
IntPtr hDesk = GetThreadDesktop((uint)processThread.Id);
if (hDesk == desk)
{
// Do something
}
}
}
However, I get Access is denied exception. I can also use
EnumDesktopWindows
However, this doesn't work for command line applications. (I am trying to prevent keyloggers)
Is there any way to get all processes within a desktop?
Thanks
I spent the last hour playing with this and I have it working fine from a console window. The code is messy, but you should be able to make your way through it:
class Program
{
private static class Win32Native
{
[Flags]
public enum CreateDesktopFlags : uint
{
DF_NONE = 0,
DF_ALLOWOTHERACCOUNTHOOK = 1
}
[Flags]
public enum CreateWindowAccessMask : uint
{
DESKTOP_READOBJECTS = 0x0001,
DESKTOP_CREATEWINDOW = 0x0002,
DESKTOP_CREATEMENU = 0x0004,
DESKTOP_HOOKCONTROL = 0x0008,
DESKTOP_JOURNALRECORD = 0x0010,
DESKTOP_JOURNALPLAYBACK = 0x0020,
DESKTOP_ENUMERATE = 0x0040,
DESKTOP_WRITEOBJECTS = 0x0080,
DESKTOP_SWITCHDESKTOP = 0x0100,
DESKTOP_ALL_ACCESS = 0x01FF
}
[Flags]
public enum CreateProcessFlags : uint
{
CREATE_NEW_CONSOLE = 0x00000010,
CREATE_NEW_PROCESS_GROUP = 0x00000200
}
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
public struct STARTUPINFO
{
public int cb;
public string lpReserved;
public string lpDesktop;
public string lpTitle;
public int dwX;
public int dwY;
public int dwXSize;
public int dwYSize;
public int dwXCountChars;
public int dwYCountChars;
public int dwFillAttribute;
public int dwFlags;
public short wShowWindow;
public short cbReserved2;
public IntPtr lpReserved2;
public IntPtr hStdInput;
public IntPtr hStdOutput;
public IntPtr hStdError;
}
[StructLayout(LayoutKind.Sequential)]
public struct PROCESS_INFORMATION
{
public IntPtr hProcess;
public IntPtr hThread;
public int dwProcessId;
public int dwThreadId;
}
[DllImport("user32.dll")]
public static extern IntPtr GetProcessWindowStation();
[return: MarshalAs(UnmanagedType.Bool)]
public delegate bool EnumWindowsProc(IntPtr hWnd, IntPtr lParam);
[return: MarshalAs(UnmanagedType.Bool)]
public delegate bool EnumDesktopProc([MarshalAs(UnmanagedType.LPWStr)] string lpszDesktop, IntPtr lParam);
[DllImport("user32.dll", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool EnumDesktopWindows(IntPtr hDesktop, EnumWindowsProc lpfn, IntPtr lParam);
[DllImport("user32.dll", EntryPoint = "GetWindowTextW", CharSet = CharSet.Unicode)]
public static extern int GetWindowText(IntPtr hWnd, StringBuilder lpString, int nMaxCount);
[DllImport("user32.dll", EntryPoint = "GetClassNameW", CharSet = CharSet.Unicode)]
public static extern int GetClassName(IntPtr hWnd, StringBuilder lpString, int nMaxCount);
[DllImport("user32.dll", SetLastError = true, EntryPoint = "CreateDesktopW", CharSet = CharSet.Unicode)]
public static extern IntPtr CreateDesktop(
string lpszDesktop, IntPtr lpszDevice,
IntPtr pDevMode, CreateDesktopFlags dwFlags,
CreateWindowAccessMask dwDesiredAccess,
IntPtr lpsa);
[DllImport("user32.dll", SetLastError = true, EntryPoint = "EnumDesktopsW", CharSet = CharSet.Unicode)]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool EnumDesktops(IntPtr hwinsta, EnumDesktopProc lpEnumFunc, IntPtr lParam);
[DllImport("user32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool CloseDesktop(IntPtr hDesktop);
[DllImport("kernel32.dll", SetLastError = true, EntryPoint = "CreateProcessW", CharSet = CharSet.Unicode)]
[return:MarshalAs(UnmanagedType.Bool)]
public static extern bool CreateProcess(
string lpApplicationName,
string lpCommandLine,
IntPtr lpProcessAttributes,
IntPtr lpThreadAttributes,
bool bInheritHandles,
CreateProcessFlags dwCreationFlags,
IntPtr lpEnvironment,
string lpCurrentDirectory,
ref STARTUPINFO lpStartupInfo,
out PROCESS_INFORMATION lpProcessInformation);
[DllImport("kernel32.dll")]
[return:MarshalAs(UnmanagedType.Bool)]
public static extern bool CloseHandle(IntPtr hObject);
[DllImport("kernel32.dll")]
[return:MarshalAs(UnmanagedType.Bool)]
public static extern bool TerminateProcess(IntPtr hProcess, uint uExitCode);
}
static int Main(string[] args)
{
StringBuilder sbWndText = new StringBuilder(512),
sbWndClass = new StringBuilder(512);
Console.WriteLine("Trying current desktop:");
if(!Win32Native.EnumDesktopWindows(IntPtr.Zero, (hWnd, lParam) =>
{
Win32Native.GetWindowText(hWnd, sbWndText, sbWndText.Capacity);
Win32Native.GetClassName(hWnd, sbWndClass, sbWndClass.Capacity);
Console.WriteLine($"Found Window: {hWnd} with title \"{sbWndText}\" and class name \"{sbWndClass}\"");
return true;
}, IntPtr.Zero))
{
var error = Marshal.GetLastWin32Error();
Console.WriteLine($"EnumDesktopWindows for current desktop failed with error {error}");
}
Console.WriteLine("Current desktops: ");
Win32Native.EnumDesktops(Win32Native.GetProcessWindowStation(), (desktopName, lParam) =>
{
Console.WriteLine($"Found desktop: {desktopName}");
return true;
}, IntPtr.Zero);
Console.WriteLine("Trying new desktop:");
const string DesktopName = "ANDY DESKTOP NEATO 2";
var hDesktop = Win32Native.CreateDesktop(
DesktopName, IntPtr.Zero, IntPtr.Zero,
Win32Native.CreateDesktopFlags.DF_ALLOWOTHERACCOUNTHOOK,
Win32Native.CreateWindowAccessMask.DESKTOP_ALL_ACCESS,
IntPtr.Zero);
if(hDesktop != IntPtr.Zero)
{
Win32Native.EnumDesktops(Win32Native.GetProcessWindowStation(), (desktopName, lParam) =>
{
Console.WriteLine($"Found desktop: {desktopName}");
return true;
}, IntPtr.Zero);
var si = new Win32Native.STARTUPINFO();
si.cb = Marshal.SizeOf(si);
si.lpDesktop = DesktopName;
var pi = new Win32Native.PROCESS_INFORMATION();
if(!Win32Native.CreateProcess(
null, "cmd.exe", IntPtr.Zero, IntPtr.Zero, false,
Win32Native.CreateProcessFlags.CREATE_NEW_CONSOLE |
Win32Native.CreateProcessFlags.CREATE_NEW_PROCESS_GROUP,
IntPtr.Zero, null, ref si, out pi))
{
var error = Marshal.GetLastWin32Error();
Console.WriteLine($"Unable to create process on new desktop: {error}");
}
Console.WriteLine("WAITING 2 SECONDS FOR PROCESS TO START...");
Thread.Sleep(2000); // breath so the process starts
if (!Win32Native.EnumDesktopWindows(hDesktop, (hWnd, lParam) =>
{
Win32Native.GetWindowText(hWnd, sbWndText, sbWndText.Capacity);
Win32Native.GetClassName(hWnd, sbWndClass, sbWndClass.Capacity);
Console.WriteLine($"Found Window: {hWnd} with title \"{sbWndText}\" and class name \"{sbWndClass}\"");
return true;
}, IntPtr.Zero))
{
var error = Marshal.GetLastWin32Error();
Console.WriteLine($"EnumDesktopWindows for new desktop failed with error {error}");
}
// IMPORTANT: close the processes you start, otherwise you desktop won't self-destruct.
Win32Native.TerminateProcess(pi.hProcess, 42);
Win32Native.CloseHandle(pi.hProcess);
Win32Native.CloseHandle(pi.hThread);
Win32Native.CloseDesktop(hDesktop);
}
else
{
Console.WriteLine($"Unable to create desktop: {Marshal.GetLastWin32Error()}");
}
return 0;
}
}
So the issue I think you were having with EnumDesktopWindows is that when you called CreateDesktop, you didn't ask for sufficient privileges. I set all privileges on (value of 0x1FF) and then EnumDesktopWindows worked for me.
Keep in mind if you call EnumDesktopWindows and there are no windows to enumerate, it will return false with a value of 0 when you call GetLastError.
So what I did to prove that it actually is working is I created a process (cmd.exe) in the new desktop, then called EnumDesktopWindows.
Also keep in mind if you don't destroy all the processes in your new desktop, the desktop will not "self-destruct" and it will be alive until all the processes are destroyed or you logoff/reboot.
I also ran this as a normal user. I didn't need to elevate to administrator to make this work.
However, this doesn't work for command line applications. (I am trying
to prevent keyloggers)
Assume that you want to prevent from hooking keyboard input of the desktop.
Since hook need a message loop to receive keyboard messages, which requires to create a window. So restrict other users to create window application associate to your desktop can prevent them from logging keyboard inputs.
If you want to check the desktop name of a given process to see if it is same with your desktop's name (applied for window application) you can follow these steps:
Call OpenProcess() to get a HANDLE from the target process ID.
Call NtQueryInformationProcess() to retrieve the address of the process's PEB structure.
Call ReadProcessMemory() to read the PEB. It's ProcessParams.DesktopName field contains the name of the workstation/desktop currently associated with the process (there are many more fields available in the PEB.ProcessParams then what MSDN shows).
Refer to "How to get window station for a given process?"
I want to create a new class and then show a window with the specefied class.
I wrote following codes for that :
namespace WindowsFormsApplication1
{
public partial class Form1 : Form
{
[DllImport("user32.dll")]
static extern bool UpdateWindow(IntPtr hWnd);
[DllImport("user32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
static extern bool ShowWindow(IntPtr hWnd, int nCmdShow);
[DllImport("user32.dll", SetLastError = true, EntryPoint = "CreateWindowEx")]
public static extern IntPtr CreateWindowEx(
int dwExStyle,
string lpClassName,
string lpWindowName,
int dwStyle,
int x,
int y,
int nWidth,
int nHeight,
IntPtr hWndParent,
IntPtr hMenu,
IntPtr hInstance,
IntPtr lpParam);
[System.Runtime.InteropServices.DllImport("user32.dll", SetLastError = true)]
static extern System.UInt16 RegisterClassW(
[System.Runtime.InteropServices.In] ref WNDCLASSEX lpWndClass
);
struct WNDCLASSEX
{
[MarshalAs(UnmanagedType.U4)]
public int cbSize;
[MarshalAs(UnmanagedType.U4)]
public int style;
public IntPtr lpfnWndProc; // not WndProc
public int cbClsExtra;
public int cbWndExtra;
public IntPtr hInstance;
public IntPtr hIcon;
public IntPtr hCursor;
public IntPtr hbrBackground;
public string lpszMenuName;
public string lpszClassName;
public IntPtr hIconSm;
}
[DllImport("user32.dll")]
static extern IntPtr DefWindowProc(IntPtr hWnd, uint uMsg, IntPtr wParam, IntPtr lParam);
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
}
private void button1_Click(object sender, EventArgs e)
{
WNDCLASSEX wind_class = new WNDCLASSEX();
wind_class.cbSize = Marshal.SizeOf(typeof(WNDCLASSEX));
wind_class.style = 0x00020000;
wind_class.hbrBackground = (IntPtr) 5;
wind_class.cbClsExtra = 0;
wind_class.cbWndExtra = 0;
wind_class.hInstance = Marshal.GetHINSTANCE(GetType().Module);
wind_class.hIcon = this.Icon.Handle;
wind_class.hCursor = IntPtr.Zero;
wind_class.lpszMenuName = string.Empty;
wind_class.lpszClassName = "MyClass";
wind_class.lpfnWndProc = DefWindowProc(IntPtr.Zero, 0, IntPtr.Zero, IntPtr.Zero);
RegisterClassW(ref wind_class);
IntPtr lolo = CreateWindowEx(0, "MyClass", "MyClass",0,0,0,30,40,IntPtr.Zero,IntPtr.Zero,IntPtr.Zero,IntPtr.Zero);
ShowWindow(lolo, 1);
UpdateWindow(lolo);
}
}
}
But it isn't working correctly.
It doesn't show the window. when i search with Spy++ by my class name , It cant find any results..
I searched in web and do some edits in my code but they didn't work.
Where is my Problem !?
Regards.
Plain-vanilla Win32 is no fun from Win32 C, and it is much less fun from .NET. But anyway, it may be useful in rare cases. Here comes a C# class which should do what you want.
First, a general remarks on your software. In Win32, you should always check the return codes of the system calls, and in case of an error, call GetLastError() to get a more detailed information about the failure. If you had checked the result of the RegisterClass function and it failed, you would have known that it is useless to continue without having fixed that one.
The following is a class which may be used as template for further studies and which should successfully register and create a resizable window. Additionally some simple actions like doubleclick are processed in a custom Window procedure. For some parts of the code credit goes to this site being one of the very few I found in the web presenting something working.
The CreateWindowEx is tricky, because you must NOT put in a string as class name, but the result of the RegisterClassEx. The used constants are found mainly in the C-header file winuser.h. To be able to do something useful with this method, the main painting has to be done "by hand", being a cumbersome and tedious work by manipulationg Device Contexts properly. Of course, all this does not show up in the following example. The "create" method of the class may be called e.g. from a Windows Form button click. The namespace name is of course arbitrarily selected. The WinForm project is x86 32-bit, .NET 4.0.
Have fun!
namespace Win32FromForms
{
delegate IntPtr WndProc(IntPtr hWnd, uint msg, IntPtr wParam, IntPtr lParam);
class Win32Window
{
const UInt32 WS_OVERLAPPEDWINDOW = 0xcf0000;
const UInt32 WS_VISIBLE = 0x10000000;
const UInt32 CS_USEDEFAULT = 0x80000000;
const UInt32 CS_DBLCLKS = 8;
const UInt32 CS_VREDRAW = 1;
const UInt32 CS_HREDRAW = 2;
const UInt32 COLOR_WINDOW = 5;
const UInt32 COLOR_BACKGROUND = 1;
const UInt32 IDC_CROSS = 32515;
const UInt32 WM_DESTROY = 2;
const UInt32 WM_PAINT = 0x0f;
const UInt32 WM_LBUTTONUP = 0x0202;
const UInt32 WM_LBUTTONDBLCLK = 0x0203;
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
struct WNDCLASSEX
{
[MarshalAs(UnmanagedType.U4)]
public int cbSize;
[MarshalAs(UnmanagedType.U4)]
public int style;
public IntPtr lpfnWndProc;
public int cbClsExtra;
public int cbWndExtra;
public IntPtr hInstance;
public IntPtr hIcon;
public IntPtr hCursor;
public IntPtr hbrBackground;
public string lpszMenuName;
public string lpszClassName;
public IntPtr hIconSm;
}
private WndProc delegWndProc = myWndProc;
[DllImport("user32.dll")]
static extern bool UpdateWindow(IntPtr hWnd);
[DllImport("user32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
static extern bool ShowWindow(IntPtr hWnd, int nCmdShow);
[System.Runtime.InteropServices.DllImport("user32.dll", SetLastError = true)]
static extern bool DestroyWindow(IntPtr hWnd);
[DllImport("user32.dll", SetLastError = true, EntryPoint = "CreateWindowEx")]
public static extern IntPtr CreateWindowEx(
int dwExStyle,
UInt16 regResult,
//string lpClassName,
string lpWindowName,
UInt32 dwStyle,
int x,
int y,
int nWidth,
int nHeight,
IntPtr hWndParent,
IntPtr hMenu,
IntPtr hInstance,
IntPtr lpParam);
[DllImport("user32.dll", SetLastError = true, EntryPoint = "RegisterClassEx")]
static extern System.UInt16 RegisterClassEx([In] ref WNDCLASSEX lpWndClass);
[DllImport("kernel32.dll")]
static extern uint GetLastError();
[DllImport("user32.dll")]
static extern IntPtr DefWindowProc(IntPtr hWnd, uint uMsg, IntPtr wParam, IntPtr lParam);
[DllImport("user32.dll")]
static extern void PostQuitMessage(int nExitCode);
//[DllImport("user32.dll")]
//static extern sbyte GetMessage(out MSG lpMsg, IntPtr hWnd, uint wMsgFilterMin,
// uint wMsgFilterMax);
[DllImport("user32.dll")]
static extern IntPtr LoadCursor(IntPtr hInstance, int lpCursorName);
[DllImport("user32.dll")]
static extern bool TranslateMessage([In] ref MSG lpMsg);
[DllImport("user32.dll")]
static extern IntPtr DispatchMessage([In] ref MSG lpmsg);
internal bool create()
{
WNDCLASSEX wind_class = new WNDCLASSEX();
wind_class.cbSize = Marshal.SizeOf(typeof(WNDCLASSEX));
wind_class.style = (int)(CS_HREDRAW | CS_VREDRAW | CS_DBLCLKS ) ; //Doubleclicks are active
wind_class.hbrBackground = (IntPtr) COLOR_BACKGROUND +1 ; //Black background, +1 is necessary
wind_class.cbClsExtra = 0;
wind_class.cbWndExtra = 0;
wind_class.hInstance = Marshal.GetHINSTANCE(this.GetType().Module); ;// alternative: Process.GetCurrentProcess().Handle;
wind_class.hIcon = IntPtr.Zero;
wind_class.hCursor = LoadCursor(IntPtr.Zero, (int)IDC_CROSS);// Crosshair cursor;
wind_class.lpszMenuName = null;
wind_class.lpszClassName = "myClass";
wind_class.lpfnWndProc = Marshal.GetFunctionPointerForDelegate(delegWndProc);
wind_class.hIconSm = IntPtr.Zero;
ushort regResult = RegisterClassEx(ref wind_class);
if (regResult == 0)
{
uint error = GetLastError();
return false;
}
string wndClass = wind_class.lpszClassName;
//The next line did NOT work with me! When searching the web, the reason seems to be unclear!
//It resulted in a zero hWnd, but GetLastError resulted in zero (i.e. no error) as well !!??)
//IntPtr hWnd = CreateWindowEx(0, wind_class.lpszClassName, "MyWnd", WS_OVERLAPPEDWINDOW | WS_VISIBLE, 0, 0, 30, 40, IntPtr.Zero, IntPtr.Zero, wind_class.hInstance, IntPtr.Zero);
//This version worked and resulted in a non-zero hWnd
IntPtr hWnd = CreateWindowEx(0, regResult, "Hello Win32", WS_OVERLAPPEDWINDOW | WS_VISIBLE, 0, 0, 300, 400, IntPtr.Zero, IntPtr.Zero, wind_class.hInstance, IntPtr.Zero);
if (hWnd == ((IntPtr)0))
{
uint error = GetLastError();
return false;
}
ShowWindow(hWnd, 1);
UpdateWindow(hWnd);
return true;
//The explicit message pump is not necessary, messages are obviously dispatched by the framework.
//However, if the while loop is implemented, the functions are called... Windows mysteries...
//MSG msg;
//while (GetMessage(out msg, IntPtr.Zero, 0, 0) != 0)
//{
// TranslateMessage(ref msg);
// DispatchMessage(ref msg);
//}
}
private static IntPtr myWndProc(IntPtr hWnd, uint msg, IntPtr wParam, IntPtr lParam)
{
switch (msg)
{
// All GUI painting must be done here
case WM_PAINT:
break;
case WM_LBUTTONDBLCLK :
MessageBox.Show("Doubleclick");
break;
case WM_DESTROY:
DestroyWindow(hWnd);
//If you want to shutdown the application, call the next function instead of DestroyWindow
//PostQuitMessage(0);
break;
default:
break;
}
return DefWindowProc(hWnd, msg, wParam, lParam);
}
}
}
The problem is the marshaling of strings to LPStr, if you do it like this then the class name works:
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
struct WNDCLASSEX
{
[MarshalAs(UnmanagedType.U4)]
public int cbSize;
[MarshalAs(UnmanagedType.U4)]
public int style;
public IntPtr lpfnWndProc;
public int cbClsExtra;
public int cbWndExtra;
public IntPtr hInstance;
public IntPtr hIcon;
public IntPtr hCursor;
public IntPtr hbrBackground;
[MarshalAs(UnmanagedType.LPStr)]
public string lpszMenuName;
[MarshalAs(UnmanagedType.LPStr)]
public string lpszClassName;
public IntPtr hIconSm;
}
[DllImport("user32.dll", SetLastError = true, EntryPoint = "CreateWindowEx")]
public static extern IntPtr CreateWindowEx(
int dwExStyle,
//UInt16 regResult,
[MarshalAs(UnmanagedType.LPStr)]
string lpClassName,
[MarshalAs(UnmanagedType.LPStr)]
string lpWindowName,
UInt32 dwStyle,
int x,
int y,
int nWidth,
int nHeight,
IntPtr hWndParent,
IntPtr hMenu,
IntPtr hInstance,
IntPtr lpParam);
I've tried to send text messages to various applications in Windows 7 (eg. Notepad++, Notepad etc.). SendMessage is working fine for Notepad but not for Notepad++.
If i'm sending text to Notepad everything appears fine, whole text and i'm getting 1 as return from SendMessage method. But for Notepad++ only first letter appears and method SendMessage is returning 0, however Marshal.GetLastWin32Error() is not returning any error (result 0)?
Here's the code:
GUITHREADINFO gti = new GUITHREADINFO();
IntPtr hWnd = GetForegroundWindow();
uint processId;
uint activeThreadId = GetWindowThreadProcessId(hWnd, out processId);
if (GetInfo(activeThreadId, out gti))
{
int EM_REPLACESEL = 0x00C2;
int error = Marshal.GetLastWin32Error();
int result = SendMessageW(gti.hwndCaret, EM_REPLACESEL, -1, passed);//3rd param doesn't change anything
error = Marshal.GetLastWin32Error();
}
WinAPI functions and GetInfo method as long with required structures are defined as:
[DllImport("User32.dll", EntryPoint = "SendMessageW", SetLastError = true, CharSet = CharSet.Unicode)]
public static extern int SendMessageW(IntPtr hWnd, int uMsg, int wParam, string lParam);
[DllImport("user32.dll")]
static extern IntPtr GetForegroundWindow();
[DllImport("user32.dll", SetLastError = true)]
static extern uint GetWindowThreadProcessId(IntPtr hWnd, out uint lpdwProcessId);
//"Borrowed" code
public static bool GetInfo(uint hwnd, out GUITHREADINFO lpgui)
{
uint lpdwProcessId;
uint threadId = GetWindowThreadProcessId(hwnd, out lpdwProcessId);
lpgui = new GUITHREADINFO();
lpgui.cbSize = Marshal.SizeOf(lpgui);
return GetGUIThreadInfo(threadId, ref lpgui);
}
[StructLayout(LayoutKind.Sequential)]
public struct RECT
{
public int iLeft;
public int iTop;
public int iRight;
public int iBottom;
}
[StructLayout(LayoutKind.Sequential)]
public struct GUITHREADINFO
{
public int cbSize;
public int flags;
public IntPtr hwndActive;
public IntPtr hwndFocus;
public IntPtr hwndCapture;
public IntPtr hwndMenuOwner;
public IntPtr hwndMoveSize;
public IntPtr hwndCaret;
public RECT rectCaret;
}
So well i wonder what should i do to fix it so it would work (fully) for all windows not only for edit control in Notepad?
i have a standalone public kiosk pc that startups automatically everyday. It is connected to a HD TV and sometimes it is not detected. i have to personally go down to the PC, go to Screen Resolution and press Detect which it works.
my question is how do i know if the monitor i want it to display is connected properly in code?
thanks
I did manage to find some code on the MSDN site where a user is using code to determine which type of monitor is connected. I hope this may be a good starting point for you.
using System;
using System.Runtime.InteropServices;
using System.Windows;
using System.Windows.Interop;
namespace CRT
{
/// <summary>
/// Interaction logic for Window1.xaml
/// </summary>
public partial class Window1 : Window
{
public class NativeMethods
{
[DllImport("user32.dll", EntryPoint = "MonitorFromWindow", SetLastError = true)]
public static extern IntPtr MonitorFromWindow(
[In] IntPtr hwnd, uint dwFlags);
[DllImport("dxva2.dll", EntryPoint = "GetNumberOfPhysicalMonitorsFromHMONITOR", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool GetNumberOfPhysicalMonitorsFromHMONITOR(
IntPtr hMonitor, ref uint pdwNumberOfPhysicalMonitors);
[DllImport("dxva2.dll", EntryPoint = "GetPhysicalMonitorsFromHMONITOR", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool GetPhysicalMonitorsFromHMONITOR(
IntPtr hMonitor,
uint dwPhysicalMonitorArraySize,
[Out] NativeStructures.PHYSICAL_MONITOR[] pPhysicalMonitorArray);
[DllImport("dxva2.dll", EntryPoint = "DestroyPhysicalMonitors", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool DestroyPhysicalMonitors(
uint dwPhysicalMonitorArraySize, [Out] NativeStructures.PHYSICAL_MONITOR[] pPhysicalMonitorArray);
[DllImport("dxva2.dll", EntryPoint = "GetMonitorTechnologyType", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool GetMonitorTechnologyType(
IntPtr hMonitor, ref NativeStructures.MC_DISPLAY_TECHNOLOGY_TYPE pdtyDisplayTechnologyType);
[DllImport("dxva2.dll", EntryPoint = "GetMonitorCapabilities", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool GetMonitorCapabilities(
IntPtr hMonitor, ref uint pdwMonitorCapabilities, ref uint pdwSupportedColorTemperatures);
}
public class NativeConstants
{
public const int MONITOR_DEFAULTTOPRIMARY = 1;
public const int MONITOR_DEFAULTTONEAREST = 2;
public const int MONITOR_DEFAULTTONULL = 0;
}
public class NativeStructures
{
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
public struct PHYSICAL_MONITOR
{
public IntPtr hPhysicalMonitor;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 128)] public string szPhysicalMonitorDescription;
}
public enum MC_DISPLAY_TECHNOLOGY_TYPE
{
MC_SHADOW_MASK_CATHODE_RAY_TUBE,
MC_APERTURE_GRILL_CATHODE_RAY_TUBE,
MC_THIN_FILM_TRANSISTOR,
MC_LIQUID_CRYSTAL_ON_SILICON,
MC_PLASMA,
MC_ORGANIC_LIGHT_EMITTING_DIODE,
MC_ELECTROLUMINESCENT,
MC_MICROELECTROMECHANICAL,
MC_FIELD_EMISSION_DEVICE,
}
}
public Window1() { InitializeComponent(); }
private void Button_Click(object sender, RoutedEventArgs e)
{
WindowInteropHelper helper = new WindowInteropHelper(this);
IntPtr hMonitor = NativeMethods.MonitorFromWindow(helper.Handle, NativeConstants.MONITOR_DEFAULTTOPRIMARY);
int lastWin32Error = Marshal.GetLastWin32Error();
uint pdwNumberOfPhysicalMonitors = 0u;
bool numberOfPhysicalMonitorsFromHmonitor = NativeMethods.GetNumberOfPhysicalMonitorsFromHMONITOR(
hMonitor, ref pdwNumberOfPhysicalMonitors);
lastWin32Error = Marshal.GetLastWin32Error();
NativeStructures.PHYSICAL_MONITOR[] pPhysicalMonitorArray =
new NativeStructures.PHYSICAL_MONITOR[pdwNumberOfPhysicalMonitors];
bool physicalMonitorsFromHmonitor = NativeMethods.GetPhysicalMonitorsFromHMONITOR(
hMonitor, pdwNumberOfPhysicalMonitors, pPhysicalMonitorArray);
lastWin32Error = Marshal.GetLastWin32Error();
uint pdwMonitorCapabilities = 0u;
uint pdwSupportedColorTemperatures = 0u;
var monitorCapabilities = NativeMethods.GetMonitorCapabilities(
pPhysicalMonitorArray[0].hPhysicalMonitor, ref pdwMonitorCapabilities, ref pdwSupportedColorTemperatures);
lastWin32Error = Marshal.GetLastWin32Error();
NativeStructures.MC_DISPLAY_TECHNOLOGY_TYPE type =
NativeStructures.MC_DISPLAY_TECHNOLOGY_TYPE.MC_SHADOW_MASK_CATHODE_RAY_TUBE;
var monitorTechnologyType = NativeMethods.GetMonitorTechnologyType(
pPhysicalMonitorArray[0].hPhysicalMonitor, ref type);
lastWin32Error = Marshal.GetLastWin32Error();
var destroyPhysicalMonitors = NativeMethods.DestroyPhysicalMonitors(
pdwNumberOfPhysicalMonitors, pPhysicalMonitorArray);
lastWin32Error = Marshal.GetLastWin32Error();
this.lbl.Content = type;
}
}
}