2013-11-30 22:15:42 +08:00
|
|
|
#include <windows.h>
|
|
|
|
#include <tchar.h>
|
|
|
|
#include <Shlwapi.h>
|
|
|
|
#include "resource.h"
|
2013-12-07 22:17:35 +08:00
|
|
|
#include <vector>
|
2013-11-30 22:15:42 +08:00
|
|
|
|
|
|
|
#pragma comment(lib, "Shlwapi.lib")
|
|
|
|
|
2013-12-07 22:17:35 +08:00
|
|
|
#ifndef UNICODE
|
|
|
|
#error "Must be compiled with unicode support."
|
|
|
|
#endif
|
2013-11-30 22:15:42 +08:00
|
|
|
|
2013-12-07 22:17:35 +08:00
|
|
|
#define USE_TASKBAR_API (_WIN32_WINNT >= _WIN32_WINNT_WIN7)
|
|
|
|
|
|
|
|
#define MB_TITLE L"Cmder Launcher"
|
2014-02-28 07:34:37 +08:00
|
|
|
#define SHELL_MENU_REGISTRY_PATH_BACKGROUND L"Directory\\Background\\shell\\Cmder"
|
|
|
|
#define SHELL_MENU_REGISTRY_PATH_LISTITEM L"Directory\\shell\\Cmder"
|
2013-12-07 22:17:35 +08:00
|
|
|
|
|
|
|
#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)
|
2013-11-30 22:15:42 +08:00
|
|
|
{
|
2013-12-07 22:17:35 +08:00
|
|
|
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);
|
2013-11-30 22:15:42 +08:00
|
|
|
|
2013-12-07 22:17:35 +08:00
|
|
|
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<std::wstring, std::wstring> 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)
|
|
|
|
{
|
2013-11-30 22:15:42 +08:00
|
|
|
#if USE_TASKBAR_API
|
2013-12-07 22:17:35 +08:00
|
|
|
wchar_t appId[MAX_PATH] = { 0 };
|
2013-11-30 22:15:42 +08:00
|
|
|
#endif
|
2013-12-07 22:17:35 +08:00
|
|
|
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 };
|
2013-11-30 22:15:42 +08:00
|
|
|
|
|
|
|
GetModuleFileName(NULL, exeDir, sizeof(exeDir));
|
|
|
|
|
|
|
|
#if USE_TASKBAR_API
|
2013-12-07 22:17:35 +08:00
|
|
|
wcscpy_s(appId, exeDir);
|
2013-11-30 22:15:42 +08:00
|
|
|
#endif
|
|
|
|
|
|
|
|
PathRemoveFileSpec(exeDir);
|
|
|
|
|
2013-12-07 22:17:35 +08:00
|
|
|
PathCombine(icoPath, exeDir, L"icons\\cmder.ico");
|
|
|
|
PathCombine(cfgPath, exeDir, L"config\\ConEmu.xml");
|
|
|
|
PathCombine(conEmuPath, exeDir, L"vendor\\conemu-maximus5\\ConEmu.exe");
|
2013-11-30 22:15:42 +08:00
|
|
|
|
2013-12-07 22:17:35 +08:00
|
|
|
swprintf_s(args, L"/Icon \"%s\" /Title Cmder /LoadCfgFile \"%s\"", icoPath, cfgPath);
|
2013-11-30 22:15:42 +08:00
|
|
|
|
2013-12-07 22:17:35 +08:00
|
|
|
SetEnvironmentVariable(L"CMDER_ROOT", exeDir);
|
|
|
|
SetEnvironmentVariable(L"CMDER_START", path.c_str());
|
2013-11-30 22:15:42 +08:00
|
|
|
|
|
|
|
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);
|
2013-12-07 22:17:35 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2014-02-28 07:34:37 +08:00
|
|
|
void RegisterShellMenu(std::wstring opt, wchar_t* keyBaseName)
|
2013-12-07 22:17:35 +08:00
|
|
|
{
|
2014-02-28 07:34:37 +08:00
|
|
|
// First, get the paths we will use
|
|
|
|
|
|
|
|
wchar_t exePath[MAX_PATH] = { 0 };
|
|
|
|
wchar_t icoPath[MAX_PATH] = { 0 };
|
|
|
|
|
|
|
|
GetModuleFileName(NULL, exePath, sizeof(exePath));
|
|
|
|
|
|
|
|
wchar_t commandStr[MAX_PATH + 20] = { 0 };
|
|
|
|
swprintf_s(commandStr, L"\"%s\" \"%%V\"", exePath);
|
|
|
|
|
|
|
|
// Now that we have `commandStr`, it's OK to change `exePath`...
|
|
|
|
PathRemoveFileSpec(exePath);
|
|
|
|
|
|
|
|
PathCombine(icoPath, exePath, L"icons\\cmder.ico");
|
|
|
|
|
|
|
|
// Now set the registry keys
|
|
|
|
|
2013-12-07 22:17:35 +08:00
|
|
|
HKEY root = GetRootKey(opt);
|
|
|
|
|
|
|
|
HKEY cmderKey;
|
|
|
|
FAIL_ON_ERROR(
|
2014-02-28 07:34:37 +08:00
|
|
|
RegCreateKeyEx(root, keyBaseName, 0, NULL,
|
2013-12-07 22:17:35 +08:00
|
|
|
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));
|
|
|
|
|
2014-02-28 07:34:37 +08:00
|
|
|
FAIL_ON_ERROR(RegSetValueEx(cmderKey, L"Icon", 0, REG_SZ, (BYTE *)icoPath, sizeof icoPath));
|
|
|
|
|
2013-12-07 22:17:35 +08:00
|
|
|
HKEY command;
|
|
|
|
FAIL_ON_ERROR(
|
|
|
|
RegCreateKeyEx(cmderKey, L"command", 0, NULL,
|
|
|
|
REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &command, NULL));
|
|
|
|
|
|
|
|
FAIL_ON_ERROR(RegSetValue(command, L"", REG_SZ, commandStr, NULL));
|
|
|
|
|
|
|
|
RegCloseKey(command);
|
|
|
|
RegCloseKey(cmderKey);
|
|
|
|
RegCloseKey(root);
|
|
|
|
}
|
|
|
|
|
2014-02-28 07:34:37 +08:00
|
|
|
void UnregisterShellMenu(std::wstring opt, wchar_t* keyBaseName)
|
2013-12-07 22:17:35 +08:00
|
|
|
{
|
|
|
|
HKEY root = GetRootKey(opt);
|
|
|
|
HKEY cmderKey;
|
|
|
|
FAIL_ON_ERROR(
|
2014-02-28 07:34:37 +08:00
|
|
|
RegCreateKeyEx(root, keyBaseName, 0, NULL,
|
2013-12-07 22:17:35 +08:00
|
|
|
REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &cmderKey, NULL));
|
|
|
|
FAIL_ON_ERROR(RegDeleteTree(cmderKey, NULL));
|
2014-02-28 07:34:37 +08:00
|
|
|
FAIL_ON_ERROR(RegDeleteKey(root, keyBaseName));
|
2013-12-07 22:17:35 +08:00
|
|
|
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"))
|
|
|
|
{
|
2014-02-28 07:34:37 +08:00
|
|
|
RegisterShellMenu(opt.second, SHELL_MENU_REGISTRY_PATH_BACKGROUND);
|
|
|
|
RegisterShellMenu(opt.second, SHELL_MENU_REGISTRY_PATH_LISTITEM);
|
2013-12-07 22:17:35 +08:00
|
|
|
}
|
|
|
|
else if (streqi(opt.first.c_str(), L"/UNREGISTER"))
|
|
|
|
{
|
2014-02-28 07:34:37 +08:00
|
|
|
UnregisterShellMenu(opt.second, SHELL_MENU_REGISTRY_PATH_BACKGROUND);
|
|
|
|
UnregisterShellMenu(opt.second, SHELL_MENU_REGISTRY_PATH_LISTITEM);
|
2013-12-07 22:17:35 +08:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
MessageBox(NULL, L"Unrecognized parameter.\n\nValid options:\n /START <path>\n /REGISTER [USER/ALL]\n /UNREGISTER [USER/ALL]", MB_TITLE, MB_OK);
|
|
|
|
return 1;
|
|
|
|
}
|
2013-11-30 22:15:42 +08:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|