This question already has answers here:
C#: How to open Windows Explorer windows with a number of files selected
(5 answers)
Closed 4 years ago.
Could someone give an example on how to use the shell function SHOpenFolderAndSelectItems from C#? I don't quite get how to use these kind of functions and couldn't find it on pinvoke.net... =/
Say I have three files called
X:\Pictures\a.jpg
X:\Pictures\s.jpg
X:\Pictures\d.jpg
I then want to open up the X:\Pictures folder with a.jpg, s.jpg and d.jpg selected.
As you seem to have asked twice the same question (the other being C#: How to open Windows Explorer windows with a number of files selected that had no answer) I post my solution to both questions I don't know if I should make one a community wiki.
Searching for an answer after a coworker had the issue I found none so I wrote a small class to do this. The code is on Gist and I will paste the current version at the end of this post.
With your sample files, the syntax will be :
ShowSelectedInExplorer.FilesOrFolders(
#"X:\Pictures\a.jpg",
#"X:\Pictures\s.jpg",
#"X:\Pictures\d.jpg"
);
There are some limitations to my code compared to the low level API, mainly :
Selecting on the desktop is not implemented
The parent directory must be a directory or a drive, so you can't select multiple drives in the My Computer folder for example.
Anyway, here is the ShowSelectedInExplorer class source code :
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.InteropServices.ComTypes;
static class ShowSelectedInExplorer
{
[Flags]
internal enum SHCONT : ushort
{
SHCONTF_CHECKING_FOR_CHILDREN = 0x0010,
SHCONTF_FOLDERS = 0x0020,
SHCONTF_NONFOLDERS = 0x0040,
SHCONTF_INCLUDEHIDDEN = 0x0080,
SHCONTF_INIT_ON_FIRST_NEXT = 0x0100,
SHCONTF_NETPRINTERSRCH = 0x0200,
SHCONTF_SHAREABLE = 0x0400,
SHCONTF_STORAGE = 0x0800,
SHCONTF_NAVIGATION_ENUM = 0x1000,
SHCONTF_FASTITEMS = 0x2000,
SHCONTF_FLATLIST = 0x4000,
SHCONTF_ENABLE_ASYNC = 0x8000
}
[ComImport,
Guid("000214E6-0000-0000-C000-000000000046"),
InterfaceType(ComInterfaceType.InterfaceIsIUnknown),
ComConversionLoss]
internal interface IShellFolder
{
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
void ParseDisplayName(IntPtr hwnd, [In, MarshalAs(UnmanagedType.Interface)] IBindCtx pbc, [In, MarshalAs(UnmanagedType.LPWStr)] string pszDisplayName, [Out] out uint pchEaten, [Out] out IntPtr ppidl, [In, Out] ref uint pdwAttributes);
[PreserveSig]
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
int EnumObjects([In] IntPtr hwnd, [In] SHCONT grfFlags, [MarshalAs(UnmanagedType.Interface)] out IEnumIDList ppenumIDList);
[PreserveSig]
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
int BindToObject([In] IntPtr pidl, [In, MarshalAs(UnmanagedType.Interface)] IBindCtx pbc, [In] ref Guid riid, [Out, MarshalAs(UnmanagedType.Interface)] out IShellFolder ppv);
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
void BindToStorage([In] ref IntPtr pidl, [In, MarshalAs(UnmanagedType.Interface)] IBindCtx pbc, [In] ref Guid riid, out IntPtr ppv);
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
void CompareIDs([In] IntPtr lParam, [In] ref IntPtr pidl1, [In] ref IntPtr pidl2);
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
void CreateViewObject([In] IntPtr hwndOwner, [In] ref Guid riid, out IntPtr ppv);
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
void GetAttributesOf([In] uint cidl, [In] IntPtr apidl, [In, Out] ref uint rgfInOut);
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
void GetUIObjectOf([In] IntPtr hwndOwner, [In] uint cidl, [In] IntPtr apidl, [In] ref Guid riid, [In, Out] ref uint rgfReserved, out IntPtr ppv);
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
void GetDisplayNameOf([In] ref IntPtr pidl, [In] uint uFlags, out IntPtr pName);
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
void SetNameOf([In] IntPtr hwnd, [In] ref IntPtr pidl, [In, MarshalAs(UnmanagedType.LPWStr)] string pszName, [In] uint uFlags, [Out] IntPtr ppidlOut);
}
[ComImport,
Guid("000214F2-0000-0000-C000-000000000046"),
InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
internal interface IEnumIDList
{
[PreserveSig]
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
int Next(uint celt, IntPtr rgelt, out uint pceltFetched);
[PreserveSig]
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
int Skip([In] uint celt);
[PreserveSig]
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
int Reset();
[PreserveSig]
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
int Clone([MarshalAs(UnmanagedType.Interface)] out IEnumIDList ppenum);
}
class NativeMethods
{
static readonly int pointerSize = Marshal.SizeOf(typeof(IntPtr));
[DllImport("ole32.dll", EntryPoint = "CreateBindCtx")]
public static extern int CreateBindCtx_(int reserved, out IBindCtx ppbc);
public static IBindCtx CreateBindCtx()
{
IBindCtx result;
Marshal.ThrowExceptionForHR(CreateBindCtx_(0, out result));
return result;
}
[DllImport("shell32.dll", EntryPoint = "SHGetDesktopFolder", CharSet = CharSet.Unicode, SetLastError = true)]
static extern int SHGetDesktopFolder_([MarshalAs(UnmanagedType.Interface)] out IShellFolder ppshf);
public static IShellFolder SHGetDesktopFolder()
{
IShellFolder result;
Marshal.ThrowExceptionForHR(SHGetDesktopFolder_(out result));
return result;
}
[DllImport("shell32.dll", EntryPoint = "SHOpenFolderAndSelectItems")]
static extern int SHOpenFolderAndSelectItems_(
[In] IntPtr pidlFolder, uint cidl, [In, Optional, MarshalAs(UnmanagedType.LPArray)] IntPtr[] apidl, int dwFlags
);
public static void SHOpenFolderAndSelectItems(IntPtr pidlFolder, IntPtr[] apidl, int dwFlags)
{
var cidl = (apidl != null) ? (uint)apidl.Length : 0U;
var result = NativeMethods.SHOpenFolderAndSelectItems_(pidlFolder, cidl, apidl, dwFlags);
Marshal.ThrowExceptionForHR(result);
}
[DllImport("shell32.dll", CharSet = CharSet.Unicode)]
public static extern IntPtr ILCreateFromPath([In, MarshalAs(UnmanagedType.LPWStr)] string pszPath);
[DllImport("shell32.dll")]
public static extern void ILFree([In] IntPtr pidl);
}
static IntPtr GetShellFolderChildrenRelativePIDL(IShellFolder parentFolder, string displayName)
{
var bindCtx = NativeMethods.CreateBindCtx();
uint pchEaten;
uint pdwAttributes = 0;
IntPtr ppidl;
parentFolder.ParseDisplayName(IntPtr.Zero, null, displayName, out pchEaten, out ppidl, ref pdwAttributes);
return ppidl;
}
static IntPtr PathToAbsolutePIDL(string path)
{
var desktopFolder = NativeMethods.SHGetDesktopFolder();
return GetShellFolderChildrenRelativePIDL(desktopFolder, path);
}
static Guid IID_IShellFolder = typeof(IShellFolder).GUID;
static int pointerSize = Marshal.SizeOf(typeof(IntPtr));
static IShellFolder PIDLToShellFolder(IShellFolder parent, IntPtr pidl)
{
IShellFolder folder;
var result = parent.BindToObject(pidl, null, ref IID_IShellFolder, out folder);
Marshal.ThrowExceptionForHR((int)result);
return folder;
}
static IShellFolder PIDLToShellFolder(IntPtr pidl)
{
return PIDLToShellFolder(NativeMethods.SHGetDesktopFolder(), pidl);
}
static void SHOpenFolderAndSelectItems(IntPtr pidlFolder, IntPtr[] apidl, bool edit)
{
NativeMethods.SHOpenFolderAndSelectItems(pidlFolder, apidl, edit ? 1 : 0);
}
public static void FileOrFolder(string path, bool edit = false)
{
if (path == null) throw new ArgumentNullException("path");
var pidl = PathToAbsolutePIDL(path);
try
{
SHOpenFolderAndSelectItems(pidl, null, edit);
}
finally
{
NativeMethods.ILFree(pidl);
}
}
static IEnumerable<FileSystemInfo> PathToFileSystemInfo(IEnumerable<string> paths)
{
foreach (var path in paths)
{
string fixedPath = path;
if (fixedPath.EndsWith(Path.DirectorySeparatorChar.ToString()) || fixedPath.EndsWith(Path.AltDirectorySeparatorChar.ToString()))
{
fixedPath = fixedPath.Remove(fixedPath.Length - 1);
}
if (Directory.Exists(fixedPath)) yield return new DirectoryInfo(fixedPath);
else if (File.Exists(fixedPath)) yield return new FileInfo(fixedPath);
else
{
throw new FileNotFoundException("The specified file or folder doesn't exists : " + fixedPath, fixedPath);
}
}
}
public static void FilesOrFolders(string parentDirectory, ICollection<string> filenames)
{
if (filenames == null) throw new ArgumentNullException("filenames");
if (filenames.Count == 0) return;
var parentPidl = PathToAbsolutePIDL(parentDirectory);
try
{
var parent = PIDLToShellFolder(parentPidl);
List<IntPtr> filesPidl = new List<IntPtr>(filenames.Count);
foreach (var filename in filenames)
{
filesPidl.Add(GetShellFolderChildrenRelativePIDL(parent, filename));
}
try
{
SHOpenFolderAndSelectItems(parentPidl, filesPidl.ToArray(), false);
}
finally
{
foreach (var pidl in filesPidl)
{
NativeMethods.ILFree(pidl);
}
}
}
finally
{
NativeMethods.ILFree(parentPidl);
}
}
public static void FilesOrFolders(params string[] paths)
{
FilesOrFolders((IEnumerable<string>)paths);
}
public static void FilesOrFolders(IEnumerable<string> paths)
{
FilesOrFolders(PathToFileSystemInfo(paths));
}
public static void FilesOrFolders(IEnumerable<FileSystemInfo> paths)
{
if (paths == null) throw new ArgumentNullException("paths");
if (paths.Count() == 0) return;
var explorerWindows = paths.GroupBy(p => Path.GetDirectoryName(p.FullName));
foreach (var explorerWindowPaths in explorerWindows)
{
var parentDirectory = Path.GetDirectoryName(explorerWindowPaths.First().FullName);
FilesOrFolders(parentDirectory, explorerWindowPaths.Select(fsi => fsi.Name).ToList());
}
}
}
Not a 100% answer, but this snippet shows how to select a single item in the explorer from C#.
private void SelectInFileExplorer(string fullPath)
{
if (string.IsNullOrEmpty(fullPath))
throw new ArgumentNullException("fullPath");
fullPath = Path.GetFullPath(fullPath);
IntPtr pidlList = NativeMethods.ILCreateFromPathW(fullPath);
if (pidlList != IntPtr.Zero)
try
{
// Open parent folder and select item
Marshal.ThrowExceptionForHR(NativeMethods.SHOpenFolderAndSelectItems(pidlList, 0, IntPtr.Zero, 0));
}
finally
{
NativeMethods.ILFree(pidlList);
}
}
static class NativeMethods
{
[DllImport("shell32.dll", ExactSpelling=true)]
public static extern void ILFree(IntPtr pidlList);
[DllImport("shell32.dll", CharSet=CharSet.Unicode, ExactSpelling=true)]
public static extern IntPtr ILCreateFromPathW(string pszPath);
[DllImport("shell32.dll", ExactSpelling=true)]
public static extern int SHOpenFolderAndSelectItems(IntPtr pidlList, uint cild, IntPtr children, uint dwFlags);
}
Check http://www.cnblogs.com/qiuyi21/archive/2009/06/24/1510592.html. The example uses IShellLink to get pidls from path before launching SHOpenFolderAndSelectItems, I would use ILCreateFromPath instead.
Most of the needs would of SHOpoenFolderSelectedItems would be handled by:
For file selection in C# you would normally use: System.Windows.Forms.OpenFileDialog.
For folder selection in C# you would normally use: System.Windows.Forms.FolderBrowserDialog.
You would set an appropriate filter and you can set a selected item initially.
Perhaps this is close enough to what you need?
Related
I'm trying to PInvoke UpdateProcThreadAttribute() with PROC_THREAD_ATTRIBUTE_PREFERRED_NODE attribute, so that I could launch a process on a specific NUMA node. I'm working on Windows Server 2019.
I found this question that helped me to PInvoke UpdateProcThreadAttribute():
How to call CreateProcess() with STARTUPINFOEX from C# and re-parent the child
When I'm using PROC_THREAD_ATTRIBUTE_PARENT_PROCESS everything works fine, but when trying to set PROC_THREAD_ATTRIBUTE_PREFERRED_NODE as an attribute I keep getting error 24: ERROR_BAD_LENGTH (The program issued a command but the command length is incorrect).
public class ProcessCreator
{
[DllImport("kernel32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
static extern bool CreateProcess(
string lpApplicationName, string lpCommandLine, ref SECURITY_ATTRIBUTES lpProcessAttributes,
ref SECURITY_ATTRIBUTES lpThreadAttributes, bool bInheritHandles, uint dwCreationFlags,
IntPtr lpEnvironment, string lpCurrentDirectory, [In] ref STARTUPINFOEX lpStartupInfo,
out PROCESS_INFORMATION lpProcessInformation);
[DllImport("kernel32.dll", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
private static extern bool UpdateProcThreadAttribute(
IntPtr lpAttributeList, uint dwFlags, IntPtr Attribute, IntPtr lpValue,
IntPtr cbSize, IntPtr lpPreviousValue, IntPtr lpReturnSize);
[DllImport("kernel32.dll", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
private static extern bool InitializeProcThreadAttributeList(
IntPtr lpAttributeList, int dwAttributeCount, int dwFlags, ref IntPtr lpSize);
[DllImport("kernel32.dll", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
private static extern bool DeleteProcThreadAttributeList(IntPtr lpAttributeList);
[DllImport("kernel32.dll", SetLastError = true)]
static extern bool CloseHandle(IntPtr hObject);
[DllImport("kernel32.dll")]
static extern uint GetLastError();
public static bool CreateProcess(string appName, string args, string dir, out PROCESS_INFORMATION pInfo, ILogger logger)
{
const int PROC_THREAD_ATTRIBUTE_PARENT_PROCESS = 0x00020000;
const int PROC_THREAD_ATTRIBUTE_PREFERRED_NODE = 0x00020004;
pInfo = new PROCESS_INFORMATION();
var sInfoEx = new STARTUPINFOEX();
sInfoEx.StartupInfo.cb = Marshal.SizeOf(sInfoEx);
IntPtr lpValue = IntPtr.Zero;
try
{
var lpSize = IntPtr.Zero;
var success = InitializeProcThreadAttributeList(IntPtr.Zero, 1, 0, ref lpSize);
if (success || lpSize == IntPtr.Zero)
{
return false;
}
sInfoEx.lpAttributeList = Marshal.AllocHGlobal(lpSize);
success = InitializeProcThreadAttributeList(sInfoEx.lpAttributeList, 1, 0, ref lpSize);
if (!success)
{
return false;
}
// This value should persist until the attribute list is destroyed using the DeleteProcThreadAttributeList function
lpValue = Marshal.AllocHGlobal(IntPtr.Size);
// Setting preferred NUMA to be 0, for example.
Marshal.WriteIntPtr(lpValue, (IntPtr)0);
success = UpdateProcThreadAttribute(
sInfoEx.lpAttributeList,
0,
(IntPtr)PROC_THREAD_ATTRIBUTE_PREFERRED_NODE,
lpValue,
(IntPtr)IntPtr.Size,
IntPtr.Zero,
IntPtr.Zero);
if (!success)
{
logger.Info($"Error: {GetLastError()}");
return false;
}
var pSec = new SECURITY_ATTRIBUTES();
var tSec = new SECURITY_ATTRIBUTES();
pSec.nLength = Marshal.SizeOf(pSec);
tSec.nLength = Marshal.SizeOf(tSec);
return CreateProcess(appName, args, ref pSec, ref tSec, false, 0, IntPtr.Zero, dir, ref sInfoEx, out pInfo);
}
finally
{
// Free the attribute list
if (sInfoEx.lpAttributeList != IntPtr.Zero)
{
DeleteProcThreadAttributeList(sInfoEx.lpAttributeList);
Marshal.FreeHGlobal(sInfoEx.lpAttributeList);
}
Marshal.FreeHGlobal(lpValue);
// Close process and thread handles
if (pInfo.hProcess != IntPtr.Zero)
{
CloseHandle(pInfo.hProcess);
}
if (pInfo.hThread != IntPtr.Zero)
{
CloseHandle(pInfo.hThread);
}
}
}
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
struct STARTUPINFOEX
{
public STARTUPINFO StartupInfo;
public IntPtr lpAttributeList;
}
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
struct STARTUPINFO
{
public Int32 cb;
public string lpReserved;
public string lpDesktop;
public string lpTitle;
public Int32 dwX;
public Int32 dwY;
public Int32 dwXSize;
public Int32 dwYSize;
public Int32 dwXCountChars;
public Int32 dwYCountChars;
public Int32 dwFillAttribute;
public Int32 dwFlags;
public Int16 wShowWindow;
public Int16 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;
}
[StructLayout(LayoutKind.Sequential)]
public struct SECURITY_ATTRIBUTES
{
public int nLength;
public IntPtr lpSecurityDescriptor;
public int bInheritHandle;
}
}
Any help would be much appreciated.
how to delete multi-items via C# or windows api, I have search for this for a long time and no solution. I used FolderItemVerb in Shell32.dll to delete file one by one, but it would pop a dialog at same time. I will be appreciated if you know how to solve this problem. Thank you.
It isn't for the faint of heart!
Code compatible with Windows >= Vista, no XP! The XP code is at the end
This is the first time I take a look at the Shell32 interfaces... Wow... Even the most simple things are complex :-) But then, COM is always complex... Now... There are 2.5 competing data structures/interfaces for manipulating files in Shell... IShellFolder (the old COM interface, not used in this sample), IShellItem (the new COM interface, used in this sample), IDLIST (here used as a PIDLIST_ABSOLUTE, used for "collecting" multiple files together. I count it as 0.5 😀). I hope there is no memory leak anywhere (always complex). Note that .NET will free COM objects automatically. I've even added some code that I've written to help me debug (like the code to get the list of verbs supported).
Now, here there are the COM interfaces plus some Shell32.dll PInvoke methods.
[StructLayout(LayoutKind.Sequential)]
public struct PIDLIST_ABSOLUTE
{
public IntPtr Ptr;
}
[ComImport]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
[Guid("43826d1e-e718-42ee-bc55-a1e261c37bfe")]
public interface IShellItem
{
void BindToHandler(
IntPtr pbc,
[In, MarshalAs(UnmanagedType.LPStruct)] Guid bhid,
[In, MarshalAs(UnmanagedType.LPStruct)] Guid riid,
[MarshalAs(UnmanagedType.IUnknown)] out object ppv);
void GetParent(out IShellItem ppsi);
void GetDisplayName(int sigdnName, out IntPtr ppszName);
void GetAttributes(uint sfgaoMask, out uint psfgaoAttribs);
[PreserveSig]
int Compare(IShellItem psi, uint hint, out int piOrder);
}
[ComImport]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
[Guid("70629033-e363-4a28-a567-0db78006e6d7")]
public interface IEnumShellItems
{
void Next(int celt, [Out, MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 2)] IShellItem[] rgelt, out int pceltFetched);
void Skip(int celt);
void Reset();
void Clone(out IEnumShellItems ppenum);
}
[ComImport]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
[Guid("b63ea76d-1f85-456f-a19c-48159efa858b")]
public interface IShellItemArray
{
void BindToHandler(
IntPtr pbc,
[In, MarshalAs(UnmanagedType.LPStruct)] Guid bhid,
[In, MarshalAs(UnmanagedType.LPStruct)] Guid riid,
[MarshalAs(UnmanagedType.IUnknown)] out object ppvOut);
void GetPropertyStore(
uint flags,
[In, MarshalAs(UnmanagedType.LPStruct)] Guid riid,
[MarshalAs(UnmanagedType.IUnknown)] out object ppv);
void GetPropertyDescriptionList(
IntPtr keyType,
[In, MarshalAs(UnmanagedType.LPStruct)] Guid riid,
[MarshalAs(UnmanagedType.IUnknown)] out object ppv);
void GetAttributes(uint AttribFlags, uint sfgaoMask, out uint psfgaoAttribs);
void GetCount(out int pdwNumItems);
void GetItemAt(int dwIndex, out IShellItem ppsi);
void EnumItems(out IEnumShellItems ppenumShellItems);
}
[ComImport]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
[Guid("000214e4-0000-0000-c000-000000000046")]
public interface IContextMenu
{
[PreserveSig]
int QueryContextMenu(IntPtr hMenu, uint indexMenu, int idCmdFirst, int idCmdLast, uint uFlags);
void InvokeCommand([In] ref CMINVOKECOMMANDINFOEX pici);
[PreserveSig]
int GetCommandString(UIntPtr idCmd, uint uType, IntPtr pReserved, IntPtr pszName, int cchMax);
}
[StructLayout(LayoutKind.Sequential)]
public struct CMINVOKECOMMANDINFOEX
{
public int cbSize;
public uint fMask;
public IntPtr hwnd;
// Non-unicode verbs (are there unicode verbs?)
[MarshalAs(UnmanagedType.LPStr)]
public string lpVerb;
[MarshalAs(UnmanagedType.LPStr)]
public string lpParameters;
[MarshalAs(UnmanagedType.LPStr)]
public string lpDirectory;
public int nShow;
public uint dwHotKey;
public IntPtr hIcon;
[MarshalAs(UnmanagedType.LPStr)]
public string lpTitle;
// Use CMIC_MASK_UNICODE
[MarshalAs(UnmanagedType.LPWStr)]
public string lpVerbW;
[MarshalAs(UnmanagedType.LPWStr)]
public string lpParametersW;
[MarshalAs(UnmanagedType.LPWStr)]
public string lpDirectoryW;
[MarshalAs(UnmanagedType.LPWStr)]
public string lpTitleW;
public int ptInvokeX;
public int ptInvokeY;
}
// Windows >= Vista
public static class ShellItemUtilities
{
public static readonly Guid FOLDERID_RecycleBinFolder = new Guid("b7534046-3ecb-4c18-be4e-64cd4cb7d6ac");
public static readonly Guid BHID_EnumItems = new Guid("94f60519-2850-4924-aa5a-d15e84868039");
public static readonly Guid BHID_SFUIObject = new Guid("3981e225-f559-11d3-8e3a-00c04f6837d5");
// From Windows 7
[DllImport("Shell32.dll", ExactSpelling = true, SetLastError = false)]
public static extern int SHGetKnownFolderItem(
[In, MarshalAs(UnmanagedType.LPStruct)] Guid rfid,
uint dwFlags,
IntPtr hToken,
[In, MarshalAs(UnmanagedType.LPStruct)] Guid riid,
out IShellItem ppv);
// For Windows Vista
[DllImport("Shell32.dll", ExactSpelling = true, SetLastError = false)]
public static extern int SHCreateItemFromIDList(PIDLIST_ABSOLUTE pidl, [In, MarshalAs(UnmanagedType.LPStruct)] Guid riid, out IShellItem ppv);
// For Windows Vista
[DllImport("Shell32.dll", ExactSpelling = true, SetLastError = false)]
public static extern int SHGetKnownFolderIDList(
[In, MarshalAs(UnmanagedType.LPStruct)] Guid rfid,
uint dwFlags,
IntPtr hToken,
out PIDLIST_ABSOLUTE ppidl);
// From Windows Vista
[DllImport("Shell32.dll", ExactSpelling = true, SetLastError = false)]
public static extern int SHGetIDListFromObject([MarshalAs(UnmanagedType.Interface)] object punk, out PIDLIST_ABSOLUTE ppidl);
[DllImport("Shell32.dll", ExactSpelling = true, SetLastError = false)]
public static extern int SHCreateShellItemArrayFromIDLists(int cidl, [In] PIDLIST_ABSOLUTE[] rgpidl, out IShellItemArray ppsiItemArray);
public static IEnumerable<IShellItem> Enumerate(this IShellItem si)
{
object pesiTemp;
si.BindToHandler(IntPtr.Zero, BHID_EnumItems, typeof(IEnumShellItems).GUID, out pesiTemp);
var pesi = (IEnumShellItems)pesiTemp;
var items = new IShellItem[10];
while (true)
{
int fetched;
pesi.Next(1, items, out fetched);
if (fetched == 0)
{
break;
}
yield return items[0];
}
}
}
public static class ContextMenuUtilities
{
[DllImport("User32.dll", ExactSpelling = true, SetLastError = true)]
public static extern IntPtr CreateMenu();
[DllImport("User32.dll", ExactSpelling = true, SetLastError = true)]
public static extern bool DestroyMenu(IntPtr hMenu);
[DllImport("User32.dll", ExactSpelling = true, SetLastError = true)]
public static extern int GetMenuItemCount(IntPtr hMenu);
[DllImport("User32.dll", ExactSpelling = true, SetLastError = true)]
public static extern uint GetMenuItemID(IntPtr hMenu, int nPos);
[DllImport("User32.dll", CharSet = CharSet.Unicode, EntryPoint = "GetMenuStringW", ExactSpelling = true, SetLastError = true)]
public static extern int GetMenuString(IntPtr hMenu, uint uIDItem, [Out] StringBuilder lpString, int nMaxCount, uint uFlag);
public static string[] GetVerbs(IContextMenu cm, bool ansi = true)
{
IntPtr menu = IntPtr.Zero;
try
{
menu = CreateMenu();
// It isn't clear why short.MaxValue, but 0x7FFF is very used around the .NET!
int res = cm.QueryContextMenu(menu, 0, 0, short.MaxValue, 0);
if (res < 0)
{
Marshal.ThrowExceptionForHR(res);
}
//var sb = new StringBuilder(128);
int count = GetMenuItemCount(menu);
var verbs = new List<string>(count);
var handle = default(GCHandle);
try
{
var bytes = new byte[ansi ? 128 : 256];
handle = GCHandle.Alloc(bytes, GCHandleType.Pinned);
IntPtr ptr = handle.AddrOfPinnedObject();
for (int i = 0; i < count; i++)
{
uint id = GetMenuItemID(menu, i);
if (id == uint.MaxValue)
{
continue;
}
//GetMenuString(menu, (uint)i, sb, sb.Capacity, 0x00000400 /* MF_BYPOSITION */);
//string description = sb.ToString();
//sb.Clear();
res = cm.GetCommandString((UIntPtr)id, ansi ? (uint)0x00000002 /* GCS_VALIDATEA */ : 0x00000006 /* GCS_VALIDATEW */, IntPtr.Zero, ptr, bytes.Length);
if (res < 0)
{
continue;
}
if (res == 0)
{
res = cm.GetCommandString((UIntPtr)id, ansi ? (uint)0x00000000 /* GCS_VERBA */ : 0x00000004 /* GCS_VERBW */, IntPtr.Zero, ptr, bytes.Length);
if (res < 0)
{
Marshal.ThrowExceptionForHR(res);
}
verbs.Add(ansi ? Marshal.PtrToStringAnsi(ptr) : Marshal.PtrToStringUni(ptr));
}
}
}
finally
{
if (handle.IsAllocated)
{
handle.Free();
}
}
return verbs.ToArray();
}
finally
{
if (menu != IntPtr.Zero)
{
DestroyMenu(menu);
}
}
}
}
And then finally a small example program that uses it... It is a small console method that will list all the files that are present in the recycle bin, put 10 of them in an array and delete them in a single operation (verb). The SHGetKnownFolderItem is from Windows 7 on, so I'm using SHGetKnownFolderIDList + SHCreateItemFromIDList that are from Windows Vista.
The code here enumerates the IShellItem files contained in the recycle bin, saves their PIDL_ABSOLUTE in a List<>, from that List<> creates a IShellItemArray, on that IShellItemArray binds a IContextMenu, for that IContextMenu executes the delete verb. Clearly by adding/not adding all the PIDL_ABSOLUTE to the List<> you can control which files will be deleted.
private static void TestShellItem()
{
IShellItem recyleBin;
string str;
IntPtr ptr = IntPtr.Zero;
int res;
//// From Windows 7
//res = ShellItemUtilities.SHGetKnownFolderItem(ShellItemUtilities.FOLDERID_RecycleBinFolder, 0, IntPtr.Zero, typeof(IShellItem).GUID, out recyleBin);
//if (res < 0)
//{
// Marshal.ThrowExceptionForHR(res);
//}
// Windows >= Vista equivalent
var pidl = default(PIDLIST_ABSOLUTE);
try
{
res = ShellItemUtilities.SHGetKnownFolderIDList(ShellItemUtilities.FOLDERID_RecycleBinFolder, 0, IntPtr.Zero, out pidl);
if (res < 0)
{
Marshal.ThrowExceptionForHR(res);
}
res = ShellItemUtilities.SHCreateItemFromIDList(pidl, typeof(IShellItem).GUID, out recyleBin);
if (res < 0)
{
Marshal.ThrowExceptionForHR(res);
}
}
finally
{
Marshal.FreeCoTaskMem(pidl.Ptr);
}
//// Example of use of GetDisplayName
//try
//{
// recyleBin.GetDisplayName(2, out ptr);
// str = Marshal.PtrToStringUni(ptr);
//}
//finally
//{
// if (ptr != IntPtr.Zero)
// {
// Marshal.FreeCoTaskMem(ptr);
// ptr = IntPtr.Zero;
// }
//}
var pids = new List<PIDLIST_ABSOLUTE>();
try
{
foreach (IShellItem si in recyleBin.Enumerate())
{
try
{
si.GetDisplayName(0, out ptr);
str = Marshal.PtrToStringUni(ptr);
// Some condition to include/exclude...
if (pids.Count < 10)
{
Console.WriteLine(str);
// Remember to free the pidl!
res = ShellItemUtilities.SHGetIDListFromObject(si, out pidl);
if (res < 0)
{
Marshal.ThrowExceptionForHR(res);
}
pids.Add(pidl);
}
}
finally
{
if (ptr != IntPtr.Zero)
{
Marshal.FreeCoTaskMem(ptr);
ptr = IntPtr.Zero;
}
}
}
var pids2 = pids.ToArray();
IShellItemArray sia;
res = ShellItemUtilities.SHCreateShellItemArrayFromIDLists(pids2.Length, pids2, out sia);
if (res < 0)
{
Marshal.ThrowExceptionForHR(res);
}
object cmTemp;
sia.BindToHandler(IntPtr.Zero, ShellItemUtilities.BHID_SFUIObject, typeof(IContextMenu).GUID, out cmTemp);
var cm = (IContextMenu)cmTemp;
// To see verbs
//var verbsAnsi = ContextMenuUtilities.GetVerbs(cm, true);
//var verbsUnicode = ContextMenuUtilities.GetVerbs(cm, false);
var cmd = new CMINVOKECOMMANDINFOEX
{
cbSize = Marshal.SizeOf(typeof(CMINVOKECOMMANDINFOEX)),
fMask = 0x00000400 /* CMIC_MASK_FLAG_NO_UI */,
lpVerb = "delete",
};
cm.InvokeCommand(ref cmd);
}
finally
{
foreach (var pid in pids)
{
Marshal.FreeCoTaskMem(pid.Ptr);
}
}
//// Verb executed one by one
//foreach (var item in recyleBin.Enumerate())
//{
// object cmTemp;
// item.BindToHandler(IntPtr.Zero, ShellItemUtilities.BHID_SFUIObject, typeof(IContextMenu).GUID, out cmTemp);
// var cm = (IContextMenu)cmTemp;
////// To see verbs
//// var verbsAnsi = ContextMenuUtilities.GetVerbs(cm, true);
//// var verbsUnicode = ContextMenuUtilities.GetVerbs(cm, false);
// var cmd = new CMINVOKECOMMANDINFOEX
// {
// cbSize = Marshal.SizeOf(typeof(CMINVOKECOMMANDINFOEX)),
// fMask = 0x00000400 /* CMIC_MASK_FLAG_NO_UI */,
// lpVerb = "delete",
// };
// cm.InvokeCommand(ref cmd);
//}
}
Code for Windows XP, uses some code from the other version, you have to take what is needed
It uses the IShellFolder interface. Note that the IContextMenu handling is exactly the same.
[StructLayout(LayoutKind.Sequential)]
public struct PIDLIST_RELATIVE
{
public IntPtr Ptr;
}
[StructLayout(LayoutKind.Sequential)]
public struct LPITEMIDLIST
{
public IntPtr Ptr;
}
[StructLayout(LayoutKind.Sequential)]
public struct PITEMID_CHILD
{
public IntPtr Ptr;
}
public enum STRRET_TYPE
{
WSTR = 0,
OFFSET = 0x1,
CSTR = 0x2
};
[StructLayout(LayoutKind.Sequential, Pack = 8, Size = 268)]
public sealed class STRRET : IDisposable
{
public STRRET_TYPE uType;
public IntPtr pOleStr;
[DllImport("Shlwapi.dll", ExactSpelling = true, SetLastError = false)]
private static extern int StrRetToBSTR(STRRET pstr, PITEMID_CHILD pidl, [MarshalAs(UnmanagedType.BStr)] out string pbstr);
~STRRET()
{
Dispose(false);
}
public override string ToString()
{
return ToString(default(PITEMID_CHILD));
}
public string ToString(PITEMID_CHILD pidl)
{
if (uType == STRRET_TYPE.WSTR)
{
if (pOleStr == IntPtr.Zero)
{
return null;
}
string str = Marshal.PtrToStringUni(pOleStr);
return str;
}
else
{
string str;
int res = StrRetToBSTR(this, pidl, out str);
if (res < 0)
{
Marshal.ThrowExceptionForHR(res);
}
return str;
}
}
#region IDisposable Support
// This code added to correctly implement the disposable pattern.
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
#endregion
private void Dispose(bool disposing)
{
Marshal.FreeCoTaskMem(pOleStr);
pOleStr = IntPtr.Zero;
}
}
[ComImport]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
[Guid("000214e6-0000-0000-c000-000000000046")]
public interface IShellFolder
{
void ParseDisplayName(
IntPtr hwnd,
IntPtr pbc,
[MarshalAs(UnmanagedType.LPWStr)] string pszDisplayName,
out int pchEaten,
out PIDLIST_RELATIVE ppidl,
ref uint pdwAttributes);
void EnumObjects(IntPtr hwnd, uint grfFlags, out IEnumIDList ppenumIDList);
void BindToObject(
PIDLIST_RELATIVE pidl,
IntPtr pbc,
[In, MarshalAs(UnmanagedType.LPStruct)] Guid riid,
[MarshalAs(UnmanagedType.IUnknown)] out object ppv);
void BindToStorage(
PIDLIST_RELATIVE pidl,
IntPtr pbc,
[In, MarshalAs(UnmanagedType.LPStruct)] Guid riid,
[MarshalAs(UnmanagedType.IUnknown)] out object ppv);
[PreserveSig]
int CompareIDs(IntPtr lParam, PIDLIST_RELATIVE pidl1, PIDLIST_RELATIVE pidl2);
void CreateViewObject(
IntPtr hwndOwner,
[In, MarshalAs(UnmanagedType.LPStruct)] Guid riid,
[MarshalAs(UnmanagedType.IUnknown)] out object ppv);
void GetAttributesOf(
int cidl,
[In, MarshalAs(UnmanagedType.LPArray)] LPITEMIDLIST[] apidl,
ref uint rgfInOut);
void GetUIObjectOf(
IntPtr hwndOwner,
int cidl,
[In, MarshalAs(UnmanagedType.LPArray)] PITEMID_CHILD[] apidl,
[In, MarshalAs(UnmanagedType.LPStruct)] Guid riid,
IntPtr rgfReserved,
[MarshalAs(UnmanagedType.IUnknown)] out object ppv);
void GetDisplayNameOf(
PITEMID_CHILD pidl,
uint uFlags,
STRRET pName);
void SetNameOf(
IntPtr hwnd,
PITEMID_CHILD pidl,
[MarshalAs(UnmanagedType.LPWStr)] string pszName,
uint uFlags,
out PITEMID_CHILD ppidlOut);
}
[ComImport]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
[Guid("000214f2-0000-0000-c000-000000000046")]
public interface IEnumIDList
{
void Next(int celt, [Out, MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 2)] PITEMID_CHILD[] rgelt, out int pceltFetched);
void Skip(int celt);
void Reset();
void Clone(out IEnumIDList ppenum);
}
// Windows >= XP
public static class ShellFolderUtilities
{
[DllImport("Shell32.dll", ExactSpelling = true, SetLastError = false)]
public static extern int SHGetSpecialFolderLocation(IntPtr hwnd, int csidl, out PIDLIST_ABSOLUTE ppidl);
[DllImport("Shell32.dll", ExactSpelling = true, SetLastError = false)]
public static extern int SHGetDesktopFolder(out IShellFolder ppshf);
public static readonly int CSIDL_DESKTOP = 0x0000;
public static readonly int CSIDL_BITBUCKET = 0x000a;
// https://blogs.msdn.microsoft.com/oldnewthing/20110830-00/?p=9773
public static void BindToCsidl(int csidl, Guid riid, out object ppv)
{
var pidl = default(PIDLIST_ABSOLUTE);
try
{
int res;
if (csidl != CSIDL_DESKTOP)
{
res = SHGetSpecialFolderLocation(IntPtr.Zero, csidl, out pidl);
if (res < 0)
{
Marshal.ThrowExceptionForHR(res);
}
}
IShellFolder psfDesktop;
res = SHGetDesktopFolder(out psfDesktop);
if (res < 0)
{
Marshal.ThrowExceptionForHR(res);
}
if (csidl == CSIDL_DESKTOP)
{
ppv = psfDesktop;
return;
}
psfDesktop.BindToObject(new PIDLIST_RELATIVE { Ptr = pidl.Ptr }, IntPtr.Zero, riid, out ppv);
}
finally
{
Marshal.FreeCoTaskMem(pidl.Ptr);
}
}
public static IEnumerable<PITEMID_CHILD> Enumerate(this IShellFolder sf)
{
IEnumIDList ppenumIDList;
sf.EnumObjects(IntPtr.Zero, 0x00020 /* SHCONTF_FOLDERS */ | 0x00040 /* SHCONTF_NONFOLDERS */, out ppenumIDList);
if (ppenumIDList == null)
{
yield break;
}
var items = new PITEMID_CHILD[1];
while (true)
{
int fetched;
ppenumIDList.Next(items.Length, items, out fetched);
if (fetched == 0)
{
break;
}
yield return items[0];
}
}
}
And then finally a small example program that uses it...
private static void TestShellFolder()
{
object recycleBinTemp;
ShellFolderUtilities.BindToCsidl(ShellFolderUtilities.CSIDL_BITBUCKET, typeof(IShellFolder).GUID, out recycleBinTemp);
var recycleBin = (IShellFolder)recycleBinTemp;
var pids = new List<PITEMID_CHILD>();
try
{
foreach (PITEMID_CHILD pidl in recycleBin.Enumerate())
{
// Remember to free the pidl!
string str;
using (var ret = new STRRET { uType = STRRET_TYPE.CSTR })
{
recycleBin.GetDisplayNameOf(pidl, 0, ret);
str = ret.ToString(pidl);
}
// Some condition to include/exclude...
if (pids.Count < 10)
{
Console.WriteLine(str);
pids.Add(pidl);
}
else
{
Marshal.FreeCoTaskMem(pidl.Ptr);
}
}
var pids2 = pids.ToArray();
object cmTemp;
recycleBin.GetUIObjectOf(IntPtr.Zero, pids2.Length, pids2, typeof(IContextMenu).GUID, IntPtr.Zero, out cmTemp);
var cm = (IContextMenu)cmTemp;
// To see verbs
//var verbsAnsi = ContextMenuUtilities.GetVerbs(cm, true);
//var verbsUnicode = ContextMenuUtilities.GetVerbs(cm, false);
var cmd = new CMINVOKECOMMANDINFOEX
{
cbSize = Marshal.SizeOf(typeof(CMINVOKECOMMANDINFOEX)),
fMask = 0x00000400 /* CMIC_MASK_FLAG_NO_UI */,
lpVerb = "delete",
};
cm.InvokeCommand(ref cmd);
}
finally
{
foreach (var pid in pids)
{
Marshal.FreeCoTaskMem(pid.Ptr);
}
}
}
First of all add System.Runtime.InteropService to your project. We will use SHEmptyRecycleBin method, which accepts 3 parameters.
After that import the Shell32.dll in your class by using DllImport.
[DllImport("Shell32.dll")]
static extern int SHEmptyRecycleBin(IntPtr hwnd, string pszRootPath, RecycleFlag dwFlags);
Then define an enum for the RecycleBin flags(dwFlags). The values are in Hexadecimal.
enum RecycleFlag : int
{
SHERB_NOCONFIRMATION = 0x00000001, // No confirmation
SHERB_NOPROGRESSUI = 0x00000001, // No progress tracking window
SHERB_NOSOUND = 0x00000004 // No sound played
}
Place the following code in empty recycle bin button which calls the system method in Shell32.dll as:
SHEmptyRecycleBin(IntPtr.Zero, null, RecycleFlag.SHERB_NOSOUND | RecycleFlag.SHERB_NOCONFIRMATION);
reference: here
This question already has answers here:
How do I restart a WPF application? [duplicate]
(8 answers)
Closed 9 years ago.
I have a full-screen WPF application which runs at start-up on Windows 7 Ultimate. In case the application crashes/closes in the event of an unhandled exception I need to restart the WPF application automatically.
What is the simplest way to do it?
in above case u can use a windows service to monitor the application. in the processes wether if its running or not. if it has stoped for any reason then the service must start this application again.
Twist: in Windows Vista microsoft changed windows security system. there for Windows Services will start under Session 0. which is a issue to be consider here. but to execute the Windows applicaton from the Window Service you can use below code.
public class ProcessAsUser
{
[DllImport("advapi32.dll", SetLastError = true)]
private static extern bool CreateProcessAsUser(
IntPtr hToken,
string lpApplicationName,
string lpCommandLine,
ref SECURITY_ATTRIBUTES lpProcessAttributes,
ref SECURITY_ATTRIBUTES lpThreadAttributes,
bool bInheritHandles,
uint dwCreationFlags,
IntPtr lpEnvironment,
string lpCurrentDirectory,
ref STARTUPINFO lpStartupInfo,
out PROCESS_INFORMATION lpProcessInformation);
[DllImport("advapi32.dll", EntryPoint = "DuplicateTokenEx", SetLastError = true)]
private static extern bool DuplicateTokenEx(
IntPtr hExistingToken,
uint dwDesiredAccess,
ref SECURITY_ATTRIBUTES lpThreadAttributes,
Int32 ImpersonationLevel,
Int32 dwTokenType,
ref IntPtr phNewToken);
[DllImport("advapi32.dll", SetLastError = true)]
private static extern bool OpenProcessToken(
IntPtr ProcessHandle,
UInt32 DesiredAccess,
ref IntPtr TokenHandle);
[DllImport("userenv.dll", SetLastError = true)]
private static extern bool CreateEnvironmentBlock(
ref IntPtr lpEnvironment,
IntPtr hToken,
bool bInherit);
[DllImport("userenv.dll", SetLastError = true)]
private static extern bool DestroyEnvironmentBlock(
IntPtr lpEnvironment);
[DllImport("kernel32.dll", SetLastError = true)]
private static extern bool CloseHandle(
IntPtr hObject);
private const short SW_SHOW = 5;
private const uint TOKEN_QUERY = 0x0008;
private const uint TOKEN_DUPLICATE = 0x0002;
private const uint TOKEN_ASSIGN_PRIMARY = 0x0001;
private const int GENERIC_ALL_ACCESS = 0x10000000;
private const int STARTF_USESHOWWINDOW = 0x00000001;
private const int STARTF_FORCEONFEEDBACK = 0x00000040;
private const uint CREATE_UNICODE_ENVIRONMENT = 0x00000400;
private static bool LaunchProcessAsUser(string cmdLine, IntPtr token, IntPtr envBlock)
{
bool result = false;
PROCESS_INFORMATION pi = new PROCESS_INFORMATION();
SECURITY_ATTRIBUTES saProcess = new SECURITY_ATTRIBUTES();
SECURITY_ATTRIBUTES saThread = new SECURITY_ATTRIBUTES();
saProcess.nLength = (uint)Marshal.SizeOf(saProcess);
saThread.nLength = (uint)Marshal.SizeOf(saThread);
STARTUPINFO si = new STARTUPINFO();
si.cb = (uint)Marshal.SizeOf(si);
//if this member is NULL, the new process inherits the desktop
//and window station of its parent process. If this member is
//an empty string, the process does not inherit the desktop and
//window station of its parent process; instead, the system
//determines if a new desktop and window station need to be created.
//If the impersonated user already has a desktop, the system uses the
//existing desktop.
si.lpDesktop = #"WinSta0\Default"; //Modify as needed
si.dwFlags = STARTF_USESHOWWINDOW | STARTF_FORCEONFEEDBACK;
si.wShowWindow = SW_SHOW;
//Set other si properties as required.
result = CreateProcessAsUser(
token,
null,
cmdLine,
ref saProcess,
ref saThread,
false,
CREATE_UNICODE_ENVIRONMENT,
envBlock,
null,
ref si,
out pi);
if (result == false)
{
int error = Marshal.GetLastWin32Error();
string message = String.Format("CreateProcessAsUser Error: {0}", error);
Debug.WriteLine(message);
}
return result;
}
private static IntPtr GetPrimaryToken(int processId)
{
IntPtr token = IntPtr.Zero;
IntPtr primaryToken = IntPtr.Zero;
bool retVal = false;
Process p = null;
try
{
p = Process.GetProcessById(processId);
}
catch (ArgumentException)
{
string details = String.Format("ProcessID {0} Not Available", processId);
Debug.WriteLine(details);
throw;
}
//Gets impersonation token
retVal = OpenProcessToken(p.Handle, TOKEN_DUPLICATE, ref token);
if (retVal == true)
{
SECURITY_ATTRIBUTES sa = new SECURITY_ATTRIBUTES();
sa.nLength = (uint)Marshal.SizeOf(sa);
//Convert the impersonation token into Primary token
retVal = DuplicateTokenEx(
token,
TOKEN_ASSIGN_PRIMARY | TOKEN_DUPLICATE | TOKEN_QUERY,
ref sa,
(int)SECURITY_IMPERSONATION_LEVEL.SecurityIdentification,
(int)TOKEN_TYPE.TokenPrimary,
ref primaryToken);
//Close the Token that was previously opened.
CloseHandle(token);
if (retVal == false)
{
string message = String.Format("DuplicateTokenEx Error: {0}", Marshal.GetLastWin32Error());
Debug.WriteLine(message);
}
}
else
{
string message = String.Format("OpenProcessToken Error: {0}", Marshal.GetLastWin32Error());
Debug.WriteLine(message);
}
//We'll Close this token after it is used.
return primaryToken;
}
private static IntPtr GetEnvironmentBlock(IntPtr token)
{
IntPtr envBlock = IntPtr.Zero;
bool retVal = CreateEnvironmentBlock(ref envBlock, token, false);
if (retVal == false)
{
//Environment Block, things like common paths to My Documents etc.
//Will not be created if "false"
//It should not adversley affect CreateProcessAsUser.
string message = String.Format("CreateEnvironmentBlock Error: {0}", Marshal.GetLastWin32Error());
Debug.WriteLine(message);
}
return envBlock;
}
public static bool Launch(string appCmdLine /*,int processId*/)
{
bool ret = false;
//Either specify the processID explicitly
//Or try to get it from a process owned by the user.
//In this case assuming there is only one explorer.exe
Process[] ps = Process.GetProcessesByName("explorer");
int processId = -1;//=processId
if (ps.Length > 0)
{
processId = ps[0].Id;
}
if (processId > 1)
{
IntPtr token = GetPrimaryToken(processId);
if (token != IntPtr.Zero)
{
IntPtr envBlock = GetEnvironmentBlock(token);
ret = LaunchProcessAsUser(appCmdLine, token, envBlock);
if (envBlock != IntPtr.Zero)
DestroyEnvironmentBlock(envBlock);
CloseHandle(token);
}
}
return ret;
}
}
[StructLayout(LayoutKind.Sequential)]
internal struct PROCESS_INFORMATION
{
public IntPtr hProcess;
public IntPtr hThread;
public uint dwProcessId;
public uint dwThreadId;
}
[StructLayout(LayoutKind.Sequential)]
internal struct SECURITY_ATTRIBUTES
{
public uint nLength;
public IntPtr lpSecurityDescriptor;
public bool bInheritHandle;
}
[StructLayout(LayoutKind.Sequential)]
public struct STARTUPINFO
{
public uint cb;
public string lpReserved;
public string lpDesktop;
public string lpTitle;
public uint dwX;
public uint dwY;
public uint dwXSize;
public uint dwYSize;
public uint dwXCountChars;
public uint dwYCountChars;
public uint dwFillAttribute;
public uint dwFlags;
public short wShowWindow;
public short cbReserved2;
public IntPtr lpReserved2;
public IntPtr hStdInput;
public IntPtr hStdOutput;
public IntPtr hStdError;
}
internal enum SECURITY_IMPERSONATION_LEVEL
{
SecurityAnonymous,
SecurityIdentification,
SecurityImpersonation,
SecurityDelegation
}
internal enum TOKEN_TYPE
{
TokenPrimary = 1,
TokenImpersonation
}
to use above code.
ProcessAsUser.Launch("applicationlocation.exe");
or Simply you can try this.
In your Wpf App.cs code file.
protected override void OnExit(ExitEventArgs e)
{
base.OnExit(e);
System.Windows.Forms.Application.Restart();
}
But this solution will not guarentee that application will start again if closed. so i haved used the Windows Service one.
I am trying to register my application for scanner's scanning action. Following code should do that:
public class Class1
{
[ComImport]
[Guid("641BD880-2DC8-11D0-90EA-00AA0060F86C")]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
public interface IStillImage
{
[PreserveSig]
int RegisterLaunchApplication([In, MarshalAs(UnmanagedType.LPWStr)] string pwszAppName, [In, MarshalAs(UnmanagedType.LPWStr)] string pwszCommandLine);
}
[DllImport("kernel32.dll")]
static extern IntPtr GetModuleHandle(
[MarshalAs(UnmanagedType.LPWStr)] string lpModuleName);
[DllImport("sti.dll", EntryPoint = "StiCreateInstanceW")]
static extern int StiCreateInstance(IntPtr hinst, int dwVer, out IStillImage ppSti, IntPtr punkOuter);
const int STI_VERSION_3 = 0x01000003;
public static void DoStaff()
{
IntPtr hinst = GetModuleHandle(null);
IStillImage sti;
int ret = StiCreateInstance(hinst, STI_VERSION_3, out sti, IntPtr.Zero);
ret = sti.RegisterLaunchApplication("SuperTruperApp", #"c:\Windows\notepad.exe");
}
}
But after running this code I am always getting error -2147024809 => 0x80070057 which should stand for wrong argument.
I found same issue on http://www.tech-archive.net/Archive/DotNet/microsoft.public.dotnet.framework.interop/2008-04/msg00123.html does any one have working solution?
Next question will be about successful unregister :-)
Thanks a lot
I made a great progress on this topic. I copied STI interface implementation from EverNote source code and this solution was working as well.
namespace StiWorks
{
//COPY OF https://github.com/ryanmcdonnell/ScanToEvernote/blob/c8fd7dfed041950499afe7578700199461a37c65/ScanToEvernote/Sti.cs
public enum STI_DEVICE_TYPE : int
{
StiDeviceTypeDefault = 0,
StiDeviceTypeScanner = 1,
StiDeviceTypeDigitalCamera = 2,
StiDeviceTypeStreamingVideo = 3
}
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
public struct STI_DEV_CAPS
{
public int dwGeneric;
}
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
public struct STI_DEVICE_INFORMATIONW
{
private const int STI_MAX_INTERNAL_NAME_LENGTH = 128;
public int dwSize;
public STI_DEVICE_TYPE DeviceType;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = STI_MAX_INTERNAL_NAME_LENGTH)]
string szDeviceInternalName;
public STI_DEV_CAPS DeviceCapabilities;
public int dwHardwareConfiguration;
[MarshalAs(UnmanagedType.LPWStr)]
public string pszVendorDescription;
[MarshalAs(UnmanagedType.LPWStr)]
public string pszDeviceDescription;
[MarshalAs(UnmanagedType.LPWStr)]
public string pszPortName;
[MarshalAs(UnmanagedType.LPWStr)]
public string pszPropProvider;
[MarshalAs(UnmanagedType.LPWStr)]
public string pszLocalName;
}
[Guid("641BD880-2DC8-11D0-90EA-00AA0060F86C"), // IStillImageW
InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
public interface IStillImage // cannot list any base interfaces here
{
// note that IUnknown Interface members are NOT listed here
void Initialize(IntPtr hinst, [In] int dwVersion);
void GetDeviceList([In] int dwType, [In] int dwFlags, [Out] out int pdwItemsReturned, [In, Out] IntPtr ppBuffer);
void GetDeviceInfo([In, MarshalAs(UnmanagedType.LPWStr)] string pwszDeviceName, [In, Out] IntPtr ppBuffer);
void CreateDevice([In, MarshalAs(UnmanagedType.LPWStr)] string pwszDeviceName, [In] int dwMode, [In, Out] IntPtr pDevice, [In, Out] IntPtr punkOuter);
void GetDeviceValue([In, MarshalAs(UnmanagedType.LPWStr)] string pwszDeviceName, [In, MarshalAs(UnmanagedType.LPWStr)] string pValueName, [In, Out] ref int pType, [In, Out] StringBuilder pData, [In, Out] ref int cbData);
void SetDeviceValue([In, MarshalAs(UnmanagedType.LPWStr)] string pwszDeviceName, [In, MarshalAs(UnmanagedType.LPWStr)] string pValueName, [In] int Type, [In, Out] IntPtr pData, [In] int cbData);
void GetSTILaunchInformation([In, Out, MarshalAs(UnmanagedType.LPWStr)] ref string pwszDeviceName, [In, Out] ref int pdwEventCode, [In, Out, MarshalAs(UnmanagedType.LPWStr)] ref string pwszEventName);
void RegisterLaunchApplication([In, MarshalAs(UnmanagedType.LPWStr)] string pwszAppName, [In, MarshalAs(UnmanagedType.LPWStr)] string pwszCommandLine);
void UnregisterLaunchApplication([In, MarshalAs(UnmanagedType.LPWStr)] string pwszAppName);
void EnableHwNotifications([In, MarshalAs(UnmanagedType.LPWStr)] string pwszDeviceName, [In] bool bNewState);
void GetHwNotificationState([In, MarshalAs(UnmanagedType.LPWStr)] string pwszDeviceName, [In, Out] ref bool pbCurrentState);
void RefreshDeviceBus([In, MarshalAs(UnmanagedType.LPWStr)] string pwszDeviceName);
void LaunchApplicationForDevice([In, MarshalAs(UnmanagedType.LPWStr)]
string pwszDeviceName, [In, MarshalAs(UnmanagedType.LPWStr)] string
pwszAppName, [In, Out] IntPtr pStiNofify);
void SetupDeviceParameters([In, Out] ref STI_DEVICE_INFORMATIONW pDeviceInfo);
void WriteToErrorLog([In] int dwMessageType, [In, MarshalAs(UnmanagedType.LPWStr)] string pszMessage);
}
[ComImport, Guid("B323F8E0-2E68-11D0-90EA-00AA0060F86C")]
public class Sti
{
}
and usage in code for application registration
Sti sti = new Sti();
IStillImage stillImage = (IStillImage) sti;
stillImage.RegisterLaunchApplication("MY_ID_I_WANT_TO_BE_IN_REGISTRY", "C:\ApplicationToRegister.exe");
usage in code for application unregistration
Sti sti = new Sti();
IStillImage stillImage = (IStillImage) sti;
stillImage.UnregisterLaunchApplication("MY_ID_I_WANT_TO_BE_IN_REGISTRY");
You missed some methods in your interface and as result you called Initialize method instead of RegisterLaunchApplication method. Please, try use next interface (all methods except RegisterLaunchApplication and UnregisterLaunchApplication are stubs):
[ComImport]
[Guid("641BD880-2DC8-11D0-90EA-00AA0060F86C")]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
public interface IStillImage
{
int Initialize();
int GetDeviceList();
int GetDeviceInfo();
int CreateDevice();
int GetDeviceValue();
int SetDeviceValue();
int GetSTILaunchInformation();
[PreserveSig]
int RegisterLaunchApplication([In, MarshalAs(UnmanagedType.LPWStr)] string pwszAppName, [In, MarshalAs(UnmanagedType.LPWStr)] string pwszCommandLine);
[PreserveSig]
int UnregisterLaunchApplication([In, MarshalAs(UnmanagedType.LPWStr)] string pwszAppName);
}
I need to create a new process but so that it is a "child" of another process not the current process eg re-parent the new process.
The following have got me almost there .NET : How to call CreateProcessAsUser() with STARTUPINFOEX from C# and .NET : How to PInvoke UpdateProcThreadAttribute and http://winprogger.com/launching-a-non-child-process/
using System;
using System.Diagnostics;
using System.IO;
using System.Runtime.InteropServices;
public class ProcessCreator
{
[DllImport("kernel32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
static extern bool CreateProcess(
string lpApplicationName, string lpCommandLine, ref SECURITY_ATTRIBUTES lpProcessAttributes,
ref SECURITY_ATTRIBUTES lpThreadAttributes, bool bInheritHandles, uint dwCreationFlags,
IntPtr lpEnvironment, string lpCurrentDirectory, [In] ref STARTUPINFOEX lpStartupInfo,
out PROCESS_INFORMATION lpProcessInformation);
[DllImport("kernel32.dll", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
private static extern bool UpdateProcThreadAttribute(
out IntPtr lpAttributeList, uint dwFlags, IntPtr Attribute, IntPtr lpValue,
IntPtr cbSize, IntPtr lpPreviousValue, IntPtr lpReturnSize);
[DllImport("kernel32.dll", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
private static extern bool InitializeProcThreadAttributeList(
out IntPtr lpAttributeList, int dwAttributeCount, int dwFlags, ref IntPtr lpSize);
public static bool CreateProcess(int parentProcessId)
{
const uint EXTENDED_STARTUPINFO_PRESENT = 0x00080000;
const int PROC_THREAD_ATTRIBUTE_PARENT_PROCESS = 0x00020000;
var pInfo = new PROCESS_INFORMATION();
var sInfoEx = new STARTUPINFOEX();
sInfoEx.StartupInfo = new STARTUPINFO();
if (parentProcessId > 0)
{
var lpSize = IntPtr.Zero;
IntPtr dummyPtr;
var success = InitializeProcThreadAttributeList(out dummyPtr, 1, 0, ref lpSize);
if (success || lpSize == IntPtr.Zero)
{
return false;
}
sInfoEx.lpAttributeList = Marshal.AllocHGlobal(lpSize);
if (sInfoEx.lpAttributeList == IntPtr.Zero)
{
return false;
}
success = InitializeProcThreadAttributeList(out sInfoEx.lpAttributeList, 1, 0, ref lpSize);
if (!success)
{
return false;
}
var parentHandle = Process.GetProcessById(parentProcessId).Handle;
success = UpdateProcThreadAttribute(
out sInfoEx.lpAttributeList,
0,
(IntPtr)PROC_THREAD_ATTRIBUTE_PARENT_PROCESS,
parentHandle,
(IntPtr)IntPtr.Size,
IntPtr.Zero,
IntPtr.Zero);
if (!success)
{
return false;
}
sInfoEx.StartupInfo.cb = Marshal.SizeOf(sInfoEx);
}
var pSec = new SECURITY_ATTRIBUTES();
var tSec = new SECURITY_ATTRIBUTES();
pSec.nLength = Marshal.SizeOf(pSec);
tSec.nLength = Marshal.SizeOf(tSec);
var lpApplicationName = Path.Combine(Environment.SystemDirectory, "notepad.exe");
return CreateProcess(lpApplicationName, null, ref pSec, ref tSec, false, EXTENDED_STARTUPINFO_PRESENT, IntPtr.Zero, null, ref sInfoEx, out pInfo);
}
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
struct STARTUPINFOEX
{
public STARTUPINFO StartupInfo;
public IntPtr lpAttributeList;
}
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
struct STARTUPINFO
{
public Int32 cb;
public string lpReserved;
public string lpDesktop;
public string lpTitle;
public Int32 dwX;
public Int32 dwY;
public Int32 dwXSize;
public Int32 dwYSize;
public Int32 dwXCountChars;
public Int32 dwYCountChars;
public Int32 dwFillAttribute;
public Int32 dwFlags;
public Int16 wShowWindow;
public Int16 cbReserved2;
public IntPtr lpReserved2;
public IntPtr hStdInput;
public IntPtr hStdOutput;
public IntPtr hStdError;
}
[StructLayout(LayoutKind.Sequential)]
internal struct PROCESS_INFORMATION
{
public IntPtr hProcess;
public IntPtr hThread;
public int dwProcessId;
public int dwThreadId;
}
[StructLayout(LayoutKind.Sequential)]
public struct SECURITY_ATTRIBUTES
{
public int nLength;
public IntPtr lpSecurityDescriptor;
public int bInheritHandle;
}
}
ProcessCreator.CreateProcess(0) starts Notepad as a child of current process which is the default behaviour. So far so good.
If the value passed in is non 0 the code attempts to start Notepad as a child of the process whose process ID matches the input value (I am assuming that process exists for now).
Unfortunately that part does not work and throws the following exception:
FatalExecutionEngineError was detected
Message: The runtime has encountered a fatal error. The address of the error was at 0x69a2c7ad, on thread 0x1de0. The error code is 0xc0000005. This error may be a bug in the CLR or in the unsafe or non-verifiable portions of user code. Common sources of this bug include user marshaling errors for COM-interop or PInvoke, which may corrupt the stack.
Any pointers much appreciated.
There are two issues with your code. First, the lpAttributeList parameter of the InitializeProcThreadAttributeList and UpdateProcThreadAttribute functions must be typed as IntPtr with no out modifier. Second, the lpValue parameter of the UpdateProcThreadAttribute function must be a pointer to the attribute value (in your case, parentHandle), not the value itself. Below is the fixed code.
using System;
using System.Diagnostics;
using System.IO;
using System.Runtime.InteropServices;
public class ProcessCreator
{
[DllImport("kernel32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
static extern bool CreateProcess(
string lpApplicationName, string lpCommandLine, ref SECURITY_ATTRIBUTES lpProcessAttributes,
ref SECURITY_ATTRIBUTES lpThreadAttributes, bool bInheritHandles, uint dwCreationFlags,
IntPtr lpEnvironment, string lpCurrentDirectory, [In] ref STARTUPINFOEX lpStartupInfo,
out PROCESS_INFORMATION lpProcessInformation);
[DllImport("kernel32.dll", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
private static extern bool UpdateProcThreadAttribute(
IntPtr lpAttributeList, uint dwFlags, IntPtr Attribute, IntPtr lpValue,
IntPtr cbSize, IntPtr lpPreviousValue, IntPtr lpReturnSize);
[DllImport("kernel32.dll", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
private static extern bool InitializeProcThreadAttributeList(
IntPtr lpAttributeList, int dwAttributeCount, int dwFlags, ref IntPtr lpSize);
[DllImport("kernel32.dll", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
private static extern bool DeleteProcThreadAttributeList(IntPtr lpAttributeList);
[DllImport("kernel32.dll", SetLastError = true)]
static extern bool CloseHandle(IntPtr hObject);
public static bool CreateProcess(int parentProcessId)
{
const uint EXTENDED_STARTUPINFO_PRESENT = 0x00080000;
const int PROC_THREAD_ATTRIBUTE_PARENT_PROCESS = 0x00020000;
var pInfo = new PROCESS_INFORMATION();
var sInfoEx = new STARTUPINFOEX();
sInfoEx.StartupInfo.cb = Marshal.SizeOf(sInfoEx);
IntPtr lpValue = IntPtr.Zero;
try
{
if (parentProcessId > 0)
{
var lpSize = IntPtr.Zero;
var success = InitializeProcThreadAttributeList(IntPtr.Zero, 1, 0, ref lpSize);
if (success || lpSize == IntPtr.Zero)
{
return false;
}
sInfoEx.lpAttributeList = Marshal.AllocHGlobal(lpSize);
success = InitializeProcThreadAttributeList(sInfoEx.lpAttributeList, 1, 0, ref lpSize);
if (!success)
{
return false;
}
var parentHandle = Process.GetProcessById(parentProcessId).Handle;
// This value should persist until the attribute list is destroyed using the DeleteProcThreadAttributeList function
lpValue = Marshal.AllocHGlobal(IntPtr.Size);
Marshal.WriteIntPtr(lpValue, parentHandle);
success = UpdateProcThreadAttribute(
sInfoEx.lpAttributeList,
0,
(IntPtr)PROC_THREAD_ATTRIBUTE_PARENT_PROCESS,
lpValue,
(IntPtr)IntPtr.Size,
IntPtr.Zero,
IntPtr.Zero);
if (!success)
{
return false;
}
}
var pSec = new SECURITY_ATTRIBUTES();
var tSec = new SECURITY_ATTRIBUTES();
pSec.nLength = Marshal.SizeOf(pSec);
tSec.nLength = Marshal.SizeOf(tSec);
var lpApplicationName = Path.Combine(Environment.SystemDirectory, "notepad.exe");
return CreateProcess(lpApplicationName, null, ref pSec, ref tSec, false, EXTENDED_STARTUPINFO_PRESENT, IntPtr.Zero, null, ref sInfoEx, out pInfo);
}
finally
{
// Free the attribute list
if (sInfoEx.lpAttributeList != IntPtr.Zero)
{
DeleteProcThreadAttributeList(sInfoEx.lpAttributeList);
Marshal.FreeHGlobal(sInfoEx.lpAttributeList);
}
Marshal.FreeHGlobal(lpValue);
// Close process and thread handles
if (pInfo.hProcess != IntPtr.Zero)
{
CloseHandle(pInfo.hProcess);
}
if (pInfo.hThread != IntPtr.Zero)
{
CloseHandle(pInfo.hThread);
}
}
}
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
struct STARTUPINFOEX
{
public STARTUPINFO StartupInfo;
public IntPtr lpAttributeList;
}
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
struct STARTUPINFO
{
public Int32 cb;
public string lpReserved;
public string lpDesktop;
public string lpTitle;
public Int32 dwX;
public Int32 dwY;
public Int32 dwXSize;
public Int32 dwYSize;
public Int32 dwXCountChars;
public Int32 dwYCountChars;
public Int32 dwFillAttribute;
public Int32 dwFlags;
public Int16 wShowWindow;
public Int16 cbReserved2;
public IntPtr lpReserved2;
public IntPtr hStdInput;
public IntPtr hStdOutput;
public IntPtr hStdError;
}
[StructLayout(LayoutKind.Sequential)]
internal struct PROCESS_INFORMATION
{
public IntPtr hProcess;
public IntPtr hThread;
public int dwProcessId;
public int dwThreadId;
}
[StructLayout(LayoutKind.Sequential)]
public struct SECURITY_ATTRIBUTES
{
public int nLength;
public IntPtr lpSecurityDescriptor;
public int bInheritHandle;
}
}