C# Handle without a form - c#

Im trying to get my program to send messages to control volume but I need a handle.
I currently tried to use broadcast as seen below in the current code but that would cause all processes to send a message causing volume to go up to 100 or 0 and freezing the program. Ive tried using Process.GetCurrentProcess().MainWindowHandle; but that only works if I have a form or command prompt. Note I wish to have this program work using my a modification of my current code.
using System;
using System.Windows.Forms;
using System.Runtime.InteropServices;
using System.Diagnostics;
namespace Utilities
{
static class VolumeMessage
{
private const int APPCOMMAND_VOLUME_MUTE = 0x80000;
private const int APPCOMMAND_VOLUME_UP = 0xA0000;
private const int APPCOMMAND_VOLUME_DOWN = 0x90000;
private const int WM_APPCOMMAND = 0x319;
private static IntPtr Handle = (IntPtr)0xffff;
[DllImport("user32.dll")]
public static extern IntPtr SendMessageW(IntPtr hWnd, int Msg,
IntPtr wParam, IntPtr lParam);
public static void Mute()
{
SendMessageW(Handle, WM_APPCOMMAND, Handle,
(IntPtr)APPCOMMAND_VOLUME_MUTE);
}
public static void volumeDown()
{
SendMessageW(Handle, WM_APPCOMMAND, Handle,
(IntPtr)APPCOMMAND_VOLUME_DOWN);
}
public static void volumeUp()
{
SendMessageW(Handle, WM_APPCOMMAND, Handle,
(IntPtr)APPCOMMAND_VOLUME_UP);
}
}
}

You can use
var handle = Process.GetProcessesByName("explorer").First().MainWindowHandle;
Note that for the second parameter you can pass IntPtr.Zero
BTW I faced the same problem, also with mute/volume control...

I think you sometimes just need a form to get windows messages working right, so create one and make it always hidden. We've had to so this previously for something along these lines.

If you really want to do it this way then you could send it to the desktop hwnd I believe. From memory there is an API to get this hwnd which is just something like GetDesktopWindow or something like that.
However there has got to be a better way. Surely an API exists to directly control the volume.

Related

How to get window handler (of another program) from Process ID or Process Name?

I'm making a program to show another program fullscreen programmatically. To do this, I use MoveWindow() from WinAPI, but it needs a Window Handler. I tried to get it using FindWindow(), but since it uses the window name, I often had situations where the name was in a different language and it didn't work (or it didn't exist at all). So now I need to somehow get the Window Handler of the desired program by PID or even more conveniently by the name of the process. In C++, I found EnumWindows(), but I completely don't understand how to rewrite it in C#.
Question: How do I get the Window Handler using the PID or the program name?
Use EnumWindows to enumerate the handles of all windows and pass the window handle as a parameter to the GetWindowThreadProcessId function.
After obtaining the pid, compare the value with the pid of another program you provided. If it is the same, use MoveWindow to move it.
C# example:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime;
using System.Runtime.InteropServices;
using System.Diagnostics;
namespace EnumPTW
{
class Program
{
[DllImport("user32.dll", SetLastError = true)]
static extern uint GetWindowThreadProcessId(IntPtr hWnd, out uint lpdwProcessId);
// Callback Declaration
public delegate bool EnumWindowsCallback(IntPtr hwnd, int lParam);
[DllImport("user32.dll")]
private static extern int EnumWindows(EnumWindowsCallback callPtr, int lParam);
[DllImport("user32.dll", SetLastError = true)]
internal static extern bool MoveWindow(IntPtr hWnd, int X, int Y, int nWidth, int nHeight, bool bRepaint);
public static bool ReportWindow(IntPtr hwnd, int lParam)
{
uint processId = 0;
uint threadId = GetWindowThreadProcessId(hwnd, out processId);
if(processId == 23272) //23272: another program pid
{
Console.WriteLine(string.Format("Enumerated Window Handle 0x{0:X8}, Process {1}, Thread {2}", hwnd.ToInt32(), processId, threadId));
MoveWindow(hwnd, 100, 100, 800, 600, true);
}
return true;
}
static void Main(string[] args)
{
// Have to declare a delegate so that a thunk is created, so that win32 may call us back.
EnumWindowsCallback callBackFn = new EnumWindowsCallback(ReportWindow);
EnumWindows(callBackFn, 0);
Console.WriteLine("Finished. Press any key to continue.");
Console.ReadKey();
}
}
}
You can also use OpenProcess to get the handle of the process based on the pid, then use GetModuleFileNameEx to get the name of the process, and then compare the name with the process name you provided.
Sample: The using of OpenProcess and GetModuleFileNameEx

Turn Monitor completely off (not Standby) programmatically [duplicate]

Is it programmatically possible to turn a monitor on/off through code (C#)?
Did you even try googling it?
First hit:
http://www.codeproject.com/KB/cs/Monitor_management_guide.aspx
I am not surprised you need to use some DLL's supplied by Windows.
(I guessed you needed a C# solution, because that's the only tag you applied).
EDIT February 8th 2013:
It was mentioned that the solution no longer worked under Windows 7 en 8. Well here is one that works nicely under Windows 7, haven't tried Windows 8 yet.
http://cocoa.ninja/posts/Turn-off-your-monitor-in-Csharp.html
namespace MonitorOff {
public enum MonitorState {
MonitorStateOn = -1,
MonitorStateOff = 2,
MonitorStateStandBy = 1
}
public partial class Form1 : Form {
[DllImport("user32.dll")]
private static extern int SendMessage(int hWnd, int hMsg, int wParam, int lParam);
public Form1() {
InitializeComponent();
SystemEvents.SessionSwitch += SystemEvents_SessionSwitch;
}
void SystemEvents_SessionSwitch(object sender, SessionSwitchEventArgs e) {
SetMonitorInState(MonitorState.MonitorStateOff);
}
private void button1_Click(object sender, EventArgs e) {
SetMonitorInState(MonitorState.MonitorStateOff);
}
private void SetMonitorInState(MonitorState state) {
SendMessage(0xFFFF, 0x112, 0xF170, (int)state);
}
}
}
The answer https://stackoverflow.com/a/713504/636189 above works great for turning off a Windows 7/8 monitor but not for waking it up. On those systems you'll need to do something hackish like this (as found https://stackoverflow.com/a/14171736/636189):
[DllImport("user32.dll")]
static extern void mouse_event(Int32 dwFlags, Int32 dx, Int32 dy, Int32 dwData, UIntPtr dwExtraInfo);
private const int MOUSEEVENTF_MOVE = 0x0001;
private void Wake(){
mouse_event(MOUSEEVENTF_MOVE, 0, 1, 0, UIntPtr.Zero);
Sleep(40);
mouse_event(MOUSEEVENTF_MOVE, 0, -1, 0, UIntPtr.Zero);
}
Press the on/off button
If you want to do it in code, apparently this is possible in the Win32 API:
SendMessage hWnd, WM_SYSCOMMAND, SC_MONITORPOWER, param
where WM_SYSCOMMAND = 0x112 and
SC_MONITORPOWER = 0xF170 and
param indicates the mode to put the monitor in:
-1 : on
2 : off
1 : energy saving mode
hWnd can be a handle for any window - so if you have a Form, something like this should work
int WM_SYSCOMMAND = 0x112;
int SC_MONITORPOWER = 0xF170;
[DllImport("user32.dll", CharSet = CharSet.Auto)]
private static extern int SendMessage(IntPtr hWnd, int wMsg, IntPtr wParam, IntPtr lParam);
public static void Main(string[] args)
{
Form f = new Form();
bool turnOff = true; //set true if you want to turn off, false if on
SendMessage(f.Handle, WM_SYSCOMMAND, (IntPtr)SC_MONITORPOWER, (IntPtr)(turnOff ? 2 : -1));
}
Note I haven't actually tried this...
For who wants this functionality on a console application:
using System;
using System.Runtime.InteropServices;
using System.Timers;
namespace TurnScreenOFF
{
class Program
{
private static int WM_SYSCOMMAND = 0x0112;
private static uint SC_MONITORPOWER = 0xF170;
public static void Main(string[] args)
{
SendMessage(GetConsoleWindow(), WM_SYSCOMMAND, (IntPtr)SC_MONITORPOWER, (IntPtr)2);
}
[DllImport("kernel32.dll")]
static extern IntPtr GetConsoleWindow();
[DllImport("user32.dll", CharSet = CharSet.Auto)]
private static extern int SendMessage(IntPtr hWnd, int wMsg, IntPtr wParam, IntPtr lParam);
}
}
Adaptated and tested. 100% working on Windows 8.
This code can be useful for turning on and turning off.. It worked in Windows 7 also.
private int SC_MONITORPOWER = 0xF170;
private uint WM_SYSCOMMAND = 0x0112;
[DllImport("user32.dll")]
static extern IntPtr SendMessage(IntPtr hWnd, uint Msg, IntPtr wParam, IntPtr lParam);
enum MonitorState
{
ON = -1,
OFF = 2,
STANDBY = 1
}
private void SetMonitorState(MonitorState state)
{
Form frm = new Form();
SendMessage(frm.Handle, WM_SYSCOMMAND, (IntPtr)SC_MONITORPOWER, (IntPtr)state);
}
For calling the function you must do like:
SetMonitorState(MonitorState.ON);
OR
SetMonitorState(MonitorState.OFF);
Note: This code tested in WPF Application. With the below namespaces:
using System.Runtime.InteropServices;
using System.Windows.Forms;
I could not find a copy paste example, so created one myself, dont forget to add a reference to System.Windows.Forms.
using System;
using System.Runtime.InteropServices;
using System.Threading;
using System.Windows.Forms;
namespace monitor_on_off
{
class Program
{
[DllImport("user32.dll")]
static extern IntPtr SendMessage(IntPtr hWnd, int msg, IntPtr wParam, IntPtr lParam);
[DllImport("user32.dll")]
static extern void mouse_event(Int32 dwFlags, Int32 dx, Int32 dy, Int32 dwData, UIntPtr dwExtraInfo);
private const int WmSyscommand = 0x0112;
private const int ScMonitorpower = 0xF170;
private const int MonitorShutoff = 2;
private const int MouseeventfMove = 0x0001;
public static void MonitorOff(IntPtr handle)
{
SendMessage(handle, WmSyscommand, (IntPtr)ScMonitorpower, (IntPtr)MonitorShutoff);
}
private static void MonitorOn()
{
mouse_event(MouseeventfMove, 0, 1, 0, UIntPtr.Zero);
Thread.Sleep(40);
mouse_event(MouseeventfMove, 0, -1, 0, UIntPtr.Zero);
}
static void Main()
{
var form = new Form();
while (true)
{
MonitorOff(form.Handle);
Thread.Sleep(5000);
MonitorOn();
Thread.Sleep(5000);
}
}
}
}
I have gone through every single method that everyone has published for putting a monitor to sleep and waking it later at some other time. Granted the SendMessage() does work with Windows XP but it doesn't wake the monitor after the monitor has been a sleep for a period of time. I have tried using C#, DOS, scripts for playing with power profiles, and Powershell. Eventually I gave up and went back to the beginning and my first thought was proven correct. You need to use the PostMessage() after the monitor has been turned off, better yet, you should probably always use PostMessage();
So all the code that you have seen before is correct, instead use the following:
using System.Runtime.InteropServices;
[DllImport("user32.dll")]
static extern IntPtr PostMessage(int hWnd, int msg, int wParam, int lParam);
PostMessage(-1, WM_SYSCOMMAND, SC_MONITORPOWER, MONITOR_OFF);
At this time of execution and working appropriately (May 11, 2015) I am running
Windows 7 Professional Version 6.1.7601 Service Pack 1 Build 7601
Visual Studio Profesional 2013 Version 12.0.31101.00 Update 4
.NET Framework 4.5.51209
C#
My system is completely up to date.
The answer with the least SLOC:
using System;
using System.Windows.Forms;
using System.Runtime.InteropServices;
static class Program
{
[DllImport("user32.dll")]
static extern IntPtr SendMessage(IntPtr hWnd, uint Msg, int wParam, int lParam);
[STAThread]
static void Main()
{
SendMessage(new Form().Handle, 0x0112, 0xF170, 2);
}
}
For Windows 10 (tested on Pro 64 bits), I was able to turn off the monitor using the SendMessage() technique mentioned in this page.
However, impossible for me to turn the monitor back on: the "mouse move" trick did not work, the SendMessage() technique would turn the screen back on for one second then back off and using PostMessage() did not change anything.
But the trick is in fact really simple, all I had to do was simulate a keypress with SendKeys(). I'm using ALT here because in itself it has no impact on the system but it could be any other key.
SendKeys.SendWait("%");
If you're not using Windows.Forms, sending "ALT" also works using SendInput() but it's longer to implement.

What is/how do I use HFont in C#

I'm working with a printer SDK for a label printer in C#, details of which can be found here:
https://stackoverflow.com/questions/18083309/getting-a-printer-api-to-work-with-c-sharp
Taking the advice given there, I used PInvoke to get the functions in the DLLs to work, and to my surprise, it all has began to come together...mostly.
A function SlpDrawTextXY() is supposed to be able to take an argument for a font of the type Hfont. This can be created by a function called SlpCreateFont(). (details of these methods on pages 21 and 19 respectively of the documentation).
Now, my quest to discover what Hfont actually is has went poorly. MSDN mentions it a bit, but doesn't really tell me what it is exactly. The articles provided aren't really useful if you are going in blind and are definitely more suited to someone who is already half way there. Other documentation about it is really slim and I'm left guessing at what the hell is supposed to be happening.
I have a block of code that looks like this:
public partial class Form1 : Form
{
[DllImport("SlpApi7x32.dll")]
static extern void SlpDebugMode(int nMode);
[DllImport("SlpApi7x32.dll")]
static extern int SlpOpenPrinter(String strPrinterName, int nID, bool fPortrait);
[DllImport("SlpApi7x32.dll")]
static extern void SlpClosePrinter();
[DllImport("SlpApi7x32.dll")]
static extern bool SlpStartLabel();
[DllImport("SlpApi7x32.dll")]
static extern void SlpDrawTextXY(int x, int y, Font iFont, String lpText);
[DllImport("SlpApi7x32.dll")]
static extern bool SlpEndLabel();
[DllImport("SlpApi7x32.dll")]
static extern Font SlpCreateFont(String lpName, int nPoints, int nAttributes);
[DllImport("GDI32.dll")]
public static extern bool DeleteObject(IntPtr objectHandle);
public Form1()
{
InitializeComponent();
}
private void print_Click(object sender, EventArgs e)
{
//Font myFont = new Font("Arial", 12);
//IntPtr hFont = myFont.ToHfont();
SlpDebugMode(2);
SlpOpenPrinter("Smart Label Printer 440", 1, false);
{
SlpStartLabel();
//Font font = SlpCreateFont("Courier", 12, 0);
SlpDrawTextXY(30, 30, null, "Hello World!");
SlpEndLabel();
}
SlpClosePrinter();
}
}
There are some remnants of my toying around that have been commented out. If it's commented out, it doesn't work.
This code will actually go to the printer and will 'print' a blank label, so it does seem like I'm really close. The third argument in SlpDrawTextXY is where the font is supposed to be though and I have it set as 'null' just to see if I can get past it successfully. This code is based on the sample C code in the documentation on page 12. I would like to be able to transform this code into something that actually prints text.
[DllImport("SlpApi7x32.dll")]
static extern Font SlpCreateFont(...)
Using Font is not correct here. SlpCreateFont() returns a HFONT, a "handle to font". It is the way you manipulate a font when you create one in unmanaged code. And is the exact same kind of animal you get back from the Font.ToHfont() method. So you must declare it the way ToHfont() returns it, it must be IntPtr in your declarations. Update the other declarations accordingly.
Do note that you'll have some decent odds that you can use Font.ToHfont() instead of SlpCreateFont(). The rules are the same however, you must be sure to call DeleteObject() when you are done using the font or you'll leak GDI objects that eventually will crash your code.
Hans was absolutely right. For future reference, below is working code:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.Runtime.InteropServices;
namespace SSLP
{
public partial class Form1 : Form
{
[DllImport("SlpApi7x32.dll")]
static extern void SlpDebugMode(int nMode);
[DllImport("SlpApi7x32.dll")]
static extern int SlpOpenPrinter(String strPrinterName, int nID, bool fPortrait);
[DllImport("SlpApi7x32.dll")]
static extern void SlpClosePrinter();
[DllImport("SlpApi7x32.dll")]
static extern bool SlpStartLabel();
[DllImport("SlpApi7x32.dll")]
static extern void SlpDrawTextXY(int x, int y, IntPtr iFont, String lpText);
[DllImport("SlpApi7x32.dll")]
static extern bool SlpEndLabel();
[DllImport("SlpApi7x32.dll")]
static extern IntPtr SlpCreateFont(String lpName, int nPoints, int nAttributes);
[DllImport("GDI32.dll")]
public static extern bool DeleteObject(IntPtr objectHandle);
public Form1()
{
InitializeComponent();
}
private void Button1_Click(object sender, EventArgs e)
{
IntPtr font = SlpCreateFont("Arial", 10, 0);
SlpDebugMode(2);
//The second parameter defines the type of label per the documentation.
SlpOpenPrinter("Smart Label Printer 440", 3, false);
{
SlpStartLabel();
//Draw as much as you want with these!
SlpDrawTextXY(0, 0, font, "Hello World");
SlpEndLabel();
}
SlpClosePrinter();
DeleteObject(font);
}
}
}

In a WPF app how do you override the Console Close command?

In my WPF application I use the Console Window as a debug/message window - I have options setup to show and hide the window as the user desires and all that works great. The only issue is that when the user closes the Console window it exits the entire program. How can I override this so that when the user click on the X it just hides the Console instead of exiting the application?
this is what I have so far:
const int SW_HIDE = 0;
const int SW_SHOW = 5;
public static bool ConsoleVisible { get; private set; }
[DllImport("kernel32.dll")]
static extern IntPtr GetConsoleWindow();
[DllImport("user32.dll")]
static extern bool ShowWindow(IntPtr hWnd, int nCmdShow);
public static void HideConsole()
{
var handle = GetConsoleWindow();
ShowWindow(handle, SW_HIDE);
ConsoleVisible = false;
}
public static void ShowConsole()
{
var handle = GetConsoleWindow();
ShowWindow(handle, SW_SHOW);
ConsoleVisible = true;
}
** For people wanting to utilize this you need: using System.Runtime.InteropServices;
This code was derived from this answer: https://stackoverflow.com/a/3571628/649382
** Edit **
Looking around a bit more it seems like this is not possible. I saw an answer here: https://stackoverflow.com/a/12015131/649382 that talks about removing the exit button which would also be acceptable, except it looks like the code is in C++ and I can't figure out it's C# alternative.
** Edit 2 **
I was able to figure out the conversion to C# and have written it as the answer below.
So as has been discussed there is no way to prevent the Console Window from closing the WPF/Application Window. Prior to Windows Vista there were some workarounds, but since then they have been removed (probably for security reasons). The work around I was able to come up with was to disable the Exit button on the Console Window and place show/hide options into my application. The application start class looks like this:
using System;
using System.Windows;
using System.Runtime.InteropServices;
namespace MyApp
{
/// <summary>
/// Interaction logic for App.xaml
/// </summary>
public partial class App : Application
{
public App()
{
ConsoleVisible = true;
DisableConsoleExit();
}
#region Console Window Commands
// Show/Hide
[DllImport("kernel32.dll")]
static extern IntPtr GetConsoleWindow();
[DllImport("user32.dll")]
static extern bool ShowWindow(IntPtr hWnd, uint nCmdShow);
const uint SW_HIDE = 0;
const uint SW_SHOWNORMAL = 1;
const uint SW_SHOWNOACTIVATE = 4; // Show without activating
public static bool ConsoleVisible { get; private set; }
public static void HideConsole()
{
IntPtr handle = GetConsoleWindow();
ShowWindow(handle, SW_HIDE);
ConsoleVisible = false;
}
public static void ShowConsole(bool active = true)
{
IntPtr handle = GetConsoleWindow();
if (active) { ShowWindow(handle, SW_SHOWNORMAL); }
else { ShowWindow(handle, SW_SHOWNOACTIVATE); }
ConsoleVisible = true;
}
// Disable Console Exit Button
[DllImport("user32.dll")]
static extern IntPtr GetSystemMenu(IntPtr hWnd, bool bRevert);
[DllImport("user32.dll")]
static extern IntPtr DeleteMenu(IntPtr hMenu, uint uPosition, uint uFlags);
const uint SC_CLOSE = 0xF060;
const uint MF_BYCOMMAND = (uint)0x00000000L;
public static void DisableConsoleExit()
{
IntPtr handle = GetConsoleWindow();
IntPtr exitButton = GetSystemMenu(handle, false);
if (exitButton != null) DeleteMenu(exitButton, SC_CLOSE, MF_BYCOMMAND);
}
#endregion
}
}
Hope this helps everyone out who may have a similar issue.
I think you should look into creating the console using AllocConsole and releasing it using FreeConsole. That way you may be able to give the user the ability to close the console window while keeping your WPF application running.

Get key pressed from other application C#

I would like to get the key pressed by user on other application. For example, in notepad, not the program itself. Here is my coding that using PostMessage method to continuously send key to notepad but however, I wish to stop it when some key is pressed.
using System.Diagnostics;
using System.Runtime.InteropServices;
using System.Threading;
[DllImport("user32.dll")]
public static extern IntPtr FindWindow(
string ClassName,
string WindowName);
[DllImport("User32.dll")]
public static extern IntPtr FindWindowEx(
IntPtr Parent,
IntPtr Child,
string lpszClass,
string lpszWindows);
[DllImport("User32.dll")]
public static extern Int32 PostMessage(
IntPtr hWnd,
int Msg,
int wParam,
int lParam);
private const int WM_KEYDOWN = 0x100;
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
Thread t = new Thread(new ThreadStart(Test));
t.Start();
}
Boolean ControlKeyDown = true;
public void Test()
{
// retrieve Notepad main window handle
IntPtr Notepad = FindWindow("Notepad", "Untitled - Notepad");
if (!Notepad.Equals(IntPtr.Zero))
{
// retrieve Edit window handle of Notepad
IntPtr Checking = FindWindowEx(Notepad, IntPtr.Zero, "Edit", null);
if (!Checking.Equals(IntPtr.Zero))
{
while (ControlKeyDown)
{
Thread.Sleep(100);
PostMessage(Checking, WM_KEYDOWN, (int)Keys.A, 0);
}
}
}
}
Hence, my idea is set the ControlKeyDown to false when user pressed X key in notepad. After research through internet, I found out this code and edited:
protected override void OnKeyDown(KeyEventArgs kea)
{
if (kea.KeyCode == Keys.X)
ControlKeyDown = false;
}
Yes, by this, it definitely will stop the looping but this is not I want as it will stop the loop when user presses X key on the program but not in notepad. This is because the KeyEventArgs is System.Windows.Forms.KeyEventArgs and not Notepad.
Need help :(
I guess you are looking for keyboard hooking. See this article, it is c++ but you appear to be agile in p/invoke so you probably get how to port it easily.
You might want to take a look at the SetWindowsHookEx function in the user32.dll.
I also user the gma.UserActivity library to do it in a project.

Categories