Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion Installer/Installer.iss
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@ Source: "Prerequisites\VC_redist.x64.exe"; DestDir: "{tmp}"; Flags: dontcopy
Name: "{commonstartmenu}\Programs\{#MyAppName}\{cm:ConfigureShortcutName}"; Filename: "{app}\Configure.exe"; Comment: "{cm:ConfigureShortcutName}"

[Registry]
Root: HKLM; Subkey: "Software\Convertster"; ValueType: string; ValueName: "ExecutablePath"; ValueData: "{app}\ImageConverter.exe"; Flags: uninsdeletekey
Root: HKLM; Subkey: "Software\Convertster"; ValueType: string; ValueName: "InstallPath"; ValueData: "{app}"; Flags: uninsdeletekey
Root: HKCU; Subkey: "Software\Convertster"; Flags: uninsdeletekey

[Code]
Expand Down
Binary file modified ShellExtContextMenuHandler/ConvertsterContextMenuHandler.rc
Binary file not shown.
137 changes: 124 additions & 13 deletions ShellExtContextMenuHandler/FileContextMenuExt.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -50,11 +50,100 @@ void FileContextMenuExt::OnConvertToPng(HWND hWnd)
}
}

void FileContextMenuExt::OnConfigure(HWND hWnd)
{
std::wstring installPath;
HKEY hKey = nullptr;

LONG result = RegOpenKeyExW(
HKEY_LOCAL_MACHINE,
L"Software\\Convertster",
0,
KEY_READ,
&hKey);

if (result != ERROR_SUCCESS)
{
MessageBoxW(hWnd, L"Unable to open registry key for Convertster.", L_Friendly_Menu_Name, MB_OK | MB_ICONERROR);
return;
}

DWORD type = 0;
DWORD size = 0;

if (RegQueryValueExW(hKey, L"InstallPath", nullptr, &type, nullptr, &size) != ERROR_SUCCESS || type != REG_SZ)
{
RegCloseKey(hKey);
MessageBoxW(hWnd, L"Unable to read Convertster install path.", L_Friendly_Menu_Name, MB_OK | MB_ICONERROR);
return;
}

installPath.resize(size / sizeof(wchar_t), L'\0');

if (RegQueryValueExW(hKey, L"InstallPath", nullptr, nullptr, reinterpret_cast<LPBYTE>(&installPath[0]), &size) != ERROR_SUCCESS)
{
RegCloseKey(hKey);
MessageBoxW(hWnd, L"Unable to read Convertster install path.", L_Friendly_Menu_Name, MB_OK | MB_ICONERROR);
return;
}

installPath.resize(wcslen(installPath.c_str()));
RegCloseKey(hKey);

// Strip any trailing backslash before appending the filename.
if (!installPath.empty() && installPath.back() == L'\\')
{
installPath.pop_back();
}

// Build path to Configure.exe in the install directory.
std::wstring configurePath = installPath + L"\\Configure.exe";

if (!PathFileExistsW(configurePath.c_str()))
{
MessageBoxW(hWnd, L"Configure.exe not found.", L_Friendly_Menu_Name, MB_OK | MB_ICONERROR);
return;
}

std::wstring cmdLine = L"\"" + configurePath + L"\"";
std::vector<wchar_t> cmdLineBuf(cmdLine.begin(), cmdLine.end());
cmdLineBuf.push_back(L'\0');

STARTUPINFOW si = {};
si.cb = sizeof(si);
PROCESS_INFORMATION pi = {};

BOOL created = CreateProcessW(
nullptr,
cmdLineBuf.data(),
nullptr,
nullptr,
FALSE,
0,
nullptr,
nullptr,
&si,
&pi
);

if (!created)
{
DWORD err = GetLastError();
wchar_t errMsg[256];
StringCchPrintfW(errMsg, ARRAYSIZE(errMsg), L"CreateProcess failed (0x%08X).", static_cast<unsigned>(err));
MessageBoxW(hWnd, errMsg, L_Friendly_Menu_Name, MB_OK | MB_ICONERROR);
return;
}

CloseHandle(pi.hThread);
CloseHandle(pi.hProcess);
}

bool FileContextMenuExt::RunConverterCommand(HWND hWnd, PCWSTR targetFormat)
{
// Build command-line arguments: program path first, then the format,
// then each filename quoted.
std::wstring exePath;
std::wstring installPath;
HKEY hKey = nullptr;

LONG result = RegOpenKeyExW(
Expand All @@ -75,7 +164,7 @@ bool FileContextMenuExt::RunConverterCommand(HWND hWnd, PCWSTR targetFormat)

if (RegQueryValueExW(
hKey,
L"ExecutablePath",
L"InstallPath",
nullptr,
&type,
nullptr,
Expand All @@ -85,25 +174,34 @@ bool FileContextMenuExt::RunConverterCommand(HWND hWnd, PCWSTR targetFormat)
return false;
}

exePath.resize(size / sizeof(wchar_t), L'\0');
installPath.resize(size / sizeof(wchar_t), L'\0');

if (RegQueryValueExW(
hKey,
L"ExecutablePath",
L"InstallPath",
nullptr,
nullptr,
reinterpret_cast<LPBYTE>(&exePath[0]),
reinterpret_cast<LPBYTE>(&installPath[0]),
&size) != ERROR_SUCCESS)
{
RegCloseKey(hKey);
return false;
}

// Remove trailing null added by registry
exePath.resize(wcslen(exePath.c_str()));
installPath.resize(wcslen(installPath.c_str()));

RegCloseKey(hKey);

// Strip any trailing backslash before appending the filename.
if (!installPath.empty() && installPath.back() == L'\\')
{
installPath.pop_back();
}

// Build path to ImageConverter.exe in the install directory.
std::wstring exePath = installPath + L"\\ImageConverter.exe";

// Verify executable exists.
if (!PathFileExistsW(exePath.c_str()))
{
Expand Down Expand Up @@ -344,9 +442,11 @@ IFACEMETHODIMP FileContextMenuExt::QueryContextMenu(HMENU hMenu, UINT indexMenu,
// Load localized submenu strings into member variables
int toJpgLen = LoadStringW(m_hResourceInstance, IDS_TO_JPG, m_toJpgTextBuf, ARRAYSIZE(m_toJpgTextBuf));
int toPngLen = LoadStringW(m_hResourceInstance, IDS_TO_PNG, m_toPngTextBuf, ARRAYSIZE(m_toPngTextBuf));
int configureLen = LoadStringW(m_hResourceInstance, IDS_CONFIGURE, m_configureTextBuf, ARRAYSIZE(m_configureTextBuf));

const wchar_t* toJpgText = (toJpgLen > 0) ? m_toJpgTextBuf : L_To_JPG;
const wchar_t* toPngText = (toPngLen > 0) ? m_toPngTextBuf : L_To_PNG;
const wchar_t* configureText = (configureLen > 0) ? m_configureTextBuf : L_Configure;

if (!AppendMenuW(hSubMenu, MF_STRING, idCmdFirst + IDM_CONVERT_JPG, toJpgText))
{
Expand All @@ -355,15 +455,26 @@ IFACEMETHODIMP FileContextMenuExt::QueryContextMenu(HMENU hMenu, UINT indexMenu,
}

// Add "To PNG" only if none of the selected files are already PNGs
bool pngAdded = false;
if (!anyHasPng)
{
if (!AppendMenuW(hSubMenu, MF_STRING, idCmdFirst + IDM_CONVERT_PNG, toPngText))
{
DestroyMenu(hSubMenu);
return HRESULT_FROM_WIN32(GetLastError());
}
pngAdded = true;
}

// Add separator then Configure option
if (!AppendMenuW(hSubMenu, MF_SEPARATOR, 0, nullptr))
{
DestroyMenu(hSubMenu);
return HRESULT_FROM_WIN32(GetLastError());
}

if (!AppendMenuW(hSubMenu, MF_STRING, idCmdFirst + IDM_CONFIGURE, configureText))
{
DestroyMenu(hSubMenu);
return HRESULT_FROM_WIN32(GetLastError());
}

mii.hSubMenu = hSubMenu;
Expand All @@ -377,11 +488,7 @@ IFACEMETHODIMP FileContextMenuExt::QueryContextMenu(HMENU hMenu, UINT indexMenu,
// Return an HRESULT value with the severity set to SEVERITY_SUCCESS.
// Set the code value to the offset of the largest command identifier
// that was assigned, plus one (1).
USHORT largestId = static_cast<USHORT>(IDM_CONVERT_JPG);
if (pngAdded)
{
largestId = static_cast<USHORT>(IDM_CONVERT_PNG);
}
USHORT largestId = static_cast<USHORT>(IDM_CONFIGURE);

return MAKE_HRESULT(SEVERITY_SUCCESS, 0, static_cast<USHORT>(largestId + 1));
}
Expand All @@ -407,6 +514,10 @@ IFACEMETHODIMP FileContextMenuExt::InvokeCommand(LPCMINVOKECOMMANDINFO pCommandI
{
OnConvertToPng(pCommandInfo->hwnd);
}
else if (LOWORD(pCommandInfo->lpVerb) == IDM_CONFIGURE)
{
OnConfigure(pCommandInfo->hwnd);
}
else
{
return E_FAIL;
Expand Down
3 changes: 3 additions & 0 deletions ShellExtContextMenuHandler/FileContextMenuExt.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ enum
{
IDM_CONVERT_JPG = 0,
IDM_CONVERT_PNG = 1,
IDM_CONFIGURE = 2,
};

class FileContextMenuExt : public IShellExtInit, public IContextMenu
Expand Down Expand Up @@ -47,10 +48,12 @@ class FileContextMenuExt : public IShellExtInit, public IContextMenu
wchar_t m_menuTextBuf[256];
wchar_t m_toJpgTextBuf[128];
wchar_t m_toPngTextBuf[128];
wchar_t m_configureTextBuf[128];

// Handlers for conversion submenu
void OnConvertToJpg(HWND hWnd);
void OnConvertToPng(HWND hWnd);
void OnConfigure(HWND hWnd);

bool FileContextMenuExt::RunConverterCommand(HWND hWnd, PCWSTR targetFormat);

Expand Down
1 change: 1 addition & 0 deletions ShellExtContextMenuHandler/common.h
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
// English (default)
#define L_To_JPG L"To JPG"
#define L_To_PNG L"To PNG"
#define L_Configure L"Configure"

#define Verb_Name "imageconverter"
#define L_Verb_Name L"imageconverter"
Expand Down
1 change: 1 addition & 0 deletions ShellExtContextMenuHandler/resource.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,3 +9,4 @@
#define IDS_TO_JPG 201
#define IDS_TO_PNG 202
#define IDS_HELP_TEXT 203
#define IDS_CONFIGURE 204