needing to emulate Win key in a batch file - batch-file

I have been trying to find the answer, but my research has not come up with much that is helpful to my situation. I am needing to emulate the Windows Key in my batch file that I am creating. This is to help me Maximize the window, as well as easily move it between monitors without the use of a mouse. The workstation this batch will autorun on, will not have access to a mouse or physical Keyboard.
This is the code I am working with.
#if (#CodeSection == #Batch) #then
#echo off
rem Use %SendKeys% to send keys to the keyboard buffer
set SendKeys=CScript //nologo //E:JScript "%~F0"
rem Start the other program in the same Window
Start "Progam"
rem the script only works if the application in question is the active window. Set a timer
timeout /t 10
rem use the tab key to move the cursor to the login and password inputs.
%SendKeys% "This would be the username{TAB}"
%SendKeys% "this would be the password{ENTER}"
rem I then have a timer to let the login happen
timeout /t 10
rem this where I am now trying to maximize and move the active window around.
goto :EOF
#end
// JScript section
var WshShell = WScript.CreateObject("WScript.Shell");
WshShell.SendKeys(WScript.Arguments(0));

Great question! Yeah, I had to battle this myself some time ago. I wanted to auto launch an application installed from the Microsoft Store on startup, and for reasons the easiest way for me to do that was to pin it to my Taskbar then simulate hitting ⊞+1 to launch it. I assume the case is now as it was back then, but there's no way to SendKeys() the Windows meta key. But thanks to LandOfTheLostPass on reddit, I discovered an alternative to SendKeys(): sending the keyboard scan code.
I modified the code from reddit to allow me to simulate pressing multiple keys, then release them. If I recall correctly, the code on reddit would only simulate press then release a single key at a time. I only modified the scan code function for multi-key combos. Re-examining the code now, it appears I might've broken the SendChars() function. But I never used it anyway.
<# : win+1.bat -- Batch portion
#echo off & setlocal
powershell -window minimized -noprofile "iex (${%~f0} | out-string)"
goto :EOF
: end batch / begin PowerShell chimera #>
# https://www.reddit.com/r/PowerShell/comments/3qk9mc/keyboard_keypress_script/
Add-Type #"
using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;
public static class KBEmulator {
public enum InputType : uint {
INPUT_MOUSE = 0,
INPUT_KEYBOARD = 1,
INPUT_HARDWARE = 3
}
[Flags]
internal enum KEYEVENTF : uint
{
KEYDOWN = 0x0,
EXTENDEDKEY = 0x0001,
KEYUP = 0x0002,
SCANCODE = 0x0008,
UNICODE = 0x0004
}
[Flags]
internal enum MOUSEEVENTF : uint
{
ABSOLUTE = 0x8000,
HWHEEL = 0x01000,
MOVE = 0x0001,
MOVE_NOCOALESCE = 0x2000,
LEFTDOWN = 0x0002,
LEFTUP = 0x0004,
RIGHTDOWN = 0x0008,
RIGHTUP = 0x0010,
MIDDLEDOWN = 0x0020,
MIDDLEUP = 0x0040,
VIRTUALDESK = 0x4000,
WHEEL = 0x0800,
XDOWN = 0x0080,
XUP = 0x0100
}
// Master Input structure
[StructLayout(LayoutKind.Sequential)]
public struct lpInput {
internal InputType type;
internal InputUnion Data;
internal static int Size { get { return Marshal.SizeOf(typeof(lpInput)); } }
}
// Union structure
[StructLayout(LayoutKind.Explicit)]
internal struct InputUnion {
[FieldOffset(0)]
internal MOUSEINPUT mi;
[FieldOffset(0)]
internal KEYBDINPUT ki;
[FieldOffset(0)]
internal HARDWAREINPUT hi;
}
// Input Types
[StructLayout(LayoutKind.Sequential)]
internal struct MOUSEINPUT
{
internal int dx;
internal int dy;
internal int mouseData;
internal MOUSEEVENTF dwFlags;
internal uint time;
internal UIntPtr dwExtraInfo;
}
[StructLayout(LayoutKind.Sequential)]
internal struct KEYBDINPUT
{
internal short wVk;
internal short wScan;
internal KEYEVENTF dwFlags;
internal int time;
internal UIntPtr dwExtraInfo;
}
[StructLayout(LayoutKind.Sequential)]
internal struct HARDWAREINPUT
{
internal int uMsg;
internal short wParamL;
internal short wParamH;
}
private class unmanaged {
[DllImport("user32.dll", SetLastError = true)]
internal static extern uint SendInput (
uint cInputs,
[MarshalAs(UnmanagedType.LPArray)]
lpInput[] inputs,
int cbSize
);
[DllImport("user32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
public static extern short VkKeyScan(char ch);
}
internal static short VkKeyScan(char ch) {
return unmanaged.VkKeyScan(ch);
}
internal static uint SendInput(uint cInputs, lpInput[] inputs, int cbSize) {
return unmanaged.SendInput(cInputs, inputs, cbSize);
}
public static void SendScanCodeCombo(short[] scanCodes) {
lpInput[] KeyInputs = new lpInput[1];
lpInput KeyInput = new lpInput();
Enum[] actions = { KEYEVENTF.KEYDOWN, KEYEVENTF.KEYUP };
// Generic Keyboard Event
KeyInput.type = InputType.INPUT_KEYBOARD;
KeyInput.Data.ki.wScan = 0;
KeyInput.Data.ki.time = 0;
KeyInput.Data.ki.dwExtraInfo = UIntPtr.Zero;
// Press and release the correct key combination
foreach (KEYEVENTF action in actions) {
foreach (short scanCode in scanCodes) {
KeyInput.Data.ki.wVk = scanCode;
KeyInput.Data.ki.dwFlags = action;
KeyInputs[0] = KeyInput;
SendInput(1, KeyInputs, lpInput.Size);
}
}
return;
}
public static void SendChars(char[] keys) {
lpInput[] KeyInputs = new lpInput[1];
lpInput KeyInput = new lpInput();
Enum[] actions = { KEYEVENTF.KEYDOWN, KEYEVENTF.KEYUP };
// Generic Keyboard Event
KeyInput.type = InputType.INPUT_KEYBOARD;
KeyInput.Data.ki.wScan = 0;
KeyInput.Data.ki.time = 0;
KeyInput.Data.ki.dwExtraInfo = UIntPtr.Zero;
foreach (KEYEVENTF action in actions) {
foreach (char ch in keys) {
// Press the key
KeyInput.Data.ki.wVk = VkKeyScan(ch);
KeyInput.Data.ki.dwFlags = KEYEVENTF.KEYDOWN;
KeyInputs[0] = KeyInput;
SendInput(1, KeyInputs, lpInput.Size);
// Release the key
KeyInput.Data.ki.dwFlags = KEYEVENTF.KEYUP;
KeyInputs[0] = KeyInput;
SendInput(1, KeyInputs, lpInput.Size);
}
}
return;
}
}
"# # end Add-Type
# Send LWin+1
[KBEmulator]::SendScanCodeCombo(#(0x5B, 0x31))
See Virtual-Key Codes on Microsoft Docs to find the scan codes for other keys.
By the way, the Windows API provides other ways to maximize and move windows without simulating keyboard shortcuts. (Please don't judge too harshly. I wrote that hack before learning how to write Batch + PowerShell hybrid scripts or to include .NET code in PowerShell.)

you can use http://nircmd.nirsoft.net/
nircmd sendkeypress key

Related

Bringing wpf App to Foreground which is running in background? [duplicate]

I'm adding some code to an app that will launch another app if it isn't already running, or if it is, bring it to the front. This requires a small amount of interop/WinAPI code, which I've gotten examples for from other sites but can't seem to get to work in Win7.
If the window is in some visible state, then the API's SetForegroundWindow method works like a treat (and this would be the main case, as per company policy if the external app is running it should not be minimized). However, if it is minimized (exceptional but important as my app will appear to do nothing in this case), neither this method nor ShowWindow/ShowWindowAsync will actually bring the window back up from the taskbar; all of the methods simply highlight the taskbar button.
Here's the code; most of it works just fine, but the call to ShowWindow() (I've also tried ShowWindowAsync) just never does what I want it to no matter what the command I send is:
[DllImport("user32.dll")]
private static extern int SetForegroundWindow(IntPtr hWnd);
private const int SW_SHOWNORMAL = 1;
private const int SW_SHOWMAXIMIZED = 3;
private const int SW_RESTORE = 9;
[DllImport("user32.dll")]
private static extern bool ShowWindow(IntPtr hWnd, int nCmdShow);
...
//The app is named uniquely enough that it can't be anything else,
//and is not normally launched except by this one.
//so this should normally return zero or one instance
var processes = Process.GetProcessesByName("ExternalApp.exe");
if (processes.Any()) //a copy is already running
{
//I can't currently tell the window's state,
//so I both restore and activate it
var handle = processes.First().MainWindowHandle;
ShowWindow(handle, SW_RESTORE); //GRR!!!
SetForegroundWindow(handle);
return true;
}
try
{
//If a copy is not running, start one.
Process.Start(#"C:\Program Files (x86)\ExternalApp\ExternalApp.exe");
return true;
}
catch (Exception)
{
//fallback for 32-bit OSes
Process.Start(#"C:\Program Files\ExternalApp\ExternalApp.exe");
return true;
}
I've tried SHOWNORMAL (1), SHOWMAXIMIZED (3), RESTORE (9), and a couple other sizing commands, but nothing seems to do the trick. Thoughts?
EDIT: I found an issue with some of the other code I had thought was working. The call to GetProcessesByName() was not finding the process because I was looking for the executable name, which was not the process name. That caused the code I thought was running and failing to actually not execute at all. I thought it was working because the external app will apparently also detect that a copy is already running and try to activate that current instance. I dropped the ".exe" from the process name I search for and now the code executes; however that seems to be a step backwards, as now the taskbar button isn't even highlighted when I call ShowWindow[Async]. So, I now know that neither my app, nor the external app I'm invoking, can change the window state of a different instance programmatically in Win7. What's goin' on here?
Working code using FindWindow method:
[DllImport("user32.dll")]
public static extern IntPtr FindWindow(string className, string windowTitle);
[DllImport("user32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
static extern bool ShowWindow(IntPtr hWnd, ShowWindowEnum flags);
[DllImport("user32.dll")]
private static extern int SetForegroundWindow(IntPtr hwnd);
[DllImport("user32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
static extern bool GetWindowPlacement(IntPtr hWnd, ref Windowplacement lpwndpl);
private enum ShowWindowEnum
{
Hide = 0,
ShowNormal = 1, ShowMinimized = 2, ShowMaximized = 3,
Maximize = 3, ShowNormalNoActivate = 4, Show = 5,
Minimize = 6, ShowMinNoActivate = 7, ShowNoActivate = 8,
Restore = 9, ShowDefault = 10, ForceMinimized = 11
};
private struct Windowplacement
{
public int length;
public int flags;
public int showCmd;
public System.Drawing.Point ptMinPosition;
public System.Drawing.Point ptMaxPosition;
public System.Drawing.Rectangle rcNormalPosition;
}
private void BringWindowToFront()
{
IntPtr wdwIntPtr = FindWindow(null, "Put_your_window_title_here");
//get the hWnd of the process
Windowplacement placement = new Windowplacement();
GetWindowPlacement(wdwIntPtr, ref placement);
// Check if window is minimized
if (placement.showCmd == 2)
{
//the window is hidden so we restore it
ShowWindow(wdwIntPtr, ShowWindowEnum.Restore);
}
//set user's focus to the window
SetForegroundWindow(wdwIntPtr);
}
You can use it by calling BringWindowToFront().
I always have one instance of the application running so if you can have several open instances simultaneously you might want to slightly change the logic.
... Apparently you cannot trust the information a Process gives you.
Process.MainWindowHandle returns the window handle of the first window created by the application, which is USUALLY that app's main top-level window. However, in my case, a call to FindWindow() shows that the handle of the actual window I want to restore is not what MainWindowHandle is pointing to. It appears that the window handle from the Process, in this case, is that of the splash screen shown as the program loads the main form.
If I call ShowWindow on the handle that FindWindow returned, it works perfectly.
What's even more unusual is that when the window's open, the call to SetForegroundWindow(), when given the process's MainWindowHandle (which should be invalid as that window has closed), works fine. So obviously that handle has SOME validity, just not when the window's minimized.
In summary, if you find yourself in my predicament, call FindWindow, passing it the known name of your external app's main window, to get the handle you need.
I had the same problem. The best solution I have found is to call ShowWindow with the flag SW_MINIMIZE, and then with SW_RESTORE. :D
Another possible solution:
// Code to display a window regardless of its current state
ShowWindow(hWnd, SW_SHOW); // Make the window visible if it was hidden
ShowWindow(hWnd, SW_RESTORE); // Next, restore it if it was minimized
SetForegroundWindow(hWnd); // Finally, activate the window
from comments at: http://msdn.microsoft.com/en-us/library/ms633548%28VS.85%29.aspx
Tray calling ShowWindow(handle, SW_RESTORE); after SetForegroundWindow(handle);
This might solve your problem.
It sounds like you're trying to perform an action that has the same result as alt-tabbing, which brings the window back if it was minimized while "remembering" if it was maximized.
NativeMethods.cs:
using System;
using System.Diagnostics;
using System.Runtime.InteropServices;
// Specify your namespace here
namespace <your.namespace>
{
static class NativeMethods
{
// This is the Interop/WinAPI that will be used
[DllImport("user32.dll")]
static extern void SwitchToThisWindow(IntPtr hWnd, bool fUnknown);
}
}
Main code:
// Under normal circumstances, only one process with one window exists
Process[] processes = Process.GetProcessesByName("ExternalApp.exe");
if (processes.Length > 0 && processes[0].MainWindowHandle != IntPtr.Zero)
{
// Since this simulates alt-tab, it restores minimized windows to their previous state
SwitchToThisWindow(process.MainWindowHandle, true);
return true;
}
// Multiple things are happening here
// First, the ProgramFilesX86 variable automatically accounts for 32-bit or 64-bit systems and returns the correct folder
// Secondly, $-strings are the C# shortcut for string.format() (It automatically calls .ToString() on each variable contained in { })
// Thirdly, if the process was able to start, the return value is not null
try { if (Process.Start($"{System.Environment.SpecialFolder.ProgramFilesX86}\\ExternalApp\\ExternalApp.exe") != null) return true; }
catch
{
// Code for handling an exception (probably FileNotFoundException)
// ...
return false;
}
// Code for when the external app was unable to start without producing an exception
// ...
return false;
I hope this provides a much simpler solution.
(General Rule: If a string value is ordinal, i.e. it belongs to something and isn't just a value, then it is better to get it programmatically. You'll save yourself a lot of trouble when changing things. In this case, I'm assuming that the install location can be converted to a global constant, and the .exe name can be found programmatically.)
I know its too late, still my working code is as follows so that someone later can get quick help :)
using System.Runtime.InteropServices;
using System.Diagnostics;
[DllImport("user32.dll")]
static extern bool SetForegroundWindow(IntPtr hWnd);
[DllImport("user32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
static extern bool ShowWindow(IntPtr hWnd, int nCmdShow);
[DllImport("user32.dll", EntryPoint = "FindWindow")]
public static extern IntPtr FindWindowByCaption(IntPtr ZeroOnly, string lpWindowName);
private static void ActivateApp(string processName)
{
Process[] p = Process.GetProcessesByName(processName);
if (p.Length > 0)
{
IntPtr handle = FindWindowByCaption(IntPtr.Zero, p[0].ProcessName);
ShowWindow(handle, 9); // SW_RESTORE = 9,
SetForegroundWindow(handle);
}
}
ActivateApp(YOUR_APP_NAME);
Actually, FindWindowByCaption is the key here, this method collects the window handle correctly when app is running silently in the system tray and also when app is minimized.

WM_HELP stops being send when vtk is started or spy++ is running

In our software we occasionally use sending WM_HELP via SendMessage api to a control. Normally the "HelpRequested" event is then fired (or up in the parent hierarchy until an event handler is registered).
We included an external complex 3d visualization library called "VTK" and after that, this Message passing does not work anymore. In trying to track down the problem I used Spy++ to see whether the message is shown there and realized that running spy++ is generating the same problem! (Also without any vtk stuff). It can be shown with this little Program:
using System.Diagnostics;
using System.Runtime.InteropServices;
using System.Windows.Forms;
namespace TestHelp
{
public partial class Form1 : Form
{
[System.Runtime.InteropServices.StructLayout(System.Runtime.InteropServices.LayoutKind.Sequential)]
struct HelpInfo
{
public uint cbSize;
public int iContextType;
public int iCtrlID;
public int hItemHandle;
public int dwContextID;
public int MouseX;
public int MouseY;
}
[DllImport("user32.DLL", EntryPoint = "SendMessage", SetLastError = true)]
private static extern int SendHelpMessage(int hWnd, uint Msg, uint wparam, ref HelpInfo helpinfo);
public static void RaiseHelp(Control ctrl)
{
HelpInfo helpInfo = new HelpInfo
{
cbSize = 48,
iContextType = 1,
iCtrlID = 0,
hItemHandle = ctrl.Handle.ToInt32(),
dwContextID = 0,
MouseX = 10,
MouseY = 10,
};
var res = SendHelpMessage(ctrl.Handle.ToInt32(), 0x053, 0, ref helpInfo);
Debug.WriteLine($"SendMessage returns:{res}");
}
public Form1()
{
InitializeComponent();
button1.HelpRequested += (sender, hlpevent) => { Trace.WriteLine("HelpRequested called"); };
timer = new Timer() {Interval = 1000, Enabled = true};
timer.Tick += (sender, args) => RaiseHelp(button1);
}
private Timer timer;
}
}
The form only contains a single button named "button1".
When you start in debugger you see "HelpRequested called" in Output window every second. When you start Spy++, nothing more, just start, it will stop that! When closing spy++ it continues to work again. Does everyone have an explanation for this behaviour? What is Spy++ doing with my application? My hope is that the same mechanism is responsible for the same problem with vtk (there only in-process, though).
Of course, using win32 api SendMessage may seem inappropriate for a WinForms application, but we don't have time now to refactor all that stuff, and I nevertheless want to understand whats happening here!
Btw.: user window message are not affected (WM_USER to 0x7FFF), checked by overriding WndProc. WM_HELP also does not show in WndProc while spy++ is running, btw.
Problem was wrong size for HelpInfo.cbSize. In 64-bit mode it is 40, in 32-bit it is 28. Yes I should use sizeof(), but this is only allowed in "unsafe" mode.
But how the hell spy++ or VTK interfere with this?

I found some code that shows/hides desktop icons, but it moves the icons in the process. How can I edit the code to not move the icons?

I'm using two batch files for Rainmeter, one to hide all icons and then launch Rainmeter, and another to show all icons and quit Rainmeter to make my desktop look normal again.
My end goal is to make these two batch files into buttons on my task bar that I can click to toggle the look of my desktop.
What I have so far is just the two batch files but all they do is show and hide desktop icons. (I found the code online because I couldn't write it myself)
show.bat
REG ADD "HKCU\Software\Microsoft\Windows\CurrentVersion\Explorer\Advanced" /V HideIcons /T REG_DWORD /D 0 /F
taskkill /f /im explorer.exe
start explorer.exe
hide.bat
REG ADD "HKCU\Software\Microsoft\Windows\CurrentVersion\Explorer\Advanced" /V HideIcons /T REG_DWORD /D 1 /F
taskkill /f /im explorer.exe
start explorer.exe
So the code I found works fine but a lot less smooth than just manually hiding desktop icons... The only problem is that when I run show.bat, my icons go back to a position that I don't want them in.
How can I one, get the batch files to show/hide icons more smoothly, and two, not move the icons around?
PS: Just wanted to stress that I seriously have no idea how the code I found works, so you may have to ELI5.
Firstly, TLDR:
I don't think what you want is possible in a batch file, so I have compiled a little program that will toggle your desktop icons on and off each time it is run, and will not affect the positions.
https://github.com/smithmart/ToggleIcons/raw/main/ToggleIcons.exe
This was thanks to another answer on stack overflow, but from what you say, I don't think you have the skills to use that answer yourself... so i did it for you.
ELI5:
I believe the reason your icons move about is because you are using taskkill to end explorer.exe.
Explorer is the program in windows that runs most of the things you see, like your start bar and desktop, plus when you are browsing through drivers and folders.
So,
taskkill /f /im explorer.exe
stops explorer.exe dead, which is why you see your start bar vanish for a split second when you run your batch.
In stopping it like that, it does not get a chance to save your Icon positions so they always revert back to the last known locations.
The reason the script you found does this is because stopping explorer.exe and then starting it back up again refreshes your desktop and this means the first line:
REG ADD "HKCU\Software\Microsoft\Windows\CurrentVersion\Explorer\Advanced" /V HideIcons /T REG_DWORD /D 1 /F
can take effect. This line changes a setting in windows to say "hide my desktop icons"
Solution(kind of)
I do not know a way in a simple batch file of refreshing your desktop settings, but, I did see this answer on stack overflow which is written in c#
How to refresh/reload Desktop
I know you probably don't have the knowledge to use this answer so I have made a little exe for you that just toggles your icons
https://github.com/smithmart/ToggleIcons/raw/main/ToggleIcons.exe
It is called ToggleIcons.exe
each time you run it, all it does is toggle desktop icons on or off
To use it, just pop it in the same folder as your batch file and add the line:
ToggleIcons.exe
to your script.
you can remove the 3 lines you already have, as this basically does all those 3 things. But, it does not restart explorer.exe which means that your icons will not move anywhere
I have also put the source code for you as taking candy from strangers is often not ideal, so if you don't feel comfortable using it I will not be offended! :D
Just in case the link to other answer is lost, here is the source:
class Program
{
//Thanks to https://stackoverflow.com/questions/17503289/how-to-refresh-reload-desktop
[DllImport("user32.dll", SetLastError = true)]
static extern IntPtr FindWindow(string lpClassName, string lpWindowName);
[DllImport("user32.dll", SetLastError = true)]
static extern IntPtr GetWindow(IntPtr hWnd, GetWindow_Cmd uCmd);
[DllImport("user32.dll", CharSet = CharSet.Auto)]
static extern IntPtr SendMessage(IntPtr hWnd, UInt32 Msg, IntPtr wParam, IntPtr lParam);
enum GetWindow_Cmd : uint
{
GW_HWNDFIRST = 0,
GW_HWNDLAST = 1,
GW_HWNDNEXT = 2,
GW_HWNDPREV = 3,
GW_OWNER = 4,
GW_CHILD = 5,
GW_ENABLEDPOPUP = 6
}
private const int WM_COMMAND = 0x111;
[DllImport("user32.dll", SetLastError = true)]
static extern IntPtr FindWindowEx(IntPtr hwndParent, IntPtr hwndChildAfter, string lpszClass, string lpszWindow);
private delegate bool EnumWindowsProc(IntPtr hWnd, IntPtr lParam);
[DllImport("user32.dll", CharSet = CharSet.Unicode)]
private static extern int GetWindowText(IntPtr hWnd, StringBuilder strText, int maxCount);
[DllImport("user32.dll", CharSet = CharSet.Unicode)]
private static extern int GetWindowTextLength(IntPtr hWnd);
[DllImport("user32.dll")]
private static extern bool EnumWindows(EnumWindowsProc enumProc, IntPtr lParam);
[DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)]
static extern int GetClassName(IntPtr hWnd, StringBuilder lpClassName, int nMaxCount);
[DllImport("user32.dll", SetLastError = false)]
static extern IntPtr GetShellWindow();
public static string GetWindowText(IntPtr hWnd)
{
int size = GetWindowTextLength(hWnd);
if (size++ > 0)
{
var builder = new StringBuilder(size);
GetWindowText(hWnd, builder, builder.Capacity);
return builder.ToString();
}
return String.Empty;
}
public static IEnumerable<IntPtr> FindWindowsWithClass(string className)
{
IntPtr found = IntPtr.Zero;
List<IntPtr> windows = new List<IntPtr>();
EnumWindows(delegate (IntPtr wnd, IntPtr param)
{
StringBuilder cl = new StringBuilder(256);
GetClassName(wnd, cl, cl.Capacity);
if (cl.ToString() == className && (GetWindowText(wnd) == "" || GetWindowText(wnd) == null))
{
windows.Add(wnd);
}
return true;
},
IntPtr.Zero);
return windows;
}
static void ToggleDesktopIcons()
{
var toggleDesktopCommand = new IntPtr(0x7402);
IntPtr hWnd = IntPtr.Zero;
if (Environment.OSVersion.Version.Major < 6 || Environment.OSVersion.Version.Minor < 2) //7 and -
hWnd = GetWindow(FindWindow("Progman", "Program Manager"), GetWindow_Cmd.GW_CHILD);
else
{
IEnumerable<IntPtr> ptrs = FindWindowsWithClass("WorkerW");
int i = 0;
while (hWnd == IntPtr.Zero && i < ptrs.Count())
{
hWnd = FindWindowEx(ptrs.ElementAt(i), IntPtr.Zero, "SHELLDLL_DefView", null);
i++;
}
}
if (hWnd == IntPtr.Zero)
{
//"SHELLDLL_DefView" was not found as a child within WorkerW - Lets check the current ShellWindow
IntPtr desktop = GetShellWindow();
hWnd = FindWindowEx(desktop, IntPtr.Zero, "SHELLDLL_DefView", null);
}
if (hWnd != IntPtr.Zero)
{
SendMessage(hWnd, WM_COMMAND, toggleDesktopCommand, IntPtr.Zero);
}
}
static void Main(string[] args)
{
ToggleDesktopIcons();
}
}
Update:
The process "SHELLDLL_DefView" is where we need to send the command to toggle the icons and this actually starts life as a child of progman. After the user activates some other features (unsure which ones, but Windows + Tab is one) it switches parent to WorkerW
Changed this code to check within the currentShellWindow
Dim wsh
Set wsh = CreateObject("Shell.Application")
wsh.ToggleDesktop 'show and hide the desktop

Drag & Drop for SpecialFolders

I have an application that allows users to drag and drop files or entire folders into a special "drop area," at which point all files are processed. The application is being developed using WPF, and this particular XAML view sets "AllowDrop" to true and handles the Drop event in code-behind.
Everything is working for normal files and standrard Windows folders. However, if the user drops a special Windows folder (e.g., Pictures, Videos), then the functionality does not work. It would appear this is because the contents of DragEventArgs.Data are not a DataFormats.FileDrop enum. That's not the case with other folders or files.
My code for handling the drop, in part, is:
private void OnDrop(object Sender, DragEventArgs E)
{
if (E.Data.GetDataPresent(DataFormats.FileDrop))
{
var _droppedFilePaths = E.Data.GetData(DataFormats.FileDrop, true) as string[];
// Process the files....
}
}
Is there any way to identify that the drop data contains the Windows 7 pictures library and map back to its actual path?
Using the solution described here, I wrote the following method:
const string ShellIdListArrayName = "Shell IDList Array";
static IEnumerable<string> GetPathsFromShellIDListArray(IDataObject data)
{
if (data.GetDataPresent(ShellIdListArrayName))
{
var ms = (MemoryStream)data.GetData(ShellIdListArrayName);
byte[] bytes = ms.ToArray();
IntPtr p = Marshal.AllocHGlobal(bytes.Length);
Marshal.Copy(bytes, 0, p, bytes.Length);
uint cidl = (uint)Marshal.ReadInt32(p, 0);
int offset = sizeof(uint);
IntPtr parentpidl = (IntPtr)((int)p + (uint)Marshal.ReadInt32(p, offset));
StringBuilder path = new StringBuilder(256);
SHGetPathFromIDList(parentpidl, path);
for (int i = 1; i <= cidl; ++i)
{
offset += sizeof(uint);
IntPtr relpidl = (IntPtr)((int)p + (uint)Marshal.ReadInt32(p, offset));
IntPtr abspidl = ILCombine(parentpidl, relpidl);
if (SHGetPathFromIDList(abspidl, path) != 0)
{
yield return path.ToString();
}
ILFree(abspidl);
}
}
}
[DllImport("shell32.dll")]
public static extern int SHGetPathFromIDList(IntPtr pidl, StringBuilder pszPath);
[DllImport("shell32.dll")]
public static extern IntPtr ILCombine(IntPtr pidl1, IntPtr pidl2);
[DllImport("shell32.dll")]
public static extern void ILFree(IntPtr pidl);
You can just pass e.Data from your event handler to this method, and you will get a sequence of paths (assuming the items do have a path of course... for instance, "My computer" doesn't have a path)

How to simulate multimedia key press (in C)?

Modern keyboards have special multimedia keys, e.g. 'Pause/Play' or 'Open Web Browser'. Is it possible to write a program that "presses" these keys?
I would prefer solution in C, but I would accept a language agnostic solution, too.
Use the SendInput Windows API, if you are talking about programming under Win32.
You need to build INPUT structures, setting the type member to INPUT_KEYBOARD. In the ki member (KEYBDINPUT type), you can set vk (virtual key) to your desired VK code (for example, VK_MEDIA_NEXT_TRACK, VK_MEDIA_STOP).
Virtual key codes: http://msdn.microsoft.com/en-us/library/dd375731(v=VS.85).aspx
SendInput Function: http://msdn.microsoft.com/en-us/library/ms646310(v=VS.85).aspx
I've not tested the following, but should be like this:
KEYBDINPUT kbi;
kbi.wVk = VK_MEDIA_STOP; // Provide your own
kbi.wScan = 0;
kbi.dwFlags = 0; // See docs for flags (mm keys may need Extended key flag)
kbi.time = 0;
kbi.dwExtraInfo = (ULONG_PTR) GetMessageExtraInfo();
INPUT input;
input.type = INPUT_KEYBOARD;
input.ki = kbi;
SendInput(1, &input, sizeof(INPUT));
Even more easier than the accepted answer is keybd_event. No structs just a call with numeric parameters.
// C# example:
public const int KEYEVENTF_EXTENDEDKEY = 1;
public const int KEYEVENTF_KEYUP = 2;
public const int VK_MEDIA_NEXT_TRACK = 0xB0;
public const int VK_MEDIA_PLAY_PAUSE = 0xB3;
public const int VK_MEDIA_PREV_TRACK = 0xB1;
[DllImport("user32.dll", SetLastError = true)]
public static extern void keybd_event(byte virtualKey, byte scanCode, uint flags, IntPtr extraInfo);
keybd_event(VK_MEDIA_PREV_TRACK, 0, KEYEVENTF_EXTENDEDKEY, IntPtr.Zero);

Resources