I'm trying to run discord.exe inside a windows form but im getting this error. Can someone help me, thanks. Here is the error message: Error message in English ("The system cannot find the file specified")
These are my codes:
[DllImport("user32.dll")]
static extern IntPtr SetParent(IntPtr child, IntPtr newParent);
[DllImport("user32.dll")]
static extern int SendMessage(IntPtr hWnd, int Msg, int wParam, int Iparam);
[DllImport("user32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
private static extern bool IsWindowVisible(IntPtr hWnd);
private const int WM_SYSCOMMAND = 274;
private const int SC_MAXIMIZE = 61488;
private void button1_Click(object sender, EventArgs e)
{
string anan = "discord.exe";
Process calistir = Process.Start(anan);
while (calistir.MainWindowHandle == IntPtr.Zero || !IsWindowVisible(calistir.MainWindowHandle))
{
System.Threading.Thread.Sleep(10);
calistir.Refresh();
}
SetParent(calistir.MainWindowHandle, this.Handle);
SendMessage(calistir.MainWindowHandle, WM_SYSCOMMAND, SC_MAXIMIZE, 0);
}
if you wanna run the software, first you have to give the path of the file. I changed the code but you have to change it according to the information on your computer. Then it will work.
You can see the screenshot here: Discord App => Properties
https://i.hizliresim.com/1p5ZYG.jpg
string anan = #"C:\Users\YouPC\AppData\Local\Discord\Discord.exe";
Process calistir = Process.Start(anan);
while (calistir.MainWindowHandle == IntPtr.Zero ||
!IsWindowVisible(calistir.MainWindowHandle))
{
System.Threading.Thread.Sleep(10);
calistir.Refresh();
}
SetParent(calistir.MainWindowHandle, this.Handle);
SendMessage(calistir.MainWindowHandle, WM_SYSCOMMAND, SC_MAXIMIZE, 0);
Related
I would like to ask you a question about bringing calculator window to front in Windows 10. I have tested a lot of codes, but nothing is really working. I think the main problem is, that Calculator is part of "ApplicationFrameHost".
In my application (C# WinForm), I would like to start system Calculator, if it's not running. If it's running bring the window to front even if it's minimized or not.
public static class WindowHelper
{
[DllImport("user32.dll")]
private static extern void keybd_event(byte bVk, byte bScan, uint dwFlags, int dwExtraInfo);
[DllImport("user32.dll")]
private static extern bool SetForegroundWindow(IntPtr hWnd);
[DllImport("user32.dll")]
private static extern bool ShowWindow(IntPtr hWnd, int nCmdShow);
private const int ALT = 0xA4;
private const int EXTENDEDKEY = 0x01;
private const int KEYUP = 0x02;
private const int SW_MINIMIZE = 0x06;
private const int SW_RESTORE = 0x09;
public static void BringProcessToFront(IntPtr mainWindowHandle)
{
// check if window has focus already
//if (mainWindowHandle == GetForegroundWindow()) return;
ShowWindow(mainWindowHandle, SW_RESTORE);
// simulate ALT key down
keybd_event((byte)ALT, 0x45, EXTENDEDKEY | 0, 0);
// simulate ALT key up
keybd_event((byte)ALT, 0x45, EXTENDEDKEY | KEYUP, 0);
// bring window into foreground
SetForegroundWindow(mainWindowHandle);
}
}
private void btnCalc_Click(object sender, EventArgs e)
{
// get all processes
System.Diagnostics.Process[] processes = System.Diagnostics.Process.GetProcesses();
// get ApplicationFrameHost for win10
System.Diagnostics.Process[] appFH = System.Diagnostics.Process.GetProcessesByName("ApplicationFrameHost");
IntPtr mWHandle = IntPtr.Zero;
foreach (System.Diagnostics.Process proc in processes)
{
if (proc.ProcessName == "calc" || proc.ProcessName == "Calculator" || proc.ProcessName == "win32calc")
{
// non-ApplicationFrameHost case
mWHandle = proc.MainWindowHandle;
if (appFH.Length > 0)
{
// if ApplicationFrameHost is running, find calculator MainWindowHandle
foreach (System.Diagnostics.Process app in appFH)
{
if ((app.MainWindowTitle == proc.MainWindowTitle) || (proc.MainWindowTitle.Length == 0))
mWHandle = app.MainWindowHandle;
}
}
// bring window to front
WindowHelper.BringProcessToFront(mWHandle);
return;
}
}
// calculator was not found, starts new one
System.Diagnostics.Process.Start("calc");
}
This code is working on Windows 7 as well, but not for 10 with no-english localization. There is a problem, when Calculator is minimized, it can't be restored.
As I said, I have tried lot of codes like:
public static extern IntPtr FindWindow(string lpClassName, string lpWindowName);
public static extern IntPtr FindWindowEx(IntPtr hwndParent, IntPtr hwndChildAfter, string lpszClass, string lpszWindow);
private static extern bool GetWindowPlacement(IntPtr hWnd, ref WINDOWPLACEMENT lpwndpl);
// this was working to bring focus on already displayed window
WindowHelper.FindWindowEx(app.MainWindowHandle, IntPtr.Zero, "Windows.UI.Core.CoreWindow", null);
The main problem is, that I didn't find the solution, which could unminimize window on non-english localized windows.
Do you have some example, how to deal with that?
Thank you.
EDIT:
After some testing, I have identified, why is not possible to bring this window to front. Win7 and Win10 with en (Maybe it isn't related to locale) has Calculator still activated even if it's minimized or not. On the other hand a second Win10 has process suspended when it's minimized (see picture attachment). So now the question is, how to un-suspend it. Then hopefully window could be bring to front.
You cannot force the foreground window if you are not the foreground window. There are actually a bunch of conditions that determine when you can force the foreground window. From the docs: (bottom one applies to you)
The system restricts which processes can set the foreground window.
A process can set the foreground window only if one of the following
conditions is true:
The process is the foreground process.
The process was started by the foreground process.
The process received the last input event.
There is no foreground process.
The process is being debugged.
The foreground process is not a Modern Application or the Start Screen. The foreground is not locked (see LockSetForegroundWindow)
The foreground lock time-out has expired (see SPI_GETFOREGROUNDLOCKTIMEOUT in SystemParametersInfo).
No menus are active.
An application cannot force a window to the foreground while the user is
working with another window. Instead, Windows flashes the taskbar button of the
window to notify the user.
After some time (little bit occupied by another projects) I have founded the solution, which is working for me.
public static class WindowHelper
{
public static Dictionary<IntPtr, String> appWins;
public static bool ThreadWindows(IntPtr handle, IntPtr param)
{
int size = WindowHelper.GetWindowTextLength(handle);
if (size > 0)
{
StringBuilder strbTitle = new StringBuilder(size + 1);
WindowHelper.GetWindowText(handle, strbTitle, strbTitle.Capacity);
if (strbTitle.Length > 0)
{
appWins.Add(handle, strbTitle.ToString());
return true;
}
}
return false;
}
public static void BringProcessToFront(IntPtr mainWindowHandle)
{
// check if window has focus already
//if (mainWindowHandle == GetForegroundWindow()) return;
ShowWindow(mainWindowHandle, SW_RESTORE);
// simulate ALT key down
keybd_event((byte)ALT, 0x45, EXTENDEDKEY | 0, 0);
// simulate ALT key up
keybd_event((byte)ALT, 0x45, EXTENDEDKEY | KEYUP, 0);
// bring window into foreground
SetForegroundWindow(mainWindowHandle);
}
//[DllImport("user32.dll")]
//private static extern IntPtr GetForegroundWindow();
[DllImport("user32.dll", CharSet = CharSet.Unicode)]
public static extern int GetWindowTextLength(IntPtr hWnd);
[DllImport("user32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
public static extern int GetWindowText(IntPtr hWnd, StringBuilder lpString, int nMaxCount);
public delegate bool EnumThreadDelegate(IntPtr hWnd, IntPtr lParam);
[DllImport("user32.dll")]
public static extern bool EnumThreadWindows(int dwThreadId, EnumThreadDelegate lpfn, IntPtr lParam);
[DllImport("User32.dll")]
public static extern IntPtr FindWindowEx(IntPtr hwndParent, IntPtr hwndChildAfter, string lpszClass, string lpszWindow);
[DllImport("user32.dll")]
private static extern void keybd_event(byte bVk, byte bScan, uint dwFlags, int dwExtraInfo);
[DllImport("user32.dll")]
private static extern bool SetForegroundWindow(IntPtr hWnd);
[DllImport("user32.dll")]
private static extern bool ShowWindow(IntPtr hWnd, int nCmdShow);
private const int ALT = 0xA4;
private const int EXTENDEDKEY = 0x01;
private const int KEYUP = 0x02;
private const int SW_RESTORE = 0x09;
}
private void btnCalc_Click(object sender, EventArgs e)
{
// get all processes
System.Diagnostics.Process[] processes = System.Diagnostics.Process.GetProcesses();
// get ApplicationFrameHost for win10
System.Diagnostics.Process[] appFH = System.Diagnostics.Process.GetProcessesByName("ApplicationFrameHost");
IntPtr mWHandle = IntPtr.Zero;
foreach (System.Diagnostics.Process proc in processes)
{
if (proc.ProcessName == "calc" || proc.ProcessName == "Calculator" || proc.ProcessName == "win32calc")
{
// save first handle
mWHandle = proc.MainWindowHandle;
// if ApplicationFrameHost is running, find calculator MainWindowHandle
foreach (System.Diagnostics.Process app in appFH)
{
// calculator is already running
if (mWHandle == (IntPtr)0x00)
{
mWHandle = WindowHelper.FindWindowEx(app.MainWindowHandle, IntPtr.Zero, "Windows.UI.Core.CoreWindow", null);
} else
{
// create new windows dictionary
WindowHelper.appWins = new Dictionary<IntPtr, String>();
// enumerate all windows in all AFH threads
foreach (System.Diagnostics.ProcessThread thread in app.Threads)
WindowHelper.EnumThreadWindows(thread.Id, new WindowHelper.EnumThreadDelegate(WindowHelper.ThreadWindows), IntPtr.Zero);
// check if proc window was found
if (WindowHelper.appWins.ContainsValue(proc.MainWindowTitle))
{
IntPtr hwnd;
// get key from value
if ((hwnd = WindowHelper.appWins.First(x => x.Value == proc.MainWindowTitle).Key) != (IntPtr)0)
mWHandle = hwnd;
}
// clear list
WindowHelper.appWins.Clear();
}
}
if (mWHandle != (IntPtr)(0x00))
{
// bring already running calc to front
WindowHelper.BringProcessToFront(mWHandle);
return;
}
// do not search for other processes
break;
}
}
// start new calc instance
System.Diagnostics.Process.Start("calc");
}
This solution is locale independent.
Thanks to everyone who pointing me to the right direction.
I'm looking to detect and handle keycodes from a USB HID keyboard that fall outside the "normal" set of codes, i.e. codes above 100 (0x64) in a .NET Windows Forms application (.NET Framework 4.5).
Specifically, in my case I need to detect codes between 0x68 and 0x78, but I'd like to be able to detect anything up to 0xA4, which seems to be the upper limit of HID keyboard codes (aside from things like Ctrl, Alt, Win, etc.)
This question here seemed to be exactly what I was looking for, but I have had no success getting the advice on that answer to work. I have KeyPreview set to true for the form, and event handlers registered for KeyDown, KeyPress, and PreviewKeyDown, but none of them fire on reception of an 0x68 (F13) code. For now I'd just like to print the pressed key to a richtextbox control:
public mainFrm()
{
InitializeComponent();
this.KeyPreview = true;
this.KeyDown += new KeyEventHandler(KeyDownHandler);
this.KeyPress += new KeyPressEventHandler(KeyPressHandler);
this.PreviewKeyDown += new PreviewKeyDownEventHandler(PreviewKeyHandler);
}
private void KeyPressHandler(object sender, KeyPressEventArgs e)
{
rtb_hidLog.AppendText("Press: " + e.KeyChar.ToString() + "\r\n");
}
private void KeyDownHandler(object sender, KeyEventArgs e)
{
rtb_hidLog.AppendText("KeyDown: "+ e.KeyCode.ToString() + "\r\n");
}
private void PreviewKeyHandler(object sender, PreviewKeyDownEventArgs e)
{
rtb_hidLog.AppendText("Preview: " + e.KeyCode.ToString() + "\r\n");
}
I even tried overriding ProcessCmdKey (as per this question) and that also does not fire on 0x68:
protected override bool ProcessCmdKey(ref Message msg, Keys keyData)
{
rtb_hidLog.AppendText("CmdKey: " + keyData.ToString() + "\r\n");
return base.ProcessCmdKey(ref msg, keyData);
}
I have a USB HID Keyboard device connected (a PSoC microcontroller as a HID keyboard) that sends the 0x68 (F13) keycode when I press a button, but it doesn't fire the PreviewKeyHander. A standard 'A' code (0x04) from the PSoC device fires the KeyDownHandler and KeyPressHandler events with no problem. I have confirmed via USB Analyzer that the 0x68 code is being sent correctly, I just can't seem to force .NET to recognize it and fire an event. Is there something I'm missing or a trick I need to do to force my application to fire an event on these codes?
I've now also tried using Interop to use the win32 API (User32.dll) to hook into the keyboard input, and that also does not work. I get the same results; the hooked event will fire for all the keys on my keyboard, but anything not in that range does not fire a key pressed event.
My USB HID descriptor for the keyboard device, in case there is some issue there:
You can use a keyboard interceptor "in a separate DLL project that is referenced in your application" that is used by Form like this:
public delegate IntPtr KeyBoardHook( int nCode, IntPtr wParam, IntPtr lParam);
public class InterceptKeys : IDisposable
{
private const int WH_KEYBOARD_LL = 13;
private const int WM_KEYDOWN = 0x0100;
private KeyBoardHook _proc;
public event KeyBoardHook OnKeyBoardKeyClicked;
private static IntPtr _hookID = IntPtr.Zero;
public InterceptKeys()
{
_proc = HookCallback;
_hookID = SetHook(_proc);
if(_hookID == IntPtr.Zero)
{
throw new Exception($"Error Happened [{Marshal.GetLastWin32Error()}]");
}
}
public void Dispose()
{
UnhookWindowsHookEx(_hookID);
}
private IntPtr SetHook(KeyBoardHook proc)
{
using (Process curProcess = Process.GetCurrentProcess())
using (ProcessModule curModule = curProcess.MainModule)
{
return SetWindowsHookEx(WH_KEYBOARD_LL, proc,
GetModuleHandle(curModule.ModuleName), 0);
}
}
private IntPtr HookCallback(
int nCode, IntPtr wParam, IntPtr lParam)
{
OnKeyBoardKeyClicked?.Invoke(nCode, wParam, lParam);
//if (nCode >= 0 && wParam == (IntPtr)WM_KEYDOWN)
//{
// int vkCode = Marshal.ReadInt32(lParam);
// Console.WriteLine((char)vkCode);
//}
return CallNextHookEx(_hookID, nCode, wParam, lParam);
}
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
private static extern IntPtr SetWindowsHookEx(int idHook,
KeyBoardHook lpfn, IntPtr hMod, uint dwThreadId);
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
private static extern bool UnhookWindowsHookEx(IntPtr hhk);
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
private static extern IntPtr CallNextHookEx(IntPtr hhk, int nCode,
IntPtr wParam, IntPtr lParam);
[DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
private static extern IntPtr GetModuleHandle(string lpModuleName);
}
[DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
private static extern IntPtr GetModuleHandle(string lpModuleName);
}
I just want to do real minimized, all public codes are not minimizing in right way! It just minimize it as shown, but not minimize like if I click on Minimize button. How did I know that? Or what benefit will I get from that? When I press on minimize button, it reduce from CPU usage! (It's a game anyway.)
My code is :
[DllImport("User32.Dll", EntryPoint = "PostMessageA", SetLastError = true)]
public static extern bool PostMessage(IntPtr hWnd, uint msg, IntPtr wParam, IntPtr lParam);
List<int> ProcIDs = new List<int>();
private void timer1_Tick(object sender, EventArgs e)
{
foreach (Process process in Process.GetProcesses())
{
if (process.ProcessName == "League of Legends")
{
// MinimizeWindow((IntPtr)hProcess);
if (!ProcIDs.Contains(process.Id))
{
IntPtr hProcess = GetProcessWindow(process.Id);
ProcIDs.Add(process.Id);
PostMessage(hProcess, WM_SYSCOMMAND, (IntPtr)SC_MINIMIZE, IntPtr.Zero);
}
}
}
}
const int WM_SYSCOMMAND = 274;
const int SC_MINIMIZE = 0xF020;
I also tried other methods and it does the same, just minimize as show, but not real minimize! :)
You can try this
[DllImport("user32.dll")]
private static extern bool ShowWindow(IntPtr hWnd, WindowShowStyle nCmdShow);
with window style as ShowMinimized = 2,
http://www.pinvoke.net/default.aspx/user32.showwindow
I need to simulate a keypress in game window. I try to send key "A", but it don't work:
[DllImport("user32.dll", SetLastError = true)]
static extern IntPtr FindWindow(string lpClassName, string lpWindowName);
[DllImport("USER32.DLL")]
public static extern bool SetForegroundWindow(IntPtr hWnd);
[DllImport("user32.dll")]
public static extern IntPtr PostMessage(IntPtr hWnd, uint Msg, IntPtr wParam, IntPtr lParam);
private void button1_Click(object sender, EventArgs e)
{
IntPtr hWnd = FindWindow(null, "Game Name"); // it's work!
if (hWnd == IntPtr.Zero)
{
MessageBox.Show("Game is not running");
return;
}
SetForegroundWindow(hWnd); // it's work too and now I have active window of game
System.Threading.Thread.Sleep(3000);
const int WM_KEYDOWN = 0x0100;
PostMessage(hWnd, WM_KEYDOWN, (IntPtr)Keys.A, IntPtr.Zero); // don't work ;-(
}
What error do you get? Is the game running as administrator? You could be blocked by UIPI.
it's a standard windows function that the display goes into sleep mode after the configured time. is it somehow possible to send the display into sleep mode immediately from a c# .net application in windows 7? i've already tried one thing i found but it didn't work for me.
[DllImport("user32.dll")]
static extern IntPtr SendMessage(IntPtr hWnd, UInt32 Msg, IntPtr wParam, IntPtr lParam);
[DllImport("user32.dll", CharSet = CharSet.Auto, ExactSpelling = true)]
public static extern IntPtr GetDesktopWindow();
private const int SC_MONITORPOWER = 0xF170;
private const UInt32 WM_SYSCOMMAND = 0x0112;
private const int MONITOR_ON = -1;
private const int MONITOR_OFF = 2;
private const int MONITOR_STANBY = 1;
public static void DisplayToSleep()
{
var hWnd = GetDesktopWindow();
var ret = SendMessage(hWnd , Constants.WM_SYSCOMMAND, (IntPtr)Constants.SC_MONITORPOWER, (IntPtr)Constants.MONITOR_OFF);
}
hWnd seems to have a valid value but ret is always 0.
thx, kopi_b
This works fine in a WinForms application:
public partial class Form1 : Form
{
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);
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
SendMessage(this.Handle, WM_SYSCOMMAND, (IntPtr)SC_MONITORPOWER, (IntPtr)2);
}
}
The problem seems to come from the GetDesktopWindow function.
You need to use HWND_BROADCAST instead of the desktop window handle to ensure that the monitor powers off:
private const int HWND_BROADCAST = 0xFFFF;
var ret = SendMessage((IntPtr)HWND_BROADCAST, WM_SYSCOMMAND, (IntPtr)SC_MONITORPOWER, (IntPtr)MONITOR_OFF);
I have Visual Studio 2010 and Windows 7 and created a Windows Form Application with a 'Sleep' and 'Hibernate' button. The following worked for me:
private void Sleep_Click(object sender, EventArgs e)
{
bool retVal = Application.SetSuspendState(PowerState.Suspend, false, false);
if (retVal == false)
MessageBox.Show("Could not suspend the system.");
}
private void Hibernate_Click(object sender, EventArgs e)
{
bool retVal = Application.SetSuspendState(PowerState.Hibernate, false, false);
if (retVal == false)
MessageBox.Show("Could not hybernate the system.");
}
I found this here