Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Port WinRT #1302

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
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
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
Loading