Skip to content

Commit

Permalink
Port WinRT
Browse files Browse the repository at this point in the history
IB-8256

Signed-off-by: Raul Metsma <raul@metsma.ee>
  • Loading branch information
metsma committed Nov 7, 2024
1 parent cd8d216 commit 2b2f22d
Show file tree
Hide file tree
Showing 9 changed files with 138 additions and 229 deletions.
20 changes: 1 addition & 19 deletions extensions/windows/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -2,41 +2,24 @@ cmake_minimum_required(VERSION 3.16)
project(EsteidShellExtension VERSION 3.13.9)

set(CMAKE_MODULE_PATH ${CMAKE_SOURCE_DIR}/cmake/modules)
set(CMAKE_INCLUDE_CURRENT_DIR ON)

include(VersionInfo)

if(CMAKE_SIZEOF_VOID_P EQUAL 8)
set(MIDL_TARGET "x64")
set(PLATFORM "x64")
else()
set(MIDL_TARGET "win32")
set(PLATFORM "x86")
endif()

add_custom_command(
OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/EsteidShellExtension_i.h
${CMAKE_CURRENT_BINARY_DIR}/EsteidShellExtension_i.c
COMMAND Midl.Exe ${CMAKE_CURRENT_SOURCE_DIR}/EsteidShellExtension.idl
/nologo /target NT100 /char signed /env ${MIDL_TARGET}
/tlb EsteidShellExtension.tlb
/h EsteidShellExtension_i.h
/iid EsteidShellExtension_i.c
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
VERBATIM
)

add_library(${PROJECT_NAME} SHARED
${CMAKE_CURRENT_BINARY_DIR}/EsteidShellExtension_i.c
dllmain.cpp
EsteidShellExtension.def
EsteidShlExt.cpp
EsteidShellExtension.rc
)
set_target_properties(${PROJECT_NAME} PROPERTIES
MSVC_RUNTIME_LIBRARY "MultiThreaded$<$<CONFIG:Debug>:Debug>"
COMPILE_DEFINITIONS "_UNICODE;UNICODE;_WINDLL"
INCLUDE_DIRECTORIES ${CMAKE_CURRENT_BINARY_DIR}
COMPILE_DEFINITIONS "_UNICODE;UNICODE;_WINDLL;WIN32_LEAN_AND_MEAN"
INTERPROCEDURAL_OPTIMIZATION YES
COMPILE_OPTIONS "/guard:cf"
LINK_OPTIONS "/guard:cf"
Expand All @@ -47,7 +30,6 @@ set_target_properties(${PROJECT_NAME} PROPERTIES
add_custom_target(msishellext DEPENDS ${PROJECT_NAME}
COMMAND wix.exe build -nologo
-arch ${PLATFORM}
-d MSI_VERSION=${VERSION}
-d ShellExt=$<TARGET_FILE:EsteidShellExtension>
${CMAKE_CURRENT_SOURCE_DIR}/EsteidShellExtension.wxs
${CMAKE_MODULE_PATH}/WelcomeDlg.wxs
Expand Down
29 changes: 0 additions & 29 deletions extensions/windows/EsteidShellExtension.idl

This file was deleted.

4 changes: 2 additions & 2 deletions extensions/windows/EsteidShellExtension.wxs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
<Wix xmlns="http://wixtoolset.org/schemas/v4/wxs"
xmlns:ui="http://wixtoolset.org/schemas/v4/wxs/ui">
<Package Name="EstEID Shell Extension" UpgradeCode="$(var.ShellUpgradeCode)"
Language="1033" Version="$(var.MSI_VERSION)" Codepage="1251" Manufacturer="RIA" InstallerVersion="500">
Language="1033" Version="!(bind.FileVersion.ShellExt)" Manufacturer="RIA" InstallerVersion="500">
<MediaTemplate EmbedCab="yes" CompressionLevel="high" />
<MajorUpgrade AllowSameVersionUpgrades="yes" Schedule="afterInstallInitialize" DowngradeErrorMessage=
"A newer version of [ProductName] is already installed. If you are trying to downgrade, please uninstall the newer version first." />
Expand All @@ -29,7 +29,7 @@
<!--RegistryValue Root='HKCR' Key='*\shell\[ProductName]' Type='string' Value='Sign with [ProductName]' />
<RegistryValue Root='HKCR' Key='*\shell\[ProductName]' Name="Icon" Type='string' Value='"[INSTALLFOLDER]qdigidoc4.exe",0' />
<RegistryValue Root='HKCR' Key='*\shell\[ProductName]\command' Type='string' Value='"[INSTALLFOLDER]qdigidoc4.exe" "%1"' /-->
<File Source="$(var.ShellExt)" />
<File Id="ShellExt" Source="$(var.ShellExt)" />
<RegistryKey Root="HKCR" Key="CLSID\$(var.ShellExtId)\InprocServer32">
<RegistryValue Type="string" Value="[INSTALLFOLDER]EsteidShellExtension.dll" />
<RegistryValue Type="string" Name="ThreadingModel" Value="Apartment" />
Expand Down
167 changes: 69 additions & 98 deletions extensions/windows/EsteidShlExt.cpp
Original file line number Diff line number Diff line change
@@ -1,12 +1,18 @@
// EsteidShlExt.cpp : Implementation of CEsteidShlExt
// http://msdn.microsoft.com/en-us/library/bb757020.aspx

#include "stdafx.h"
#include "EsteidShlExt.h"
#include "resource.h"

#include <shellapi.h>
#include <shlwapi.h>
#include <uxtheme.h>

extern HINSTANCE instanceHandle;

typedef DWORD ARGB;

bool HasAlpha(ARGB *pargb, SIZE &sizeImage, int cxRow)
bool HasAlpha(ARGB *pargb, const SIZE &sizeImage, int cxRow)
{
ULONG cxDelta = cxRow - sizeImage.cx;
for(ULONG y = sizeImage.cy; y; --y)
Expand All @@ -23,31 +29,16 @@ bool HasAlpha(ARGB *pargb, SIZE &sizeImage, int cxRow)

BITMAPINFO InitBitmapInfo(const SIZE &sizeImage)
{
BITMAPINFO pbmi = {};
pbmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
BITMAPINFO pbmi{{sizeof(BITMAPINFOHEADER)}};
pbmi.bmiHeader.biPlanes = 1;
pbmi.bmiHeader.biCompression = BI_RGB;

pbmi.bmiHeader.biWidth = sizeImage.cx;
pbmi.bmiHeader.biHeight = sizeImage.cy;
pbmi.bmiHeader.biBitCount = 32;
return pbmi;
}

HBITMAP Create32BitHBITMAP(HDC hdc, const SIZE &sizeImage, void **ppvBits)
{
BITMAPINFO bmi = InitBitmapInfo(sizeImage);
if (HDC hdcUsed = hdc ? hdc : GetDC(nullptr))
{
HBITMAP phBmp = CreateDIBSection(hdcUsed, &bmi, DIB_RGB_COLORS, ppvBits, nullptr, 0);
if (hdc != hdcUsed)
ReleaseDC(NULL, hdcUsed);
return phBmp;
}
return nullptr;
}

HRESULT ConvertToPARGB32(HDC hdc, ARGB *pargb, HBITMAP hbmp, SIZE &sizeImage, int cxRow)
HRESULT ConvertToPARGB32(HDC hdc, ARGB *pargb, HBITMAP hbmp, const SIZE &sizeImage, int cxRow)
{
BITMAPINFO bmi = InitBitmapInfo(sizeImage);
HRESULT hr = E_OUTOFMEMORY;
Expand Down Expand Up @@ -77,7 +68,7 @@ HRESULT ConvertToPARGB32(HDC hdc, ARGB *pargb, HBITMAP hbmp, SIZE &sizeImage, in
return hr;
}

HRESULT ConvertBufferToPARGB32(HPAINTBUFFER hPaintBuffer, HDC hdc, HICON hicon, SIZE &sizeIcon)
HRESULT ConvertBufferToPARGB32(HPAINTBUFFER hPaintBuffer, HDC hdc, HICON hicon, const SIZE &sizeIcon)
{
RGBQUAD *prgbQuad;
int cxRow = 0;
Expand All @@ -102,18 +93,24 @@ HRESULT ConvertBufferToPARGB32(HPAINTBUFFER hPaintBuffer, HDC hdc, HICON hicon,

CEsteidShlExt::CEsteidShlExt()
{
SIZE sizeIcon = { GetSystemMetrics(SM_CXSMICON), GetSystemMetrics(SM_CYSMICON) };
if(HICON hIcon = (HICON)LoadImage(_AtlBaseModule.GetModuleInstance(), MAKEINTRESOURCE(IDB_DIGIDOCICO), IMAGE_ICON, sizeIcon.cx, sizeIcon.cy, LR_DEFAULTCOLOR|LR_CREATEDIBSECTION))
const SIZE sizeIcon { GetSystemMetrics(SM_CXSMICON), GetSystemMetrics(SM_CYSMICON) };
if(HICON hIcon = (HICON)LoadImage(instanceHandle, MAKEINTRESOURCE(IDB_DIGIDOCICO), IMAGE_ICON, sizeIcon.cx, sizeIcon.cy, LR_DEFAULTCOLOR|LR_CREATEDIBSECTION))
{
if(HDC hdcDest = CreateCompatibleDC(nullptr)) {
if((m_DigidocBmp = Create32BitHBITMAP(hdcDest, sizeIcon, nullptr))) {
if(HBITMAP hbmpOld = (HBITMAP)SelectObject(hdcDest, m_DigidocBmp)) {
if(HDC hdcDest = CreateCompatibleDC(nullptr))
{
BITMAPINFO bmi = InitBitmapInfo(sizeIcon);
if((m_DigidocBmp = CreateDIBSection(hdcDest, &bmi, DIB_RGB_COLORS, nullptr, nullptr, 0)))
{
if(HBITMAP hbmpOld = (HBITMAP)SelectObject(hdcDest, m_DigidocBmp))
{
RECT rcIcon = { 0, 0, sizeIcon.cx, sizeIcon.cy };
BLENDFUNCTION bfAlpha = { AC_SRC_OVER, 0, 255, AC_SRC_ALPHA };
BP_PAINTPARAMS paintParams = { sizeof(paintParams), BPPF_ERASE, nullptr, &bfAlpha };
HDC hdcBuffer;
if(HPAINTBUFFER hPaintBuffer = BeginBufferedPaint(hdcDest, &rcIcon, BPBF_DIB, &paintParams, &hdcBuffer)) {
if(DrawIconEx(hdcBuffer, 0, 0, hIcon, sizeIcon.cx, sizeIcon.cy, 0, nullptr, DI_NORMAL)) {
if(HPAINTBUFFER hPaintBuffer = BeginBufferedPaint(hdcDest, &rcIcon, BPBF_DIB, &paintParams, &hdcBuffer))
{
if(DrawIconEx(hdcBuffer, 0, 0, hIcon, sizeIcon.cx, sizeIcon.cy, 0, nullptr, DI_NORMAL))
{
// If icon did not have an alpha channel, we need to convert buffer to PARGB.
ConvertBufferToPARGB32(hPaintBuffer, hdcDest, hIcon, sizeIcon);
}
Expand All @@ -136,13 +133,12 @@ CEsteidShlExt::~CEsteidShlExt()
STDMETHODIMP CEsteidShlExt::Initialize(
LPCITEMIDLIST /* pidlFolder */, LPDATAOBJECT pDataObj, HKEY /* hProgID */)
{
FORMATETC fmt = { CF_HDROP, nullptr, DVASPECT_CONTENT, -1, TYMED_HGLOBAL };
STGMEDIUM stg = { TYMED_HGLOBAL };
FORMATETC fmt{ CF_HDROP, nullptr, DVASPECT_CONTENT, -1, TYMED_HGLOBAL };
STGMEDIUM stg{ TYMED_HGLOBAL };
m_Files.clear();

// Look for CF_HDROP data in the data object.
if (FAILED(pDataObj->GetData(&fmt, &stg))) {
// Nope! Return an "invalid argument" error back to Explorer.
return E_INVALIDARG;
}

Expand All @@ -153,36 +149,21 @@ STDMETHODIMP CEsteidShlExt::Initialize(
return E_INVALIDARG;
}

// Sanity check - make sure there is at least one filename.
UINT nFiles = DragQueryFile(hDrop, 0xFFFFFFFF, nullptr, 0);
if (nFiles == 0) {
GlobalUnlock(stg.hGlobal);
ReleaseStgMedium(&stg);
return E_INVALIDARG;
}

for (UINT i = 0; i < nFiles; i++) {
for (UINT i = 0, nFiles = DragQueryFile(hDrop, 0xFFFFFFFF, nullptr, 0); i < nFiles; i++) {
// Get path length in chars
UINT len = DragQueryFile(hDrop, i, nullptr, 0);
if (len == 0 || len >= MAX_PATH)
continue;

// Get the name of the file
TCHAR szFile[MAX_PATH];
if (DragQueryFile(hDrop, i, szFile, len+1) == 0)
continue;

tstring str = tstring(szFile);
if (str.empty())
continue;

m_Files.push_back(str);
auto &szFile = m_Files.emplace_back(len, 0);
if (DragQueryFile(hDrop, i, szFile.data(), len + 1) != len)
m_Files.pop_back();
}

GlobalUnlock(stg.hGlobal);
ReleaseStgMedium(&stg);

// Don't show menu if no items were found
return m_Files.empty() ? E_INVALIDARG : S_OK;
}

Expand All @@ -194,17 +175,17 @@ STDMETHODIMP CEsteidShlExt::QueryContextMenu(
if (uFlags & CMF_DEFAULTONLY)
return MAKE_HRESULT(SEVERITY_SUCCESS, FACILITY_NULL, 0);

PCTCH sign = _T("Sign digitally");
PCTCH encrypt = _T("Encrypt");
LPCWSTR sign = L"Sign digitally";
LPCWSTR encrypt = L"Encrypt";
switch (PRIMARYLANGID(GetUserDefaultUILanguage()))
{
case LANG_ESTONIAN:
sign = _T("Allkirjasta digitaalselt");
encrypt = _T("Krüpteeri");
sign = L"Allkirjasta digitaalselt";
encrypt = L"Krüpteeri";
break;
case LANG_RUSSIAN:
sign = _T("Подписать дигитально");
encrypt = _T("Зашифровать");
sign = L"Подписать дигитально";
encrypt = L"Зашифровать";
break;
default: break;
}
Expand All @@ -222,24 +203,26 @@ STDMETHODIMP CEsteidShlExt::QueryContextMenu(
STDMETHODIMP CEsteidShlExt::GetCommandString(
UINT_PTR idCmd, UINT uFlags, UINT * /* pwReserved */, LPSTR pszName, UINT cchMax)
{
USES_CONVERSION;

// Check idCmd, it must be 0 or 1 since we have only two menu items.
if (idCmd > MENU_ENCRYPT)
return E_INVALIDARG;

// If Explorer is asking for a help string, copy our string into the
// supplied buffer.
if (uFlags & GCS_HELPTEXT) {
LPCTSTR szText = idCmd == MENU_SIGN ? _T("Allkirjasta valitud failid digitaalselt") : _T("Krüpteeri valitud failid");

if (uFlags & GCS_UNICODE) {
LPCWSTR szText = idCmd == MENU_SIGN
? L"Allkirjasta valitud failid digitaalselt"
: L"Krüpteeri valitud failid";
// We need to cast pszName to a Unicode string, and then use the
// Unicode string copy API.
lstrcpynW(LPWSTR(pszName), T2CW(szText), int(cchMax));
lstrcpynW(LPWSTR(pszName), szText, int(cchMax));
} else {
LPCSTR szText = idCmd == MENU_SIGN
? "Allkirjasta valitud failid digitaalselt"
: "Krüpteeri valitud failid";
// Use the ANSI string copy API to return the help string.
lstrcpynA(pszName, T2CA(szText), int(cchMax));
lstrcpynA(pszName, szText, int(cchMax));
}

return S_OK;
Expand All @@ -248,57 +231,45 @@ STDMETHODIMP CEsteidShlExt::GetCommandString(
return E_INVALIDARG;
}

bool WINAPI CEsteidShlExt::FindRegistryInstallPath(tstring* path)
bool WINAPI CEsteidShlExt::FindRegistryInstallPath(std::wstring &path)
{
static PCTCH IDCARD_REGKEY = _T("SOFTWARE\\RIA\\Open-EID");
static PCTCH IDCARD_REGVALUE = _T("Installed");
HKEY hkey;
DWORD dwSize = MAX_PATH * sizeof(TCHAR);
TCHAR szInstalldir[MAX_PATH];
LSTATUS dwRet = RegOpenKeyEx(HKEY_LOCAL_MACHINE, IDCARD_REGKEY, 0, KEY_QUERY_VALUE, &hkey);
if (dwRet == ERROR_SUCCESS) {
dwRet = RegQueryValueEx(hkey, IDCARD_REGVALUE, nullptr, nullptr, LPBYTE(szInstalldir), &dwSize);
RegCloseKey(hkey);
*path = tstring(szInstalldir);
return true;
}
dwRet = RegOpenKeyEx(HKEY_CURRENT_USER, IDCARD_REGKEY, 0, KEY_QUERY_VALUE, &hkey);
if (dwRet == ERROR_SUCCESS) {
RegCloseKey(hkey);
*path = tstring(szInstalldir);
return true;
}
return false;
static LPCWSTR IDCARD_REGKEY = L"SOFTWARE\\RIA\\Open-EID";
static LPCWSTR IDCARD_REGVALUE = L"Installed";
HKEY hkey{};
if(RegOpenKeyEx(HKEY_LOCAL_MACHINE, IDCARD_REGKEY, 0, KEY_QUERY_VALUE, &hkey))
return false;
DWORD dwSize = path.size() * sizeof(TCHAR);
bool result = true;
if(RegQueryValueEx(hkey, IDCARD_REGVALUE, nullptr, nullptr, LPBYTE(path.data()), &dwSize))
path.resize(dwSize / sizeof(TCHAR) - 1); // size includes any terminating null
else
result = false;
RegCloseKey(hkey);
return result;
}

STDMETHODIMP CEsteidShlExt::ExecuteDigidocclient(LPCMINVOKECOMMANDINFO /* pCmdInfo */, bool crypto)
{
if (m_Files.empty())
return E_INVALIDARG;

tstring path(MAX_PATH, 0);
tstring command(MAX_PATH, 0);
std::wstring path(MAX_PATH, 0);

// Read the location of the installation from registry
if (!FindRegistryInstallPath(&path)) {
// .. and fall back to directory where shellext resides if not found from registry
GetModuleFileName(_AtlBaseModule.m_hInst, &path[0], MAX_PATH);
path.resize(path.find_last_of(_T('\\')) + 1);
}

command = path + _T("qdigidoc4.exe");
if(PathFileExists(command.c_str()) != 1) {
// Replace "c:\Program Files\" with "c:\Program Files (x86)\"
command.insert(16, _T(" (x86)"));
if (!FindRegistryInstallPath(path)) {
// .. and fall back to directory where shellext resides if not found from registry
GetModuleFileName(instanceHandle, path.data(), path.size());
path.resize(path.find_last_of(L'\\') + 1);
}

path += L"qdigidoc4.exe";
// Construct command line arguments to pass to qdigidocclient.exe
tstring parameters = crypto ? _T("\"-crypto\" ") : _T("\"-sign\" ");
for (const tstring &file: m_Files)
parameters += _T("\"") + file + _T("\" ");
std::wstring parameters = crypto ? L"\"-crypto\" " : L"\"-sign\" ";
for (const auto &file: m_Files)
parameters += L"\"" + file + L"\" ";

SHELLEXECUTEINFO seInfo = { sizeof(SHELLEXECUTEINFO) };
seInfo.lpFile = command.c_str();
SHELLEXECUTEINFO seInfo{ sizeof(SHELLEXECUTEINFO) };
seInfo.lpFile = path.c_str();
seInfo.lpParameters = parameters.c_str();
seInfo.nShow = SW_SHOW;
return ShellExecuteEx(&seInfo) ? S_OK : S_FALSE;
Expand Down
Loading

0 comments on commit 2b2f22d

Please sign in to comment.