Skip to content

Commit f8a4733

Browse files
authored
Port WinRT (#1302)
IB-8256 Signed-off-by: Raul Metsma <raul@metsma.ee>
1 parent d7f4bd8 commit f8a4733

File tree

9 files changed

+141
-232
lines changed

9 files changed

+141
-232
lines changed

extensions/windows/CMakeLists.txt

Lines changed: 1 addition & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -2,41 +2,24 @@ cmake_minimum_required(VERSION 3.16)
22
project(EsteidShellExtension VERSION 3.13.9)
33

44
set(CMAKE_MODULE_PATH ${CMAKE_SOURCE_DIR}/cmake/modules)
5-
set(CMAKE_INCLUDE_CURRENT_DIR ON)
65

76
include(VersionInfo)
87

98
if(CMAKE_SIZEOF_VOID_P EQUAL 8)
10-
set(MIDL_TARGET "x64")
119
set(PLATFORM "x64")
1210
else()
13-
set(MIDL_TARGET "win32")
1411
set(PLATFORM "x86")
1512
endif()
1613

17-
add_custom_command(
18-
OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/EsteidShellExtension_i.h
19-
${CMAKE_CURRENT_BINARY_DIR}/EsteidShellExtension_i.c
20-
COMMAND Midl.Exe ${CMAKE_CURRENT_SOURCE_DIR}/EsteidShellExtension.idl
21-
/nologo /target NT100 /char signed /env ${MIDL_TARGET}
22-
/tlb EsteidShellExtension.tlb
23-
/h EsteidShellExtension_i.h
24-
/iid EsteidShellExtension_i.c
25-
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
26-
VERBATIM
27-
)
28-
2914
add_library(${PROJECT_NAME} SHARED
30-
${CMAKE_CURRENT_BINARY_DIR}/EsteidShellExtension_i.c
3115
dllmain.cpp
3216
EsteidShellExtension.def
3317
EsteidShlExt.cpp
3418
EsteidShellExtension.rc
3519
)
3620
set_target_properties(${PROJECT_NAME} PROPERTIES
3721
MSVC_RUNTIME_LIBRARY "MultiThreaded$<$<CONFIG:Debug>:Debug>"
38-
COMPILE_DEFINITIONS "_UNICODE;UNICODE;_WINDLL"
39-
INCLUDE_DIRECTORIES ${CMAKE_CURRENT_BINARY_DIR}
22+
COMPILE_DEFINITIONS "_UNICODE;UNICODE;_WINDLL;WIN32_LEAN_AND_MEAN"
4023
INTERPROCEDURAL_OPTIMIZATION YES
4124
COMPILE_OPTIONS "/guard:cf"
4225
LINK_OPTIONS "/guard:cf"
@@ -47,7 +30,6 @@ set_target_properties(${PROJECT_NAME} PROPERTIES
4730
add_custom_target(msishellext DEPENDS ${PROJECT_NAME}
4831
COMMAND wix.exe build -nologo
4932
-arch ${PLATFORM}
50-
-d MSI_VERSION=${VERSION}
5133
-d ShellExt=$<TARGET_FILE:EsteidShellExtension>
5234
${CMAKE_CURRENT_SOURCE_DIR}/EsteidShellExtension.wxs
5335
${CMAKE_MODULE_PATH}/WelcomeDlg.wxs

extensions/windows/EsteidShellExtension.idl

Lines changed: 0 additions & 29 deletions
This file was deleted.

extensions/windows/EsteidShellExtension.wxs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
<Wix xmlns="http://wixtoolset.org/schemas/v4/wxs"
1616
xmlns:ui="http://wixtoolset.org/schemas/v4/wxs/ui">
1717
<Package Name="EstEID Shell Extension" UpgradeCode="$(var.ShellUpgradeCode)"
18-
Language="1033" Version="$(var.MSI_VERSION)" Codepage="1251" Manufacturer="RIA" InstallerVersion="500">
18+
Language="1033" Version="!(bind.FileVersion.ShellExt)" Manufacturer="RIA" InstallerVersion="500">
1919
<MediaTemplate EmbedCab="yes" CompressionLevel="high" />
2020
<MajorUpgrade AllowSameVersionUpgrades="yes" Schedule="afterInstallInitialize" DowngradeErrorMessage=
2121
"A newer version of [ProductName] is already installed. If you are trying to downgrade, please uninstall the newer version first." />
@@ -29,7 +29,7 @@
2929
<!--RegistryValue Root='HKCR' Key='*\shell\[ProductName]' Type='string' Value='Sign with [ProductName]' />
3030
<RegistryValue Root='HKCR' Key='*\shell\[ProductName]' Name="Icon" Type='string' Value='"[INSTALLFOLDER]qdigidoc4.exe",0' />
3131
<RegistryValue Root='HKCR' Key='*\shell\[ProductName]\command' Type='string' Value='"[INSTALLFOLDER]qdigidoc4.exe" "%1"' /-->
32-
<File Source="$(var.ShellExt)" />
32+
<File Id="ShellExt" Source="$(var.ShellExt)" />
3333
<RegistryKey Root="HKCR" Key="CLSID\$(var.ShellExtId)\InprocServer32">
3434
<RegistryValue Type="string" Value="[INSTALLFOLDER]EsteidShellExtension.dll" />
3535
<RegistryValue Type="string" Name="ThreadingModel" Value="Apartment" />

extensions/windows/EsteidShlExt.cpp

Lines changed: 72 additions & 101 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,18 @@
11
// EsteidShlExt.cpp : Implementation of CEsteidShlExt
22
// http://msdn.microsoft.com/en-us/library/bb757020.aspx
33

4-
#include "stdafx.h"
54
#include "EsteidShlExt.h"
5+
#include "resource.h"
6+
7+
#include <shellapi.h>
8+
#include <shlwapi.h>
9+
#include <uxtheme.h>
10+
11+
extern HINSTANCE instanceHandle;
612

713
typedef DWORD ARGB;
814

9-
bool HasAlpha(ARGB *pargb, SIZE &sizeImage, int cxRow)
15+
bool HasAlpha(ARGB *pargb, const SIZE &sizeImage, int cxRow)
1016
{
1117
ULONG cxDelta = cxRow - sizeImage.cx;
1218
for(ULONG y = sizeImage.cy; y; --y)
@@ -23,31 +29,16 @@ bool HasAlpha(ARGB *pargb, SIZE &sizeImage, int cxRow)
2329

2430
BITMAPINFO InitBitmapInfo(const SIZE &sizeImage)
2531
{
26-
BITMAPINFO pbmi = {};
27-
pbmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
32+
BITMAPINFO pbmi{{sizeof(BITMAPINFOHEADER)}};
2833
pbmi.bmiHeader.biPlanes = 1;
2934
pbmi.bmiHeader.biCompression = BI_RGB;
30-
3135
pbmi.bmiHeader.biWidth = sizeImage.cx;
3236
pbmi.bmiHeader.biHeight = sizeImage.cy;
3337
pbmi.bmiHeader.biBitCount = 32;
3438
return pbmi;
3539
}
3640

37-
HBITMAP Create32BitHBITMAP(HDC hdc, const SIZE &sizeImage, void **ppvBits)
38-
{
39-
BITMAPINFO bmi = InitBitmapInfo(sizeImage);
40-
if (HDC hdcUsed = hdc ? hdc : GetDC(nullptr))
41-
{
42-
HBITMAP phBmp = CreateDIBSection(hdcUsed, &bmi, DIB_RGB_COLORS, ppvBits, nullptr, 0);
43-
if (hdc != hdcUsed)
44-
ReleaseDC(NULL, hdcUsed);
45-
return phBmp;
46-
}
47-
return nullptr;
48-
}
49-
50-
HRESULT ConvertToPARGB32(HDC hdc, ARGB *pargb, HBITMAP hbmp, SIZE &sizeImage, int cxRow)
41+
HRESULT ConvertToPARGB32(HDC hdc, ARGB *pargb, HBITMAP hbmp, const SIZE &sizeImage, int cxRow)
5142
{
5243
BITMAPINFO bmi = InitBitmapInfo(sizeImage);
5344
HRESULT hr = E_OUTOFMEMORY;
@@ -77,7 +68,7 @@ HRESULT ConvertToPARGB32(HDC hdc, ARGB *pargb, HBITMAP hbmp, SIZE &sizeImage, in
7768
return hr;
7869
}
7970

80-
HRESULT ConvertBufferToPARGB32(HPAINTBUFFER hPaintBuffer, HDC hdc, HICON hicon, SIZE &sizeIcon)
71+
HRESULT ConvertBufferToPARGB32(HPAINTBUFFER hPaintBuffer, HDC hdc, HICON hicon, const SIZE &sizeIcon)
8172
{
8273
RGBQUAD *prgbQuad;
8374
int cxRow = 0;
@@ -102,18 +93,24 @@ HRESULT ConvertBufferToPARGB32(HPAINTBUFFER hPaintBuffer, HDC hdc, HICON hicon,
10293

10394
CEsteidShlExt::CEsteidShlExt()
10495
{
105-
SIZE sizeIcon = { GetSystemMetrics(SM_CXSMICON), GetSystemMetrics(SM_CYSMICON) };
106-
if(HICON hIcon = (HICON)LoadImage(_AtlBaseModule.GetModuleInstance(), MAKEINTRESOURCE(IDB_DIGIDOCICO), IMAGE_ICON, sizeIcon.cx, sizeIcon.cy, LR_DEFAULTCOLOR|LR_CREATEDIBSECTION))
96+
const SIZE sizeIcon { GetSystemMetrics(SM_CXSMICON), GetSystemMetrics(SM_CYSMICON) };
97+
if(HICON hIcon = (HICON)LoadImage(instanceHandle, MAKEINTRESOURCE(IDB_DIGIDOCICO), IMAGE_ICON, sizeIcon.cx, sizeIcon.cy, LR_DEFAULTCOLOR|LR_CREATEDIBSECTION))
10798
{
108-
if(HDC hdcDest = CreateCompatibleDC(nullptr)) {
109-
if((m_DigidocBmp = Create32BitHBITMAP(hdcDest, sizeIcon, nullptr))) {
110-
if(HBITMAP hbmpOld = (HBITMAP)SelectObject(hdcDest, m_DigidocBmp)) {
99+
if(HDC hdcDest = CreateCompatibleDC(nullptr))
100+
{
101+
BITMAPINFO bmi = InitBitmapInfo(sizeIcon);
102+
if((m_DigidocBmp = CreateDIBSection(hdcDest, &bmi, DIB_RGB_COLORS, nullptr, nullptr, 0)))
103+
{
104+
if(HBITMAP hbmpOld = (HBITMAP)SelectObject(hdcDest, m_DigidocBmp))
105+
{
111106
RECT rcIcon = { 0, 0, sizeIcon.cx, sizeIcon.cy };
112107
BLENDFUNCTION bfAlpha = { AC_SRC_OVER, 0, 255, AC_SRC_ALPHA };
113108
BP_PAINTPARAMS paintParams = { sizeof(paintParams), BPPF_ERASE, nullptr, &bfAlpha };
114109
HDC hdcBuffer;
115-
if(HPAINTBUFFER hPaintBuffer = BeginBufferedPaint(hdcDest, &rcIcon, BPBF_DIB, &paintParams, &hdcBuffer)) {
116-
if(DrawIconEx(hdcBuffer, 0, 0, hIcon, sizeIcon.cx, sizeIcon.cy, 0, nullptr, DI_NORMAL)) {
110+
if(HPAINTBUFFER hPaintBuffer = BeginBufferedPaint(hdcDest, &rcIcon, BPBF_DIB, &paintParams, &hdcBuffer))
111+
{
112+
if(DrawIconEx(hdcBuffer, 0, 0, hIcon, sizeIcon.cx, sizeIcon.cy, 0, nullptr, DI_NORMAL))
113+
{
117114
// If icon did not have an alpha channel, we need to convert buffer to PARGB.
118115
ConvertBufferToPARGB32(hPaintBuffer, hdcDest, hIcon, sizeIcon);
119116
}
@@ -136,13 +133,12 @@ CEsteidShlExt::~CEsteidShlExt()
136133
STDMETHODIMP CEsteidShlExt::Initialize(
137134
LPCITEMIDLIST /* pidlFolder */, LPDATAOBJECT pDataObj, HKEY /* hProgID */)
138135
{
139-
FORMATETC fmt = { CF_HDROP, nullptr, DVASPECT_CONTENT, -1, TYMED_HGLOBAL };
140-
STGMEDIUM stg = { TYMED_HGLOBAL };
136+
FORMATETC fmt{ CF_HDROP, nullptr, DVASPECT_CONTENT, -1, TYMED_HGLOBAL };
137+
STGMEDIUM stg{ TYMED_HGLOBAL };
141138
m_Files.clear();
142139

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

@@ -153,36 +149,21 @@ STDMETHODIMP CEsteidShlExt::Initialize(
153149
return E_INVALIDARG;
154150
}
155151

156-
// Sanity check - make sure there is at least one filename.
157-
UINT nFiles = DragQueryFile(hDrop, 0xFFFFFFFF, nullptr, 0);
158-
if (nFiles == 0) {
159-
GlobalUnlock(stg.hGlobal);
160-
ReleaseStgMedium(&stg);
161-
return E_INVALIDARG;
162-
}
163-
164-
for (UINT i = 0; i < nFiles; i++) {
152+
for (UINT i = 0, nFiles = DragQueryFile(hDrop, 0xFFFFFFFF, nullptr, 0); i < nFiles; i++) {
165153
// Get path length in chars
166154
UINT len = DragQueryFile(hDrop, i, nullptr, 0);
167155
if (len == 0 || len >= MAX_PATH)
168156
continue;
169157

170158
// Get the name of the file
171-
TCHAR szFile[MAX_PATH];
172-
if (DragQueryFile(hDrop, i, szFile, len+1) == 0)
173-
continue;
174-
175-
tstring str = tstring(szFile);
176-
if (str.empty())
177-
continue;
178-
179-
m_Files.push_back(str);
159+
auto &szFile = m_Files.emplace_back(len, 0);
160+
if (DragQueryFile(hDrop, i, szFile.data(), len + 1) != len)
161+
m_Files.pop_back();
180162
}
181163

182164
GlobalUnlock(stg.hGlobal);
183165
ReleaseStgMedium(&stg);
184166

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

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

197-
PCTCH sign = _T("Sign digitally");
198-
PCTCH encrypt = _T("Encrypt");
178+
LPCWSTR sign = L"Sign digitally";
179+
LPCWSTR encrypt = L"Encrypt";
199180
switch (PRIMARYLANGID(GetUserDefaultUILanguage()))
200181
{
201182
case LANG_ESTONIAN:
202-
sign = _T("Allkirjasta digitaalselt");
203-
encrypt = _T("Krüpteeri");
183+
sign = L"Allkirjasta digitaalselt";
184+
encrypt = L"Krüpteeri";
204185
break;
205186
case LANG_RUSSIAN:
206-
sign = _T("Подписать дигитально");
207-
encrypt = _T("Зашифровать");
187+
sign = L"Подписать дигитально";
188+
encrypt = L"Зашифровать";
208189
break;
209190
default: break;
210191
}
@@ -222,24 +203,26 @@ STDMETHODIMP CEsteidShlExt::QueryContextMenu(
222203
STDMETHODIMP CEsteidShlExt::GetCommandString(
223204
UINT_PTR idCmd, UINT uFlags, UINT * /* pwReserved */, LPSTR pszName, UINT cchMax)
224205
{
225-
USES_CONVERSION;
226-
227206
// Check idCmd, it must be 0 or 1 since we have only two menu items.
228207
if (idCmd > MENU_ENCRYPT)
229208
return E_INVALIDARG;
230209

231210
// If Explorer is asking for a help string, copy our string into the
232211
// supplied buffer.
233212
if (uFlags & GCS_HELPTEXT) {
234-
LPCTSTR szText = idCmd == MENU_SIGN ? _T("Allkirjasta valitud failid digitaalselt") : _T("Krüpteeri valitud failid");
235-
236213
if (uFlags & GCS_UNICODE) {
214+
LPCWSTR szText = idCmd == MENU_SIGN
215+
? L"Allkirjasta valitud failid digitaalselt"
216+
: L"Krüpteeri valitud failid";
237217
// We need to cast pszName to a Unicode string, and then use the
238218
// Unicode string copy API.
239-
lstrcpynW(LPWSTR(pszName), T2CW(szText), int(cchMax));
219+
lstrcpynW(LPWSTR(pszName), szText, int(cchMax));
240220
} else {
221+
LPCSTR szText = idCmd == MENU_SIGN
222+
? "Allkirjasta valitud failid digitaalselt"
223+
: "Krüpteeri valitud failid";
241224
// Use the ANSI string copy API to return the help string.
242-
lstrcpynA(pszName, T2CA(szText), int(cchMax));
225+
lstrcpynA(pszName, szText, int(cchMax));
243226
}
244227

245228
return S_OK;
@@ -248,59 +231,47 @@ STDMETHODIMP CEsteidShlExt::GetCommandString(
248231
return E_INVALIDARG;
249232
}
250233

251-
bool WINAPI CEsteidShlExt::FindRegistryInstallPath(tstring* path)
234+
bool WINAPI CEsteidShlExt::FindRegistryInstallPath(std::wstring &path)
252235
{
253-
static PCTCH IDCARD_REGKEY = _T("SOFTWARE\\RIA\\Open-EID");
254-
static PCTCH IDCARD_REGVALUE = _T("Installed");
255-
HKEY hkey;
256-
DWORD dwSize = MAX_PATH * sizeof(TCHAR);
257-
TCHAR szInstalldir[MAX_PATH];
258-
LSTATUS dwRet = RegOpenKeyEx(HKEY_LOCAL_MACHINE, IDCARD_REGKEY, 0, KEY_QUERY_VALUE, &hkey);
259-
if (dwRet == ERROR_SUCCESS) {
260-
dwRet = RegQueryValueEx(hkey, IDCARD_REGVALUE, nullptr, nullptr, LPBYTE(szInstalldir), &dwSize);
261-
RegCloseKey(hkey);
262-
*path = tstring(szInstalldir);
263-
return true;
264-
}
265-
dwRet = RegOpenKeyEx(HKEY_CURRENT_USER, IDCARD_REGKEY, 0, KEY_QUERY_VALUE, &hkey);
266-
if (dwRet == ERROR_SUCCESS) {
267-
RegCloseKey(hkey);
268-
*path = tstring(szInstalldir);
269-
return true;
270-
}
271-
return false;
236+
HKEY hkey{};
237+
if(RegOpenKeyEx(HKEY_LOCAL_MACHINE, L"SOFTWARE\\RIA\\Open-EID", 0, KEY_QUERY_VALUE, &hkey) != ERROR_SUCCESS)
238+
return false;
239+
DWORD dwSize = path.size() * sizeof(TCHAR);
240+
bool result = true;
241+
if(RegQueryValueEx(hkey, L"Installed", nullptr, nullptr, LPBYTE(path.data()), &dwSize) == ERROR_SUCCESS)
242+
path.resize(dwSize / sizeof(TCHAR) - 1); // size includes any terminating null
243+
else
244+
result = false;
245+
RegCloseKey(hkey);
246+
return result;
272247
}
273248

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

279-
tstring path(MAX_PATH, 0);
280-
tstring command(MAX_PATH, 0);
254+
std::wstring path(MAX_PATH, 0);
281255

282256
// Read the location of the installation from registry
283-
if (!FindRegistryInstallPath(&path)) {
284-
// .. and fall back to directory where shellext resides if not found from registry
285-
GetModuleFileName(_AtlBaseModule.m_hInst, &path[0], MAX_PATH);
286-
path.resize(path.find_last_of(_T('\\')) + 1);
287-
}
288-
289-
command = path + _T("qdigidoc4.exe");
290-
if(PathFileExists(command.c_str()) != 1) {
291-
// Replace "c:\Program Files\" with "c:\Program Files (x86)\"
292-
command.insert(16, _T(" (x86)"));
257+
if (!FindRegistryInstallPath(path)) {
258+
// .. and fall back to directory where shellext resides if not found from registry
259+
GetModuleFileName(instanceHandle, path.data(), path.size());
260+
path.resize(path.find_last_of(L'\\') + 1);
293261
}
294262

263+
path += L"qdigidoc4.exe";
295264
// Construct command line arguments to pass to qdigidocclient.exe
296-
tstring parameters = crypto ? _T("\"-crypto\" ") : _T("\"-sign\" ");
297-
for (const tstring &file: m_Files)
298-
parameters += _T("\"") + file + _T("\" ");
299-
300-
SHELLEXECUTEINFO seInfo = { sizeof(SHELLEXECUTEINFO) };
301-
seInfo.lpFile = command.c_str();
302-
seInfo.lpParameters = parameters.c_str();
303-
seInfo.nShow = SW_SHOW;
265+
std::wstring parameters = crypto ? L"\"-crypto\" " : L"\"-sign\" ";
266+
for (const auto &file: m_Files)
267+
parameters += L"\"" + file + L"\" ";
268+
269+
SHELLEXECUTEINFO seInfo{
270+
.cbSize = sizeof(SHELLEXECUTEINFO),
271+
.lpFile = path.c_str(),
272+
.lpParameters = parameters.c_str(),
273+
.nShow = SW_SHOW
274+
};
304275
return ShellExecuteEx(&seInfo) ? S_OK : S_FALSE;
305276
}
306277

0 commit comments

Comments
 (0)