From 48e40467541a02db025f06530a2ed35013caf75a Mon Sep 17 00:00:00 2001 From: Austin Wagner Date: Sat, 30 Nov 2013 09:15:42 -0500 Subject: [PATCH 1/2] Add launcher Fixes bliker/cmder#39 Launcher replaces functionality of batch file to allow taskbar pinning --- launcher/.gitignore | 181 +++++++++++++++++++++++++++++++++ launcher/CmderLauncher.sln | 22 ++++ launcher/CmderLauncher.vcxproj | 98 ++++++++++++++++++ launcher/src/CmderLauncher.cpp | 60 +++++++++++ launcher/src/Resource.rc | Bin 0 -> 3292 bytes launcher/src/resource.h | Bin 0 -> 904 bytes 6 files changed, 361 insertions(+) create mode 100644 launcher/.gitignore create mode 100644 launcher/CmderLauncher.sln create mode 100644 launcher/CmderLauncher.vcxproj create mode 100644 launcher/src/CmderLauncher.cpp create mode 100644 launcher/src/Resource.rc create mode 100644 launcher/src/resource.h diff --git a/launcher/.gitignore b/launcher/.gitignore new file mode 100644 index 0000000..0036705 --- /dev/null +++ b/launcher/.gitignore @@ -0,0 +1,181 @@ +## Ignore Visual Studio temporary files, build results, and +## files generated by popular Visual Studio add-ons. + +# User-specific files +*.suo +*.user +*.sln.docstates +*.filters + +# Build results +[Dd]ebug/ +[Dd]ebugPublic/ +[Rr]elease/ +x64/ +build/ +bld/ +[Bb]in/ +[Oo]bj/ + +# Enable "build/" folder in the NuGet Packages folder since NuGet packages use it for MSBuild targets +!packages/*/build/ + +# MSTest test Results +[Tt]est[Rr]esult*/ +[Bb]uild[Ll]og.* + +#NUNIT +*.VisualState.xml +TestResult.xml + +*_i.c +*_p.c +*_i.h +*.ilk +*.meta +*.obj +*.pch +*.pdb +*.pgc +*.pgd +*.rsp +*.sbr +*.tlb +*.tli +*.tlh +*.tmp +*.tmp_proj +*.log +*.vspscc +*.vssscc +.builds +*.pidb +*.svclog +*.scc + +# Chutzpah Test files +_Chutzpah* + +# Visual C++ cache files +ipch/ +*.aps +*.ncb +*.opensdf +*.sdf +*.cachefile + +# Visual Studio profiler +*.psess +*.vsp +*.vspx + +# TFS 2012 Local Workspace +$tf/ + +# Guidance Automation Toolkit +*.gpState + +# ReSharper is a .NET coding add-in +_ReSharper*/ +*.[Rr]e[Ss]harper +*.DotSettings.user + +# JustCode is a .NET coding addin-in +.JustCode + +# TeamCity is a build add-in +_TeamCity* + +# DotCover is a Code Coverage Tool +*.dotCover + +# NCrunch +*.ncrunch* +_NCrunch_* +.*crunch*.local.xml + +# MightyMoose +*.mm.* +AutoTest.Net/ + +# Installshield output folder +[Ee]xpress/ + +# DocProject is a documentation generator add-in +DocProject/buildhelp/ +DocProject/Help/*.HxT +DocProject/Help/*.HxC +DocProject/Help/*.hhc +DocProject/Help/*.hhk +DocProject/Help/*.hhp +DocProject/Help/Html2 +DocProject/Help/html + +# Click-Once directory +publish/ + +# Publish Web Output +*.Publish.xml +*.azurePubxml + +# NuGet Packages Directory +## TODO: If you have NuGet Package Restore enabled, uncomment the next line +#packages/ +## TODO: If the tool you use requires repositories.config, also uncomment the next line +#!packages/repositories.config + +# Windows Azure Build Output +csx/ +*.build.csdef + +# Windows Store app package directory +AppPackages/ + +# Others +sql/ +*.Cache +ClientBin/ +[Ss]tyle[Cc]op.* +~$* +*~ +*.dbmdl +*.dbproj.schemaview +*.[Pp]ublish.xml +*.pfx +*.publishsettings + +# RIA/Silverlight projects +Generated_Code/ + +# Backup & report files from converting an old project file to a newer +# Visual Studio version. Backup files are not needed, because we have git ;-) +_UpgradeReport_Files/ +Backup*/ +UpgradeLog*.XML +UpgradeLog*.htm + +# SQL Server files +App_Data/*.mdf +App_Data/*.ldf + +# Business Intelligence projects +*.rdl.data +*.bim.layout +*.bim_*.settings + +# Microsoft Fakes +FakesAssemblies/ + +# ========================= +# Windows detritus +# ========================= + +# Windows image file caches +Thumbs.db +ehthumbs.db + +# Folder config file +Desktop.ini + +# Recycle Bin used on file shares +$RECYCLE.BIN/ diff --git a/launcher/CmderLauncher.sln b/launcher/CmderLauncher.sln new file mode 100644 index 0000000..e4934d3 --- /dev/null +++ b/launcher/CmderLauncher.sln @@ -0,0 +1,22 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 2013 +VisualStudioVersion = 12.0.21005.1 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "CmderLauncher", "CmderLauncher.vcxproj", "{4A8485A5-B7DD-4C44-B7F6-3E2765DD0CD3}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Win32 = Debug|Win32 + Release|Win32 = Release|Win32 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {4A8485A5-B7DD-4C44-B7F6-3E2765DD0CD3}.Debug|Win32.ActiveCfg = Debug|Win32 + {4A8485A5-B7DD-4C44-B7F6-3E2765DD0CD3}.Debug|Win32.Build.0 = Debug|Win32 + {4A8485A5-B7DD-4C44-B7F6-3E2765DD0CD3}.Release|Win32.ActiveCfg = Release|Win32 + {4A8485A5-B7DD-4C44-B7F6-3E2765DD0CD3}.Release|Win32.Build.0 = Release|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/launcher/CmderLauncher.vcxproj b/launcher/CmderLauncher.vcxproj new file mode 100644 index 0000000..557e1ac --- /dev/null +++ b/launcher/CmderLauncher.vcxproj @@ -0,0 +1,98 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + + {4A8485A5-B7DD-4C44-B7F6-3E2765DD0CD3} + Win32Proj + CmderLauncher + + + + Application + true + v120 + Unicode + + + Application + false + v120 + true + Unicode + + + + + + + + + + + + + true + Cmder + + + false + Cmder + + + + + + Level3 + Disabled + WIN32;_DEBUG;_WINDOWS;%(PreprocessorDefinitions) + true + + + Windows + true + + + + + Level3 + + + MinSpace + true + false + WIN32;NDEBUG;_WINDOWS;%(PreprocessorDefinitions) + true + Size + + + Windows + true + true + true + + + cp $(TargetPath) $(SolutionDir)..\$(TargetFileName) + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/launcher/src/CmderLauncher.cpp b/launcher/src/CmderLauncher.cpp new file mode 100644 index 0000000..9c77579 --- /dev/null +++ b/launcher/src/CmderLauncher.cpp @@ -0,0 +1,60 @@ +#include +#include +#include +#include "resource.h" + +#pragma comment(lib, "Shlwapi.lib") + +#define USE_TASKBAR_API (UNICODE && _WIN32_WINNT >= _WIN32_WINNT_WIN7) + +int APIENTRY _tWinMain(_In_ HINSTANCE hInstance, + _In_opt_ HINSTANCE hPrevInstance, + _In_ LPTSTR lpCmdLine, + _In_ int nCmdShow) +{ + UNREFERENCED_PARAMETER(hPrevInstance); + UNREFERENCED_PARAMETER(lpCmdLine); + UNREFERENCED_PARAMETER(nCmdShow); + +#if USE_TASKBAR_API + TCHAR appId[MAX_PATH] = { 0 }; +#endif + TCHAR exeDir[MAX_PATH] = { 0 }; + TCHAR icoPath[MAX_PATH] = { 0 }; + TCHAR cfgPath[MAX_PATH] = { 0 }; + TCHAR conEmuPath[MAX_PATH] = { 0 }; + TCHAR args[MAX_PATH * 2 + 256] = { 0 }; + + GetModuleFileName(NULL, exeDir, sizeof(exeDir)); + +#if USE_TASKBAR_API + _tcscpy_s(appId, exeDir); +#endif + + PathRemoveFileSpec(exeDir); + + PathCombine(icoPath, exeDir, _T("icons\\cmder.ico")); + PathCombine(cfgPath, exeDir, _T("config\\ConEmu.xml")); + PathCombine(conEmuPath, exeDir, _T("vendor\\conemu-maximus5\\ConEmu.exe")); + + _tcscat_s(args, _T("/Icon \"")); + _tcscat_s(args, icoPath); + _tcscat_s(args, _T("\" /Title Cmder /LoadCfgFile \"")); + _tcscat_s(args, cfgPath); + _tcscat_s(args, _T("\"")); + + SetEnvironmentVariable(_T("CMDER_ROOT"), exeDir); + + STARTUPINFO si = { 0 }; + si.cb = sizeof(STARTUPINFO); +#if USE_TASKBAR_API + si.lpTitle = appId; + si.dwFlags = STARTF_TITLEISAPPID; +#endif + + PROCESS_INFORMATION pi; + + CreateProcess(conEmuPath, args, NULL, NULL, false, 0, NULL, NULL, &si, &pi); + + return 0; +} \ No newline at end of file diff --git a/launcher/src/Resource.rc b/launcher/src/Resource.rc new file mode 100644 index 0000000000000000000000000000000000000000..42eec5860378de070e02e9b5f221d85728762c8d GIT binary patch literal 3292 zcmds(YmZVf5QgWoiT|O(7dIO4@(UJN@kAC4myISQWCNlk+`<8kiND?Td0V=B77iHE z4``Zmrk&2T)9K9Hx%pAHvN^l7u?=i#b4&R~wt{yBFSWH@+k{cop3t0qvX3_7Tf$#K zhwzqA>8jLvd>oV($Xw?xslh?+UNGp z+SakI)hw~M*0+{jz^&15TEjlTY4g9d3Y-T0xW8;Ty%w#D)L9+BZ2NeGm*zI*{42a8 zKXf?td;SThu5wQK;{yH*zU>?N^&Ncm{tbHf{eOBMix!3GSmP^2(ui{(7aP&@aoy9R z(K^TN&d9$BHMzQ5ABkP5yMr zt|~kCiLM4s>wc%Xy_y}?Xc5DGw3_Ij`CS`un{d0(x{uSy337GTPRP~Q_LQ~T$W`D3 zoo$IevmvWP1n4aLBS86a#Yx_w#N6B06CIot676dU>Qpzq?P-2ceBplqTVA1D$NAZ(kZRiDZNG@nXx`9WuvA4$gan`Qz(oK<3Rgt0@>`ocW61}6c zM><+{LQ{3}Z8JNChPP1`Cty~UxgqRJP%xyCOt!N# znLTr6PQN~zYU&+})mN%Op{_Zxzs2gPOEl02cB~_6n{tXYRi>pDDmb}TM#VWsvhf&nuN%Dl^|ul*8GN%`G!X` zEbHgs9dJ^ZM1Gcp+#%M|nOeTXri)`M6TSLrjd{*YCCqL5XFqpIwjj!3y2Klk7yLqF zJ#o*dEq+)#e`~-vUvqbAv;Bc?H1zCEkuF_FXmf=Q!Pbj;&6|YUHr0LJ_H+lzfN!Kr zGCl75_LZ)Cr@RSu3x|}goA!O!B!rF8TYH^(|KsKw? q_^b0i-i97CLE`7FW9>ja47=K-X;F`B+xh*68mMoInby_zcjIq^UwxGT literal 0 HcmV?d00001 From 8f6a473a40eac215e2ecd1d4fed4d9326c73eb30 Mon Sep 17 00:00:00 2001 From: Austin Wagner Date: Sat, 7 Dec 2013 09:17:35 -0500 Subject: [PATCH 2/2] Add Cmder Here Add option to launcher to register and unregister Cmder Here --- launcher/src/CmderLauncher.cpp | 227 +++++++++++++++++++++++++++++---- vendor/init.bat | 3 + 2 files changed, 202 insertions(+), 28 deletions(-) diff --git a/launcher/src/CmderLauncher.cpp b/launcher/src/CmderLauncher.cpp index 9c77579..677ee13 100644 --- a/launcher/src/CmderLauncher.cpp +++ b/launcher/src/CmderLauncher.cpp @@ -2,48 +2,107 @@ #include #include #include "resource.h" +#include #pragma comment(lib, "Shlwapi.lib") -#define USE_TASKBAR_API (UNICODE && _WIN32_WINNT >= _WIN32_WINNT_WIN7) - -int APIENTRY _tWinMain(_In_ HINSTANCE hInstance, - _In_opt_ HINSTANCE hPrevInstance, - _In_ LPTSTR lpCmdLine, - _In_ int nCmdShow) -{ - UNREFERENCED_PARAMETER(hPrevInstance); - UNREFERENCED_PARAMETER(lpCmdLine); - UNREFERENCED_PARAMETER(nCmdShow); - -#if USE_TASKBAR_API - TCHAR appId[MAX_PATH] = { 0 }; +#ifndef UNICODE +#error "Must be compiled with unicode support." #endif - TCHAR exeDir[MAX_PATH] = { 0 }; - TCHAR icoPath[MAX_PATH] = { 0 }; - TCHAR cfgPath[MAX_PATH] = { 0 }; - TCHAR conEmuPath[MAX_PATH] = { 0 }; - TCHAR args[MAX_PATH * 2 + 256] = { 0 }; + +#define USE_TASKBAR_API (_WIN32_WINNT >= _WIN32_WINNT_WIN7) + +#define MB_TITLE L"Cmder Launcher" +#define SHELL_MENU_REGISTRY_PATH L"Directory\\Background\\shell\\Cmder" + +#define streqi(a, b) (_wcsicmp((a), (b)) == 0) + +#define WIDEN2(x) L ## x +#define WIDEN(x) WIDEN2(x) +#define __WFUNCTION__ WIDEN(__FUNCTION__) + +#define FAIL_ON_ERROR(x) { DWORD ec; if ((ec = (x)) != ERROR_SUCCESS) { ShowErrorAndExit(ec, __WFUNCTION__, __LINE__); } } + +void ShowErrorAndExit(DWORD ec, const wchar_t * func, int line) +{ + wchar_t * buffer; + if (FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, + NULL, ec, 0, (LPWSTR) &buffer, 0, NULL) == 0) + { + buffer = L"Unknown error. FormatMessage failed."; + } + + wchar_t message[1024]; + swprintf_s(message, L"%s\nFunction: %s\nLine: %d", buffer, func, line); + LocalFree(buffer); + + MessageBox(NULL, message, MB_TITLE, MB_OK | MB_ICONERROR); + exit(1); +} + +typedef struct _option +{ + std::wstring name; + bool hasVal; + std::wstring value; + bool set; +} option; + +typedef std::pair optpair; + + +optpair GetOption() +{ + wchar_t * cmd = GetCommandLine(); + int argc; + wchar_t ** argv = CommandLineToArgvW(cmd, &argc); + optpair pair; + + if (argc == 1) + { + pair = optpair(L"/START", L""); + } + else if (argc == 2 && argv[1][0] != L'/') + { + pair = optpair(L"/START", argv[1]); + } + else + { + pair = optpair(argv[1], argc > 2 ? argv[2] : L""); + } + + LocalFree(argv); + + return pair; +} + +void StartCmder(std::wstring path) +{ +#if USE_TASKBAR_API + wchar_t appId[MAX_PATH] = { 0 }; +#endif + wchar_t exeDir[MAX_PATH] = { 0 }; + wchar_t icoPath[MAX_PATH] = { 0 }; + wchar_t cfgPath[MAX_PATH] = { 0 }; + wchar_t conEmuPath[MAX_PATH] = { 0 }; + wchar_t args[MAX_PATH * 2 + 256] = { 0 }; GetModuleFileName(NULL, exeDir, sizeof(exeDir)); #if USE_TASKBAR_API - _tcscpy_s(appId, exeDir); + wcscpy_s(appId, exeDir); #endif PathRemoveFileSpec(exeDir); - PathCombine(icoPath, exeDir, _T("icons\\cmder.ico")); - PathCombine(cfgPath, exeDir, _T("config\\ConEmu.xml")); - PathCombine(conEmuPath, exeDir, _T("vendor\\conemu-maximus5\\ConEmu.exe")); + PathCombine(icoPath, exeDir, L"icons\\cmder.ico"); + PathCombine(cfgPath, exeDir, L"config\\ConEmu.xml"); + PathCombine(conEmuPath, exeDir, L"vendor\\conemu-maximus5\\ConEmu.exe"); - _tcscat_s(args, _T("/Icon \"")); - _tcscat_s(args, icoPath); - _tcscat_s(args, _T("\" /Title Cmder /LoadCfgFile \"")); - _tcscat_s(args, cfgPath); - _tcscat_s(args, _T("\"")); + swprintf_s(args, L"/Icon \"%s\" /Title Cmder /LoadCfgFile \"%s\"", icoPath, cfgPath); - SetEnvironmentVariable(_T("CMDER_ROOT"), exeDir); + SetEnvironmentVariable(L"CMDER_ROOT", exeDir); + SetEnvironmentVariable(L"CMDER_START", path.c_str()); STARTUPINFO si = { 0 }; si.cb = sizeof(STARTUPINFO); @@ -55,6 +114,118 @@ int APIENTRY _tWinMain(_In_ HINSTANCE hInstance, PROCESS_INFORMATION pi; CreateProcess(conEmuPath, args, NULL, NULL, false, 0, NULL, NULL, &si, &pi); +} + +bool IsUserOnly(std::wstring opt) +{ + bool userOnly; + + if (streqi(opt.c_str(), L"ALL")) + { + userOnly = false; + } + else if (streqi(opt.c_str(), L"USER")) + { + userOnly = true; + } + else + { + MessageBox(NULL, L"Unrecognized option for /REGISTER or /UNREGISTER. Must be either ALL or USER.", MB_TITLE, MB_OK); + exit(1); + } + + return userOnly; +} + +HKEY GetRootKey(std::wstring opt) +{ + HKEY root; + + if (IsUserOnly(opt)) + { + FAIL_ON_ERROR(RegCreateKeyEx(HKEY_CURRENT_USER, L"Software\\Classes", 0, NULL, + REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &root, NULL)); + } + else + { + root = HKEY_CLASSES_ROOT; + } + + return root; +} + +void RegisterShellMenu(std::wstring opt) +{ + HKEY root = GetRootKey(opt); + + HKEY cmderKey; + FAIL_ON_ERROR( + RegCreateKeyEx(root, SHELL_MENU_REGISTRY_PATH, 0, NULL, + REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &cmderKey, NULL)); + + FAIL_ON_ERROR(RegSetValue(cmderKey, L"", REG_SZ, L"Cmder Here", NULL)); + FAIL_ON_ERROR(RegSetValueEx(cmderKey, L"NoWorkingDirectory", 0, REG_SZ, (BYTE *)L"", 2)); + + HKEY command; + FAIL_ON_ERROR( + RegCreateKeyEx(cmderKey, L"command", 0, NULL, + REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &command, NULL)); + + wchar_t exePath[MAX_PATH] = { 0 }; + + GetModuleFileName(NULL, exePath, sizeof(exePath)); + + wchar_t commandStr[MAX_PATH + 20] = { 0 }; + swprintf_s(commandStr, L"\"%s\" \"%%V\"", exePath); + + FAIL_ON_ERROR(RegSetValue(command, L"", REG_SZ, commandStr, NULL)); + + RegCloseKey(command); + RegCloseKey(cmderKey); + RegCloseKey(root); +} + +void UnregisterShellMenu(std::wstring opt) +{ + HKEY root = GetRootKey(opt); + HKEY cmderKey; + FAIL_ON_ERROR( + RegCreateKeyEx(root, SHELL_MENU_REGISTRY_PATH, 0, NULL, + REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &cmderKey, NULL)); + FAIL_ON_ERROR(RegDeleteTree(cmderKey, NULL)); + FAIL_ON_ERROR(RegDeleteKey(root, SHELL_MENU_REGISTRY_PATH)); + RegCloseKey(cmderKey); + RegCloseKey(root); +} + +int APIENTRY _tWinMain(_In_ HINSTANCE hInstance, + _In_opt_ HINSTANCE hPrevInstance, + _In_ LPTSTR lpCmdLine, + _In_ int nCmdShow) +{ + UNREFERENCED_PARAMETER(hPrevInstance); + UNREFERENCED_PARAMETER(lpCmdLine); + UNREFERENCED_PARAMETER(nCmdShow); + + optpair opt = GetOption(); + + if (streqi(opt.first.c_str(), L"/START")) + { + StartCmder(opt.second); + } + else if (streqi(opt.first.c_str(), L"/REGISTER")) + { + RegisterShellMenu(opt.second); + } + else if (streqi(opt.first.c_str(), L"/UNREGISTER")) + { + UnregisterShellMenu(opt.second); + } + else + { + MessageBox(NULL, L"Unrecognized parameter.\n\nValid options:\n /START \n /REGISTER [USER/ALL]\n /UNREGISTER [USER/ALL]", MB_TITLE, MB_OK); + return 1; + } return 0; } \ No newline at end of file diff --git a/vendor/init.bat b/vendor/init.bat index 71d2e6e..d044e4b 100644 --- a/vendor/init.bat +++ b/vendor/init.bat @@ -40,4 +40,7 @@ :: Set home path @set HOME=%USERPROFILE% + +@if defined CMDER_START cd /d "%CMDER_START%" + @echo Welcome to cmder!