diff --git a/Plugins/WinAlfred.Plugin.Doc/Main.cs b/Plugins/WinAlfred.Plugin.Doc/Main.cs index a8e525dd12..9e7a4d0445 100644 --- a/Plugins/WinAlfred.Plugin.Doc/Main.cs +++ b/Plugins/WinAlfred.Plugin.Doc/Main.cs @@ -71,6 +71,9 @@ namespace WinAlfred.Plugin.Doc }; docsetBasePath = context.PluginMetadata.PluginDirecotry + @"Docset"; + if (!Directory.Exists(docsetBasePath)) + Directory.CreateDirectory(docsetBasePath); + foreach (string path in Directory.GetDirectories(docsetBasePath)) { string name = path.Substring(path.LastIndexOf('\\') + 1); diff --git a/WinAlfred.Plugin.System/CMD.cs b/WinAlfred.Plugin.System/CMD.cs index 19b23d58bb..64c42b40e5 100644 --- a/WinAlfred.Plugin.System/CMD.cs +++ b/WinAlfred.Plugin.System/CMD.cs @@ -13,6 +13,7 @@ namespace WinAlfred.Plugin.System { private Dictionary cmdHistory = new Dictionary(); private string filePath = Directory.GetCurrentDirectory() + "\\CMDHistory.dat"; + private PluginInitContext context; protected override List QueryInternal(Query query) { @@ -71,23 +72,22 @@ namespace WinAlfred.Plugin.System return results; } - private static void ExecuteCmd(string cmd) + + private void ExecuteCmd(string cmd) { try { - Process process = new Process(); - process.StartInfo.UseShellExecute = true; - process.StartInfo.FileName = cmd; - process.Start(); + WindowsShellRun.Start(cmd); } catch (Exception e) { - MessageBox.Show("WinAlfred cound't execute this command."); + MessageBox.Show("WinAlfred cound't execute this command. \n\n" + e.Message); } } protected override void InitInternal(PluginInitContext context) { + this.context = context; LoadCmdHistory(); } diff --git a/WinAlfred.Plugin.System/WinAlfred.Plugin.System.csproj b/WinAlfred.Plugin.System/WinAlfred.Plugin.System.csproj index cfccceaa14..1946308b0c 100644 --- a/WinAlfred.Plugin.System/WinAlfred.Plugin.System.csproj +++ b/WinAlfred.Plugin.System/WinAlfred.Plugin.System.csproj @@ -37,6 +37,7 @@ + @@ -46,6 +47,7 @@ + diff --git a/WinAlfred.Plugin.System/WindowsShellRun.cs b/WinAlfred.Plugin.System/WindowsShellRun.cs new file mode 100644 index 0000000000..95247d05ad --- /dev/null +++ b/WinAlfred.Plugin.System/WindowsShellRun.cs @@ -0,0 +1,282 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Runtime.InteropServices; +using System.IO; + +namespace WinAlfred.Plugin.System +{ + /* + * http://undoc.airesoft.co.uk/shell32.dll/ShellExecCmdLine.php + * + * IDA pseudocodes: + * * CRunDlg::OKPushed https://gist.github.com/anonymous/bb0581d062ae82169768 + * * ShellExecuteCmdLine https://gist.github.com/anonymous/7efeac7a89498e2667d5 + * * PromptForMedia https://gist.github.com/anonymous/4900265ca20a98da0947 + * + * leaked Windows 2000 source codes: + * * rundlg.cpp https://gist.github.com/anonymous/d97e9490e095a40651b0 + * * exec.c https://gist.github.com/anonymous/594d62eb684cf5ff3052 + */ + + public static class WindowsShellRun + { + + [DllImport("shlwapi.dll", CharSet = CharSet.Unicode)] + static extern string PathGetArgs([In] string pszPath); + + [DllImport("shlwapi.dll", CharSet = CharSet.Unicode)] + static extern void PathRemoveArgs([MarshalAs(UnmanagedType.LPTStr)]StringBuilder lpszPath); + + [DllImport("shlwapi.dll", CharSet = CharSet.Unicode)] + static extern void PathUnquoteSpaces([MarshalAs(UnmanagedType.LPTStr)]StringBuilder lpsz); + + [DllImport("shlwapi.dll", CharSet = CharSet.Unicode)] + static extern int PathGetDriveNumber([In] string lpsz); + + const int SHPPFW_IGNOREFILENAME = 4; + + [DllImport("shell32.dll", CharSet = CharSet.Unicode)] + static extern int SHPathPrepareForWrite(IntPtr hwnd, + [MarshalAs(UnmanagedType.IUnknown)] object punkEnableModless, + string pszPath, uint dwFlags); + + static bool PromptForMedia(String cmd, out int driveId) + { + StringBuilder sb = new StringBuilder(cmd, cmd.Length); + PathRemoveArgs(sb); + PathUnquoteSpaces(sb); + + if ((driveId = PathGetDriveNumber(sb.ToString())) != -1 && + SHPathPrepareForWrite(IntPtr.Zero, 0, sb.ToString(), SHPPFW_IGNOREFILENAME) < 0) + // if replace IntPtr.Zero with a form handle, + // it will show a dialog waiting for media insert + // check it here: https://f.cloud.github.com/assets/158528/2008562/6bb65164-874d-11e3-8f66-c8a4773bd5f2.png + { + return false; + } + return true; + } + + [Flags] + enum ShellExecCmdLineFlags + { + SECL_USEFULLPATHDIR = 0x1, + SECL_NO_UI = 0x2, + SECL_4 = 0x4, + SECL_LOG_USAGE = 0x8, + SECL_USE_IDLIST = 0x10, + SECL__IGNORE_ERROR = 0x20, + SECL_RUNAS = 0x40 + } + + const int URLIS_URL = 0; + const int URLIS_FILEURL = 3; + + [DllImport("shlwapi.dll", CharSet = CharSet.Unicode)] + static extern bool UrlIs(string pszUrl, int UrlIs); + + static void ShellExecCmdLine(IntPtr hInstance, IntPtr hwnd, string command, string startDir, global::System.Diagnostics.ProcessWindowStyle nShow, ShellExecCmdLineFlags dwSeclFlags) + { + string cmd = command; + string args = null; + if (UrlIs(command, URLIS_URL)) + cmd = command; + else + { + if (global::System.Environment.OSVersion.Version.Major >= 6) + EvaluateSystemAndUserCommandLine(cmd, startDir, out cmd, out args, dwSeclFlags); + else + EvaluateUserCommandLine(cmd, startDir, out cmd, out args); + } + + if (!UrlIs(cmd, URLIS_URL) + && ( + (dwSeclFlags & ShellExecCmdLineFlags.SECL_USEFULLPATHDIR) == ShellExecCmdLineFlags.SECL_USEFULLPATHDIR + || startDir == null + || startDir.Length == 0)) + { + string dir = QualifyWorkingDir(cmd); + if (dir != null) + startDir = dir; + } + + global::System.Diagnostics.ProcessStartInfo startInfo = new global::System.Diagnostics.ProcessStartInfo(); + startInfo.UseShellExecute = true; + startInfo.Arguments = args; + startInfo.FileName = cmd; + startInfo.WindowStyle = global::System.Diagnostics.ProcessWindowStyle.Normal; + startInfo.ErrorDialog = (dwSeclFlags | ShellExecCmdLineFlags.SECL_NO_UI) == 0; + startInfo.ErrorDialogParentHandle = hwnd; + + try + { + global::System.Diagnostics.Process.Start(startInfo); + } + catch (Exception e) + { + if (!startInfo.ErrorDialog) + throw e; + } + } + + [DllImport("shell32.dll", CharSet = CharSet.Unicode)] + static extern int SHEvaluateSystemCommandTemplate( + string pszCmdTemplate, + out IntPtr ppszApplication, + out IntPtr ppszCommandLine, + out IntPtr ppszParameters + ); + + [DllImport("shell32.dll", CharSet = CharSet.Unicode)] + static extern void PathQualify( + [MarshalAs(UnmanagedType.LPWStr)] StringBuilder psz + ); + + static string QualifyWorkingDir(string pszPath) + { + // special case to make sure the working dir gets set right: + // 1) no working dir specified + // 2) a drive or a root path, or a relative path specified + // derive the working dir from the qualified path. this is to make + // sure the working dir for setup programs "A:setup" is set right + + if (pszPath.IndexOfAny(new char[] { '\\', ':'}) >= 0) + { + // build working dir based on qualified path + if (Directory.Exists(pszPath)) + return pszPath; + + pszPath = Path.GetDirectoryName(pszPath); + if (pszPath != null) + try + { + return Path.GetFullPath(pszPath); + } + catch + { + return pszPath; + } + } + + return null; + } + + static bool CopyCommand(string pszCommand, string pszDir, out string pszOut) + { + bool fRet = true; + + pszOut = pszCommand; + if (pszCommand[0] != '"') + { + if (UrlIs(pszCommand, URLIS_URL)) + { + // urls never have params... + if (UrlIs(pszCommand, URLIS_FILEURL)) + pszOut = new Uri(pszCommand).LocalPath; // PathCreateFromUrl(pszCommand, pszOut, &cchOut, 0); + else + pszOut = pszCommand; + + return false; + } + else + { + try + { + pszOut = Path.GetFullPath(pszCommand); // PathQualifyDef(pszOut, pszDir, 0); + } + catch + { + pszOut = pszCommand; + } + + // TODO: deal with attributes + if (File.Exists(pszOut) || Directory.Exists(pszOut)) // PathFileExistsAndAttributes(pszOut, NULL) + return false; + } + } + + return true; + } + + static void EvaluateUserCommandLine(string command, string startDir, out string cmd, out string args) + { + if (CopyCommand(command, startDir, out cmd)) + { + // there might be args in that command + args = PathGetArgs(cmd); + if (args != null) + cmd = cmd.Substring(0, cmd.Length - args.Length); + } + else + args = null; + + StringBuilder buffer = new StringBuilder(cmd); + PathUnquoteSpaces(buffer); + cmd = buffer.ToString(); + } + + static void EvaluateSystemAndUserCommandLine(string command, string startDir, out string cmd, out string args, ShellExecCmdLineFlags dwSeclFlags) + { + IntPtr pcmd, pcmdl, parg; + int result = SHEvaluateSystemCommandTemplate(command, out pcmd, out pcmdl, out parg); + if (result < 0) + { + if ((dwSeclFlags & ShellExecCmdLineFlags.SECL__IGNORE_ERROR) == 0) + throwHRESULT(result); + + EvaluateUserCommandLine(command, startDir, out cmd, out args); + } + else + { + cmd = Marshal.PtrToStringUni(pcmd); + args = Marshal.PtrToStringUni(parg); + Marshal.FreeCoTaskMem(pcmd); + Marshal.FreeCoTaskMem(pcmdl); + Marshal.FreeCoTaskMem(parg); + } + } + + static int throwHRESULT(int hresult) + { + throw new global::System.IO.IOException( + new global::System.ComponentModel.Win32Exception(hresult ^ -0x7FF90000).Message, + hresult); + } + + public static void Start(string cmd) + { + Start(cmd, false); + } + + public static void Start(string cmd, bool showErrorDialog) + { + Start(cmd, false, IntPtr.Zero); + } + + public static void Start(string cmd, bool showErrorDialog, IntPtr errorDialogHwnd) + { + cmd = cmd.Trim(); // PathRemoveBlanks + cmd = Environment.ExpandEnvironmentVariables(cmd); // SHExpandEnvironmentStrings + int driveId = -1; + if (PromptForMedia(cmd, out driveId)) + { + ShellExecCmdLine( + IntPtr.Zero, + errorDialogHwnd, + cmd, + null, // i have no ideas about this field + global::System.Diagnostics.ProcessWindowStyle.Normal, + ShellExecCmdLineFlags.SECL__IGNORE_ERROR | ShellExecCmdLineFlags.SECL_USE_IDLIST | ShellExecCmdLineFlags.SECL_LOG_USAGE | (showErrorDialog ? 0 : ShellExecCmdLineFlags.SECL_NO_UI) + ); + } + else + { // Device not ready 0x80070015 + throw new global::System.IO.IOException( + new global::System.ComponentModel.Win32Exception(0x15).Message, + -0x7FF90000 | 0x15); + } + } + } +} diff --git a/WinAlfred/Helper/KeyboardListener.cs b/WinAlfred/Helper/KeyboardListener.cs index 01a9e1c02c..264e6a8be3 100644 --- a/WinAlfred/Helper/KeyboardListener.cs +++ b/WinAlfred/Helper/KeyboardListener.cs @@ -101,7 +101,8 @@ namespace WinAlfred.Helper wParam.ToUInt32() == (int)KeyEvent.WM_SYSKEYDOWN || wParam.ToUInt32() == (int)KeyEvent.WM_SYSKEYUP) { - continues = hookedKeyboardCallback((KeyEvent)wParam.ToUInt32(), Marshal.ReadInt32(lParam), CheckModifiers()); + if (hookedKeyboardCallback != null) + continues = hookedKeyboardCallback((KeyEvent)wParam.ToUInt32(), Marshal.ReadInt32(lParam), CheckModifiers()); } } diff --git a/WinAlfred/Msg.xaml.cs b/WinAlfred/Msg.xaml.cs index 5959f72862..981a3b1074 100644 --- a/WinAlfred/Msg.xaml.cs +++ b/WinAlfred/Msg.xaml.cs @@ -65,7 +65,7 @@ namespace WinAlfred tbSubTitle.Text = subTitle; if (!File.Exists(icopath)) { - icopath = AppDomain.CurrentDomain.BaseDirectory + "Images\\ico.png"; + icopath = AppDomain.CurrentDomain.BaseDirectory + "Images\\app.png"; } imgIco.Source = new BitmapImage(new Uri(icopath)); Show();