How to close viber main window - c#

I'm developing a tiny launcher. Its main idea is to fix the lack of functionality in Viber for Windows.
I want it to make start Viber minimized to tray only.
Normally, when Viber is starting, it appears a Viber main window on desktop and an icon - in system tray. All the time I should close this obsolete window manually.
So, I have written a few lines of code, but I found that it still couldn't close the window:
using System;
using System.Diagnostics;
class ViberStrt {
static void Main() {
Process newProc = Process.Start("c:\\Users\\Dmytro\\AppData\\Local\\Viber\\Viber.exe");
Console.WriteLine("New process has started");
//newProc.CloseMainWindow();
newProc.WaitForExit();
newProc.Close();
newProc.Dispose();
Console.WriteLine("Process has finished");
//newProc.Kill();
}
}
But whatever I tried (Close, Dispose) - it does not work.
Method Kill does not fit, because it kills all. But the only thing I need is to close Viber main window and leave the process in the System Tray.
There is also another way: to start Viber minimized at once:
using System;
using System.Diagnostics;
class LaunchViber
{
void OpenWithStartInfo()
{
ProcessStartInfo startInfo = new ProcessStartInfo("c:\\Users\\Dmytro\\AppData\\Local\\Viber\\Viber.exe");
startInfo.WindowStyle = ProcessWindowStyle.Minimized;
Process.Start(startInfo);
}
static void Main()
{
//Process newProc = Process.Start("c:\\Users\\Dmytro\\AppData\\Local\\Viber\\Viber.exe");
LaunchViber newProc = new LaunchViber();
newProc.OpenWithStartInfo();
}
}
In such a case, we receive a minimized window on the TaskPane and an icon in the SystemTray. But in this case I have absolutely no idea how to get rid of the icon (how to close minimized window) on the TaskPane.
I shall appreciate any help/ ideas in finding a solution for this problem.

Using Pinvoke, you can try getting the handle for the actual window if you know what the window caption will be.
First, import these functions:
[DllImport("user32.dll", EntryPoint = "FindWindow", SetLastError = true)]
static extern IntPtr FindWindowByCaption(IntPtr ZeroOnly, string lpWindowName);
[DllImport("user32.dll", CharSet = CharSet.Auto)]
static extern IntPtr SendMessage(IntPtr hWnd, UInt32 Msg, IntPtr wParam, IntPtr lParam);
And you may want to declare the WM_CLOSE constant:
const UInt32 WM_CLOSE = 0x0010;
Then the code to close the window (but keep the process running the in background):
var startInfo = new ProcessStartInfo(#"c:\Users\Dmytro\AppData\Local\Viber\Viber.exe");
startInfo.WindowStyle = ProcessWindowStyle.Hidden;
var newProc = Process.Start(startInfo);
var name = "Viber +381112223344";
var windowPtr = FindWindowByCaption(IntPtr.Zero, name);
while (windowPtr == IntPtr.Zero)
{
windowPtr = FindWindowByCaption(IntPtr.Zero, name);
}
System.Threading.Thread.Sleep(100);
SendMessage(windowPtr, WM_CLOSE, IntPtr.Zero, IntPtr.Zero);

Related

Closing Personalization window using c#

I have written a program that change the windows theme but after changing the theme personalization window remains open and I want to close it. I tried using process.kill() with familiar process name but it didn't work. Thank you.
The code for what I am doing is as below:
ProcessStartInfo theinfo = new ProcessStartInfo(themepath + "aero.theme");
theinfo.CreateNoWindow = true;
Process thepr = new Process();
thepr.StartInfo = theinfo;
thepr.Start();
where "themepath" is String location to aero.theme.
I have even enabled CreateNoWindow to true then also it opens up Personalization to change theme but didn't close it automatically.
First use find window to get the window from their name by Using FindWindow..
[DllImport("user32.dll")]
public static extern int FindWindow(string lpClassName,string lpWindowName);
It returns you the handle of the window you want now you can use send message to close it..
[DllImport("User32.dll")]
public static extern int SendMessage(int hWnd, uint Msg, int wParam, int lParam);
public const int WM_SYSCOMMAND = 0x0112;
public const int SC_CLOSE = 0xF060;
private void closeWindow()
{
// retrieve the handler of the window
int iHandle = FindWindow("CabinetWClass", "Personalization");
if (iHandle > 0)
{
SendMessage(iHandle, WM_SYSCOMMAND, SC_CLOSE, 0);
}
}
You need to obtain the window handle by it's name and then send it a close message. This prevents having to kill any processes. See this article for information on obtaining the windows. See this one for closing windows from the handle.
After seeing the code and doing a little digging, you can accomplish this with two registry edits. You should read this article and just have your program edit the two registry keys in question.

After killing the process for TabletKeyboard(TabTip.exe) application doesn't bring back to its original size in wpf

I have a wpf application which runs on the windows 8 tablet . And in order to bring the keyboard for typing when the focus is on any TextBox.
I am invoking the process TabTip.exe to show the keyboard, and when the keyboard is shown my application shrinks. And after all manipulation, there is a save button. When I click on the save button, the keyboard should disappear and my application should come back to its original size.
I am killing the process TabTip.exe to close the keyboard, but the application will not get re-sized to its original size .
I tried:
if (process.ProcessName == "TabTip")
{
Application.Current.MainWindow.VerticalAlignment = VerticalAlignment.Stretch;
process.Kill();
Application.Current.MainWindow.Height = SystemParameters.WorkArea.Height;
Application.Current.MainWindow.Width = SystemParameters.WorkArea.Width;
Application.Current.MainWindow.WindowState = WindowState.Normal;
Application.Current.MainWindow.WindowState = WindowState.Maximized;
break;
}
Does anybody knows to restore the application to its original size after killing the TabTip.exe?
The Windows 8 keyboard has a number of rendering problems. These can be mitigated by starting the keyboard in its smaller mode (equivalent to hitting the minimize button). It plays much better with WPF then, actually minimizing and expanding when the process is launched and closed.
This requires launching the process in this mode, and closing it in a nicer way than you are doing right now
Include these libraries:
using System.Diagnostics;
using System.Runtime.InteropServices;
using System.Windows.Interop;
And define this external functions:
[return: MarshalAs(UnmanagedType.Bool)]
[DllImport("user32.dll", SetLastError = true)]
public static extern bool PostMessage(int hWnd, uint Msg, int wParam, int lParam);
[DllImport("user32.dll")]
public static extern IntPtr FindWindow(String sClassName, String sAppName);
Open the keyboard with:
public static void openKeyboard()
{
ProcessStartInfo startInfo = new ProcessStartInfo(#"C:\Program Files\Common Files\Microsoft Shared\ink\TabTip.exe");
startInfo.WindowStyle = ProcessWindowStyle.Hidden;
myProcess = Process.Start(startInfo);
}
and close it with:
public static void closeKeyboard()
{
uint WM_SYSCOMMAND = 274;
uint SC_CLOSE = 61536;
IntPtr KeyboardWnd = FindWindow("IPTip_Main_Window", null);
PostMessage(KeyboardWnd.ToInt32(), WM_SYSCOMMAND, (int)SC_CLOSE, 0);
}
This will give you the best behaved windows 8 on screen keyboard you can get. With any luck it will fix your rendering issues.
Abin - you asked about closing the keyboard window rather than killing the process. That's what I'm doing in a WPF app and by closing the window, my main application's window will resize as expected. A quick console app to demonstrate hiding the keyboard is here (note that this assumes you're using the keyboard in docked mode rather than the floating minimal mode):
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
namespace TabTipTest
{
class Program
{
[DllImport("user32.dll")]
public static extern IntPtr FindWindow(String sClassName, String sAppName);
[DllImport("user32.dll")]
public static extern int SendMessage(IntPtr hWnd, uint Msg, int wParam, int lParam);
/// <summary>
/// The command for a user choosing a command from the Window menu (see http://msdn.microsoft.com/en-gb/library/windows/desktop/ms646360(v=vs.85).aspx).
/// </summary>
public const int WM_SYSCOMMAND = 0x0112;
/// <summary>
/// Closes the window.
/// </summary>
public const int SC_CLOSE = 0xF060;
static void Main(string[] args)
{
HideKeyboard();
}
/// <summary>
/// Gets the window handler for the virtual keyboard.
/// </summary>
/// <returns>The handle.</returns>
public static IntPtr GetKeyboardWindowHandle()
{
return FindWindow("IPTip_Main_Window", null);
}
/// <summary>
/// Hides the keyboard by sending the window the close command.
/// </summary>
public static void HideKeyboard()
{
IntPtr keyboardHandle = GetKeyboardWindowHandle();
if (keyboardHandle != IntPtr.Zero)
{
SendMessage(keyboardHandle, WM_SYSCOMMAND, SC_CLOSE, 0);
}
}
}
}

Is there a way to have my app push its icon to other apps?

I have a WPF app that starts another application, I'd like for my application to change the Icon of this second app. I am able to use GetWindowText and SetWindowText to change the title. Is it possible to do this for the Icon as well?
update
I have no control of the second app.
To change the window title of another application:
Definitions of Win32 API functions and constants:
[DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)]
public static extern bool SetWindowText(IntPtr hwnd, String lpString);
[DllImport("user32.dll")]
public static extern int SendMessage(IntPtr hwnd, int message, int wParam, IntPtr lParam);
private const int WM_SETICON = 0x80;
private const int ICON_SMALL = 0;
private const int ICON_BIG = 1;
Usage:
Process process = Process.Start("notepad");
// If you have just started a process and want to use its main window handle,
// consider using the WaitForInputIdle method to allow the process to finish starting,
// ensuring that the main window handle has been created.
// Otherwise, an exception will be thrown.
process.WaitForInputIdle();
SetWindowText(process.MainWindowHandle, "Hello!");
Icon icon = new Icon(#"C:\Icon\File\Path.ico");
SendMessage(process.MainWindowHandle, WM_SETICON, ICON_BIG, icon.Handle);
In Windows Forms you would use
Icon ico = Icon.ExtractAssociatedIcon(#"C:\WINDOWS\system32\notepad.exe");
this.Icon = ico;
So im guessing for WPF it would be similar.

Maintaining focus on a form

I am developing a software for a blind individual in C# .NET.
The software works only with the keyboard and voice to speech.
When the computer starts the program is in the start up menu, but for some reason the program is activated not in focus therefore it does not work properly unless the focus is re transferred to it.
I found a way to hook keyboard keys even when the software is not in focus but I don't see that as a solution.
I want a way to do one or more of the following:
Make sure the program loads on start up and is in focus.
Maintain focus on the program (this computer will be run only using this program).
Find a keyboard shortcut, preferably one key only (not Alt + Tab) to return focus to the program.
There are many ways you can solve this ie you can run on startup console app that will run and focus your program:
[STAThread]
static void Main(string[] args)
{
System.Diagnostics.Process myProcess = new System.Diagnostics.Process();
myProcess.StartInfo.FileName = "calc";
myProcess.Start();
IntPtr hWnd = myProcess.Handle;
SetFocus(new HandleRef(null, hWnd));
}
[DllImport("user32.dll", CharSet = CharSet.Auto, ExactSpelling = true)]
public static extern IntPtr SetFocus(HandleRef hWnd);
You can host a windows service application and using timer check if your app is alive and is focused or you can use hotkeys to bring it back focused: http://www.codeproject.com/KB/miscctrl/ashsimplehotkeys.aspx
Edited
this is console application, that will keep your app alive and focused (tested). i need to find walkaround for windows service becouse since vista something changed and form is invisible when stared from service :P
static Process myProcess;
[STAThread]
static void Main(string[] args)
{
for (int i = 0; i < 10000; i++)
{
//count how many procesess with this name are active if more than zero its still alive
Process[] proc = Process.GetProcessesByName("myprog");
if (proc.Length > 0)
{
//its alive check if it has focus
if (proc[0].MainWindowHandle != GetForegroundWindow())
{
SetFocus(proc[0].MainWindowHandle);
}
}
//no process start new one and focus on it
else
{
myProcess = new Process();
myProcess.StartInfo.FileName = "C:\\aa\\myprog.exe";
myProcess.Start();
SetFocus(myProcess.Handle);
}
Thread.Sleep(1000);
}
}
private static void SetFocus(IntPtr handle)
{
SwitchToThisWindow(handle, true);
}
[DllImport("user32.dll")]
static extern IntPtr GetForegroundWindow();
[DllImport("user32.dll", SetLastError = true)]
public static extern void SwitchToThisWindow(IntPtr hWnd, bool fAltTab);

How do you get a child window using its control ID?

I am new to WINAPI and have figured out how to send a message to another program. The program I am using however I would like to be able to have it click on a specific button. From what I have learned by viewing Spy++ windows handles change for the programs every time they are reloaded and so do the handles for their controls. The control ID stays the same. After two days of trying to figure it out I am here.
under SendMesssageA if I specify the current handle as viewable by Spy++ and use that and run the code it works fine and clicks the button on my external application. I am attempting to use GetDlgItem as I have read that I can get the handle for the control (child window) using it. I am doing something wrong however since no matter what I do it returns 0 or 'null'.
How can I get GetDlgItem to return the child control handle so that I may use it to sendmessage to click that control in the external application?
Thanks for your help an input ahead of time.
[DllImport("User32.dll")]
static extern bool SetForegroundWindow(IntPtr hWnd);
Process[] myProcess = Process.GetProcessesByName("program name here");
[DllImport("user32.dll", CharSet = CharSet.Auto)]
static extern int SendMessageA(IntPtr hwnd, int wMsg, int wParam, uint lParam);
[DllImport("user32.dll", CharSet = CharSet.Auto)]
public static extern IntPtr GetDlgItem(int hwnd, int childID);
public const int WM_LBUTTONDOWN = 0x0201;
public const int WM_LBUTTONUP = 0x0202;
public void SendClick()
{
IntPtr hwnd = myProcess[0].MainWindowHandle;
SetForegroundWindow(hwnd);
int intCID = 1389;
IntPtr ptrTest = GetDlgItem(hwnd, intCID);
SendKeys.SendWait(" ");
Thread.Sleep(1000);
SendKeys.SendWait("various text to be sent here");
Thread.Sleep(1000);
SendKeys.SendWait("{ENTER}");
Thread.Sleep(1000);
SendMessageA(ptrTest, WM_LBUTTONDOWN, WM_LBUTTONDOWN, 0);
}
I think you have to use the Win32 API to find the "receiving" application window, and then find a child window of that handle.
This is something I found googling Win32 API FindWindow
http://www.c-sharpcorner.com/UploadFile/shrijeetnair/win32api12062005005528AM/win32api.aspx

Categories