diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index d690d1c84..87c896284 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -198,7 +198,6 @@ jobs: -Dlibdigidocpp_ROOT=${{ github.workspace }}/libs/PFiles64 ^ ${{ matrix.platform == 'arm64' && '-DQT_HOST_PATH=%QT_HOST_PATH%' || '' }} cmake --build build --target msi - cmake --build build --target msishellext cmake --build build --target appx - name: Archive artifacts uses: actions/upload-artifact@v7 diff --git a/client/CMakeLists.txt b/client/CMakeLists.txt index 475f57341..3b4accdd1 100644 --- a/client/CMakeLists.txt +++ b/client/CMakeLists.txt @@ -196,7 +196,7 @@ if( APPLE ) elseif(WIN32) target_sources(${PROJECT_NAME} PRIVATE QCNG.cpp QCNG.h) target_compile_options(${PROJECT_NAME} PRIVATE "/guard:cf") - target_link_options(${PROJECT_NAME} PRIVATE "/guard:cf" $<$:/INTEGRITYCHECK>) + target_link_options(${PROJECT_NAME} PRIVATE "/guard:cf") target_link_libraries(${PROJECT_NAME} NCrypt Crypt32 Cryptui winscard) get_filename_component(LIBS_PATH ${libdigidocpp_DIR} DIRECTORY) get_filename_component(LIBS_PATH ${LIBS_PATH} DIRECTORY) @@ -229,7 +229,7 @@ elseif(WIN32) list(APPEND SIGNCMD signtool.exe sign /a /v /s MY /n "${SIGNCERT}" /fd SHA256 /du http://installer.id.ee /tr http://timestamp.digicert.com /td SHA256) add_custom_command(TARGET ${PROJECT_NAME} POST_BUILD - COMMAND ${SIGNCMD} "$<$:/ph;/ac;${CROSSSIGNCERT}>" $ + COMMAND ${SIGNCMD} $ COMMAND_EXPAND_LISTS ) add_custom_command(TARGET msi POST_BUILD diff --git a/client/Diagnostics_win.cpp b/client/Diagnostics_win.cpp index 7b619761e..5439386b2 100644 --- a/client/Diagnostics_win.cpp +++ b/client/Diagnostics_win.cpp @@ -149,7 +149,7 @@ void Diagnostics::run() + ";C:\\Program Files (x86)\\EstIDMinidriver Minidriver"); SetDllDirectory(LPCWSTR(QCoreApplication::applicationDirPath().utf16())); static const QStringList dlls{ - "digidocpp", "qdigidoc4.exe", "EsteidShellExtension", "id-updater.exe", "web-eid.exe", + "digidocpp", "qdigidoc4.exe", "EsteidShellExtensionV2.dll", "id-updater.exe", "web-eid.exe", "EstIDMinidriver", "EstIDMinidriver64", "EestiMinidriver", "EestiMinidriver64", "estgsv4md", "estgsv4md64", "zlib1", "z", "libxml2", "libxmlsec1", "libxmlsec1-openssl", "msvcp140", "msvcp140_1", "msvcp140_2", "vcruntime140", "vcruntime140_1"}; diff --git a/extensions/windows/CMakeLists.txt b/extensions/windows/CMakeLists.txt index bc70c082a..88a5a89dc 100644 --- a/extensions/windows/CMakeLists.txt +++ b/extensions/windows/CMakeLists.txt @@ -1,42 +1,17 @@ -cmake_minimum_required(VERSION 3.16) -project(EsteidShellExtension VERSION 3.13.9) -add_library(${PROJECT_NAME} SHARED - EsteidShellExtension.def - EsteidShellExtension.cpp - EsteidShellExtension.rc -) -target_compile_definitions(${PROJECT_NAME} PRIVATE - _UNICODE - UNICODE - _WINDLL - WIN32_LEAN_AND_MEAN - VERSION=${PROJECT_VERSION_MAJOR},${PROJECT_VERSION_MINOR},${PROJECT_VERSION_PATCH},${BUILD_NUMBER} - VERSION_STR="${VERSION}" -) -set_target_properties(${PROJECT_NAME} PROPERTIES - MSVC_RUNTIME_LIBRARY "MultiThreaded$<$:Debug>" - INTERPROCEDURAL_OPTIMIZATION YES - COMPILE_OPTIONS "/guard:cf" - LINK_OPTIONS "/guard:cf" - LINK_LIBRARIES "uxtheme;RuntimeObject;Shlwapi" - SKIP_AUTOMOC ON -) - -add_library(${PROJECT_NAME}V2 SHARED +add_library(EsteidShellExtensionV2 SHARED EsteidShellExtension.def EsteidShellExtensionV2.cpp EsteidShellExtension.rc ) -target_compile_definitions(${PROJECT_NAME}V2 PRIVATE +target_compile_definitions(EsteidShellExtensionV2 PRIVATE _UNICODE UNICODE _WINDLL WIN32_LEAN_AND_MEAN - NO_ICON VERSION=${PROJECT_VERSION_MAJOR},${PROJECT_VERSION_MINOR},${PROJECT_VERSION_PATCH},${BUILD_NUMBER} VERSION_STR="${VERSION}" ) -set_target_properties(${PROJECT_NAME}V2 PROPERTIES +set_target_properties(EsteidShellExtensionV2 PROPERTIES MSVC_RUNTIME_LIBRARY "MultiThreaded$<$:Debug>" INTERPROCEDURAL_OPTIMIZATION YES COMPILE_OPTIONS "/guard:cf" @@ -45,20 +20,6 @@ set_target_properties(${PROJECT_NAME}V2 PROPERTIES SKIP_AUTOMOC ON ) -add_custom_target(msishellext DEPENDS ${PROJECT_NAME} - COMMAND wix.exe build -nologo - -arch $ENV{PLATFORM} - -d ShellExt=$ - ${CMAKE_CURRENT_SOURCE_DIR}/EsteidShellExtension.wxs - ${CMAKE_CURRENT_SOURCE_DIR}/../../common/WelcomeDlg.wxs - ${CMAKE_CURRENT_SOURCE_DIR}/../../common/WixUI_Minimal.wxs - -ext WixToolset.UI.wixext - -bv WixUIDialogBmp=${CMAKE_CURRENT_SOURCE_DIR}/../../common/dlgbmp.bmp - -bv WixUIBannerBmp=${CMAKE_CURRENT_SOURCE_DIR}/../../common/banner.bmp - -o Digidoc_ShellExt-${VERSION}$ENV{VER_SUFFIX}.$ENV{PLATFORM}.msi - WORKING_DIRECTORY ${CMAKE_BINARY_DIR} -) - set(PLATFORM $ENV{PLATFORM}) if(SIGNCERT) execute_process( @@ -73,7 +34,7 @@ file(GENERATE OUTPUT ${CMAKE_BINARY_DIR}/AppxManifest-ShellExt.xml INPUT ${CMAKE set(SHELLEXT_MSIX_FILE "DigiDoc4Shell.msix") set(SHELLEXT_MSIX_FILE ${SHELLEXT_MSIX_FILE} PARENT_SCOPE) -add_custom_target(msixshellext DEPENDS ${PROJECT_NAME}V2 +add_custom_target(msixshellext DEPENDS EsteidShellExtensionV2 COMMAND ${CMAKE_COMMAND} -E remove ${SHELLEXT_MSIX_FILE} COMMAND ${CMAKE_COMMAND} -E remove_directory appxshell COMMAND ${CMAKE_COMMAND} -E make_directory appxshell @@ -84,23 +45,8 @@ add_custom_target(msixshellext DEPENDS ${PROJECT_NAME}V2 ) if(SIGNCERT) - if(CROSSSIGNCERT) - target_link_options(${PROJECT_NAME} PRIVATE "/INTEGRITYCHECK") - endif() - add_custom_command(TARGET ${PROJECT_NAME} POST_BUILD - COMMAND signtool.exe sign /a /v /s MY /n "${SIGNCERT}" /fd SHA256 /du http://installer.id.ee - "$<$:/ph;/ac;${CROSSSIGNCERT}>" - /tr http://timestamp.digicert.com /td SHA256 $ - COMMAND_EXPAND_LISTS - ) - add_custom_command(TARGET msishellext POST_BUILD - COMMAND signtool.exe sign /a /v /s MY /n "${SIGNCERT}" /fd SHA256 /du http://installer.id.ee - /tr http://timestamp.digicert.com /td SHA256 - "${CMAKE_BINARY_DIR}/Digidoc_ShellExt-${VERSION}$ENV{VER_SUFFIX}.$ENV{PLATFORM}.msi" - ) - add_custom_command(TARGET ${PROJECT_NAME}V2 POST_BUILD + add_custom_command(TARGET EsteidShellExtensionV2 POST_BUILD COMMAND signtool.exe sign /a /v /s MY /n "${SIGNCERT}" /fd SHA256 /du http://installer.id.ee - "$<$:/ph;/ac;${CROSSSIGNCERT}>" /tr http://timestamp.digicert.com /td SHA256 $ COMMAND_EXPAND_LISTS ) diff --git a/extensions/windows/EsteidShellExtension.cpp b/extensions/windows/EsteidShellExtension.cpp deleted file mode 100644 index cea238ade..000000000 --- a/extensions/windows/EsteidShellExtension.cpp +++ /dev/null @@ -1,387 +0,0 @@ -/* - * EsteidShellExtension - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - */ - -#include "resource.h" - -#include -#include -#include -#include -#include -#include - -#include -#include - -extern "C" IMAGE_DOS_HEADER __ImageBase; - -using ARGB = DWORD; - -static constexpr bool HasAlpha(ARGB *pargb, const SIZE &sizeImage, int cxRow) -{ - ULONG cxDelta = cxRow - sizeImage.cx; - for(ULONG y = sizeImage.cy; y; --y) - { - for(ULONG x = sizeImage.cx; x; --x) - { - if(*pargb++ & 0xFF000000) - return true; - } - pargb += cxDelta; - } - return false; -} - -static constexpr BITMAPINFO InitBitmapInfo(const SIZE &sizeImage) -{ - return {{ - .biSize = sizeof(BITMAPINFOHEADER), - .biWidth = sizeImage.cx, - .biHeight = sizeImage.cy, - .biPlanes = 1, - .biBitCount = 32, - .biCompression = BI_RGB, - }}; -} - -static HRESULT ConvertToPARGB32(HDC hdc, ARGB *pargb, HBITMAP hbmp, const SIZE &sizeImage, int cxRow) try -{ - BITMAPINFO bmi = InitBitmapInfo(sizeImage); - HRESULT hr = E_UNEXPECTED; - std::vector pvBits(bmi.bmiHeader.biWidth * bmi.bmiHeader.biHeight); - if (GetDIBits(hdc, hbmp, 0, bmi.bmiHeader.biHeight, pvBits.data(), &bmi, DIB_RGB_COLORS) == bmi.bmiHeader.biHeight) - { - ULONG cxDelta = cxRow - bmi.bmiHeader.biWidth; - ARGB *pargbMask = pvBits.data(); - for (ULONG y = bmi.bmiHeader.biHeight; y; --y) - { - for (ULONG x = bmi.bmiHeader.biWidth; x; --x) - { - if (*pargbMask++) // transparent pixel - *pargb++ = 0; - else // opaque pixel - *pargb++ |= 0xFF000000; - } - pargb += cxDelta; - } - hr = S_OK; - } - return hr; -} -catch (...) -{ - return winrt::to_hresult(); -} - -static HRESULT ConvertBufferToPARGB32(HPAINTBUFFER hPaintBuffer, HDC hdc, HICON hicon, const SIZE &sizeIcon) -{ - RGBQUAD *prgbQuad; - int cxRow = 0; - HRESULT hr = GetBufferedPaintBits(hPaintBuffer, &prgbQuad, &cxRow); - if (SUCCEEDED(hr)) - { - ARGB *pargb = reinterpret_cast(prgbQuad); - if (!HasAlpha(pargb, sizeIcon, cxRow)) - { - ICONINFO info = {}; - if (GetIconInfo(hicon, &info)) - { - if (info.hbmMask) - hr = ConvertToPARGB32(hdc, pargb, info.hbmMask, sizeIcon, cxRow); - DeleteObject(info.hbmColor); - DeleteObject(info.hbmMask); - } - } - } - return hr; -} - -struct -#ifdef _WIN64 - __declspec(uuid("5606A547-759D-43DA-AEEB-D3BF1D1E816D")) -#else - __declspec(uuid("310AAB39-76FE-401B-8A7F-0F578C5F6AB5")) -#endif - CEsteidShlExt : public winrt::implements -{ - CEsteidShlExt(); - ~CEsteidShlExt() override; - - // IShellExtInit - STDMETHODIMP Initialize(LPCITEMIDLIST pidlFolder, LPDATAOBJECT pdtobj, HKEY hkeyProgID) final; - - // IContextMenu - STDMETHODIMP QueryContextMenu(HMENU, UINT, UINT, UINT, UINT) final; - STDMETHODIMP InvokeCommand(LPCMINVOKECOMMANDINFO) final; - STDMETHODIMP GetCommandString(UINT_PTR, UINT, UINT *, LPSTR, UINT) final; - -private: - enum : uint8_t { - MENU_SIGN = 0, - MENU_ENCRYPT = 1, - }; - - static bool WINAPI FindRegistryInstallPath(std::wstring &path); - STDMETHODIMP ExecuteDigidocclient(LPCMINVOKECOMMANDINFO pCmdInfo, bool crypto = false); - - HBITMAP m_DigidocBmp = nullptr; - std::vector m_Files; -}; - -CEsteidShlExt::CEsteidShlExt() -{ - const SIZE sizeIcon { GetSystemMetrics(SM_CXSMICON), GetSystemMetrics(SM_CYSMICON) }; - if(HICON hIcon = (HICON)LoadImage(reinterpret_cast(&__ImageBase), MAKEINTRESOURCE(IDB_DIGIDOCICO), IMAGE_ICON, sizeIcon.cx, sizeIcon.cy, LR_DEFAULTCOLOR|LR_CREATEDIBSECTION)) - { - 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 icon did not have an alpha channel, we need to convert buffer to PARGB. - ConvertBufferToPARGB32(hPaintBuffer, hdcDest, hIcon, sizeIcon); - } - EndBufferedPaint(hPaintBuffer, TRUE); - } - SelectObject(hdcDest, hbmpOld); - } - } - DeleteDC(hdcDest); - } - DestroyIcon(hIcon); - } -} - -CEsteidShlExt::~CEsteidShlExt() -{ - DeleteObject(m_DigidocBmp); -} - -STDMETHODIMP CEsteidShlExt::Initialize( - LPCITEMIDLIST /* pidlFolder */, LPDATAOBJECT pDataObj, HKEY /* hProgID */) -{ - 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))) { - return E_INVALIDARG; - } - - // Get a pointer to the actual data. - HDROP hDrop = HDROP(GlobalLock(stg.hGlobal)); - if (!hDrop) { - ReleaseStgMedium(&stg); - return E_INVALIDARG; - } - - 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 - 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); - - return m_Files.empty() ? E_INVALIDARG : S_OK; -} - -STDMETHODIMP CEsteidShlExt::QueryContextMenu( - HMENU hmenu, UINT uMenuIndex, UINT uidFirstCmd, - UINT /* uidLastCmd */, UINT uFlags) -{ - // If the flags include CMF_DEFAULTONLY then we shouldn't do anything. - if (uFlags & CMF_DEFAULTONLY) - return MAKE_HRESULT(SEVERITY_SUCCESS, FACILITY_NULL, 0); - - LPCWSTR sign = L"Sign digitally"; - LPCWSTR encrypt = L"Encrypt"; - switch (PRIMARYLANGID(GetUserDefaultUILanguage())) - { - case LANG_ESTONIAN: - sign = L"Allkirjasta digitaalselt"; - encrypt = L"Krüpteeri"; - break; - default: break; - } - - InsertMenu(hmenu, uMenuIndex, MF_STRING | MF_BYPOSITION, uidFirstCmd, sign); - if (m_DigidocBmp) - SetMenuItemBitmaps(hmenu, uMenuIndex, MF_BYPOSITION, m_DigidocBmp, nullptr); - InsertMenu(hmenu, uMenuIndex + MENU_ENCRYPT, MF_STRING | MF_BYPOSITION, uidFirstCmd + MENU_ENCRYPT, encrypt); - if (m_DigidocBmp) - SetMenuItemBitmaps(hmenu, uMenuIndex + MENU_ENCRYPT, MF_BYPOSITION, m_DigidocBmp, nullptr); - - return MAKE_HRESULT(SEVERITY_SUCCESS, FACILITY_NULL, 2); -} - -STDMETHODIMP CEsteidShlExt::GetCommandString( - UINT_PTR idCmd, UINT uFlags, UINT * /* pwReserved */, LPSTR pszName, UINT cchMax) -{ - // 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) { - if (uFlags & GCS_UNICODE) { - LPCWSTR szText = idCmd == MENU_ENCRYPT ? L"Encrypt selected files" : L"Digitally sign selected files"; - switch(PRIMARYLANGID(GetUserDefaultUILanguage())) - { - case LANG_ESTONIAN: - szText = idCmd == MENU_ENCRYPT ? L"Krüpteeri valitud failid" : L"Allkirjasta valitud failid digitaalselt"; - break; - default: break; - } - // We need to cast pszName to a Unicode string, and then use the - // Unicode string copy API. - 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, szText, int(cchMax)); - } - - return S_OK; - } - - return E_INVALIDARG; -} - -bool WINAPI CEsteidShlExt::FindRegistryInstallPath(std::wstring &path) -{ - HKEY hkey{}; - if(RegOpenKeyEx(HKEY_LOCAL_MACHINE, L"SOFTWARE\\RIA\\Open-EID", 0, KEY_QUERY_VALUE, &hkey) != ERROR_SUCCESS) - return false; - DWORD dwSize = path.size() * sizeof(TCHAR); - bool result = true; - if(RegQueryValueEx(hkey, L"Installed", nullptr, nullptr, LPBYTE(path.data()), &dwSize) == ERROR_SUCCESS) - 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; - - 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(reinterpret_cast(&__ImageBase), 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 - std::wstring parameters = crypto ? L"\"-crypto\" " : L"\"-sign\" "; - for (const auto &file: m_Files) - parameters += L"\"" + file + L"\" "; - - SHELLEXECUTEINFO seInfo{ - .cbSize = sizeof(SHELLEXECUTEINFO), - .lpFile = path.c_str(), - .lpParameters = parameters.c_str(), - .nShow = SW_SHOW - }; - return ShellExecuteEx(&seInfo) ? S_OK : S_FALSE; -} - -STDMETHODIMP CEsteidShlExt::InvokeCommand(LPCMINVOKECOMMANDINFO pCmdInfo) -{ - // If lpVerb really points to a string, ignore this function call and bail out. - if (HIWORD(pCmdInfo->lpVerb) != 0) - return E_INVALIDARG; - - // Get the command index - the valid ones are 0 and 1. - switch (LOWORD(pCmdInfo->lpVerb)) { - case MENU_SIGN: - return ExecuteDigidocclient(pCmdInfo); - case MENU_ENCRYPT: - return ExecuteDigidocclient(pCmdInfo, true); - default: - return E_INVALIDARG; - } -} - -struct CEsteidShlExtFactory : winrt::implements -{ - STDMETHODIMP CreateInstance( - IUnknown *pUnkOuter, REFIID riid, LPVOID *ppvObject) noexcept final try { - if(!ppvObject) - return E_POINTER; - *ppvObject = nullptr; - if(pUnkOuter) - return CLASS_E_NOAGGREGATION; - return winrt::make().as(riid, ppvObject); - } catch (...) { - return winrt::to_hresult(); - } - - STDMETHODIMP LockServer(BOOL /*fLock*/) noexcept final { - return S_OK; - } -}; - -// Used to determine whether the DLL can be unloaded by OLE -STDMETHODIMP DllCanUnloadNow() -{ - if (winrt::get_module_lock()) - return S_FALSE; - winrt::clear_factory_cache(); - return S_OK; -} - -// Returns a class factory to create an object of the requested type -//STDAPI DllGetClassObject(REFCLSID rclsid, REFIID riid, LPVOID *result) -STDMETHODIMP DllGetClassObject(const GUID &clsid, const GUID &iid, LPVOID *result) try -{ - *result = nullptr; - if (clsid == __uuidof(CEsteidShlExt)) - return winrt::make().as(iid, result); - return winrt::hresult_class_not_available().to_abi(); -} catch (...) { - return winrt::to_hresult(); -} diff --git a/extensions/windows/EsteidShellExtension.def b/extensions/windows/EsteidShellExtension.def index 4a07f5a74..4d7b7fa70 100644 --- a/extensions/windows/EsteidShellExtension.def +++ b/extensions/windows/EsteidShellExtension.def @@ -1,6 +1,6 @@ ; EsteidShellExtension.def : Declares the module parameters. -LIBRARY "EsteidShellExtension.DLL" +LIBRARY "EsteidShellExtensionV2.DLL" EXPORTS DllCanUnloadNow PRIVATE diff --git a/extensions/windows/EsteidShellExtension.rc b/extensions/windows/EsteidShellExtension.rc index 5b9fdb817..fe2760e0a 100644 --- a/extensions/windows/EsteidShellExtension.rc +++ b/extensions/windows/EsteidShellExtension.rc @@ -18,7 +18,6 @@ */ #include -#include "resource.h" VS_VERSION_INFO VERSIONINFO FILEVERSION VERSION @@ -40,9 +39,9 @@ BEGIN VALUE "CompanyName", "RIA" VALUE "FileDescription", "Estonian ID Card Software explorer integration" VALUE "FileVersion", VERSION_STR - VALUE "InternalName", "EsteidShellExtension.dll" + VALUE "InternalName", "EsteidShellExtensionV2.dll" VALUE "LegalCopyright", "(c) RIA. All rights reserved." - VALUE "OriginalFilename", "EsteidShellExtension.dll" + VALUE "OriginalFilename", "EsteidShellExtensionV2.dll" VALUE "ProductName", "Estonian ID Card Software" VALUE "ProductVersion", VERSION_STR END @@ -52,7 +51,3 @@ BEGIN VALUE "Translation", 0x409, 1252 END END - -#ifndef NO_ICON -IDB_DIGIDOCICO ICON "digidoc.ico" -#endif diff --git a/extensions/windows/EsteidShellExtension.wxs b/extensions/windows/EsteidShellExtension.wxs deleted file mode 100644 index b56604bd2..000000000 --- a/extensions/windows/EsteidShellExtension.wxs +++ /dev/null @@ -1,45 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/extensions/windows/EsteidShellExtensionV2.cpp b/extensions/windows/EsteidShellExtensionV2.cpp index 4754b824c..eb0c5e2ef 100644 --- a/extensions/windows/EsteidShellExtensionV2.cpp +++ b/extensions/windows/EsteidShellExtensionV2.cpp @@ -1,4 +1,4 @@ -/* +/* * EsteidShellExtension * * This library is free software; you can redistribute it and/or @@ -24,8 +24,18 @@ #include #include +#include + extern "C" IMAGE_DOS_HEADER __ImageBase; +struct CoTaskMemDeleter +{ + void operator()(void *value) const noexcept + { + CoTaskMemFree(value); + } +}; + template struct EsteidShellExtension : public winrt::implements, IExplorerCommand> { @@ -42,11 +52,19 @@ struct EsteidShellExtension : public winrt::implementsGetItemAt(i, &psi); FAILED(hr)) + winrt::com_ptr item; + if(auto hr = psiItemArray->GetItemAt(i, item.put()); FAILED(hr)) return hr; - LPWSTR path{}; - auto hr = psi->GetDisplayName(SIGDN_FILESYSPATH, &path); - psi->Release(); + LPWSTR value{}; + auto hr = item->GetDisplayName(SIGDN_FILESYSPATH, &value); if(FAILED(hr)) return hr; + std::unique_ptr path(value); + if(!path) + return E_UNEXPECTED; parameters += L"\""; - parameters += path; + parameters += path.get(); parameters += L"\" "; - if(path) - CoTaskMemFree(path); } SHELLEXECUTEINFO seInfo{ .cbSize = sizeof(SHELLEXECUTEINFO), @@ -106,33 +129,48 @@ struct EsteidShellExtension : public winrt::implements(&__ImageBase), path.data(), DWORD(path.size())); size > 0) - path.resize(size); - else - path.clear(); - if(auto pos = path.find_last_of('\\'); pos != std::wstring::npos) - { - path.resize(pos); - path += L"\\qdigidoc4.exe"; - } + // The maximum extended-length path is 32,767 characters plus the null terminator. + std::wstring path(32768, 0); + auto size = GetModuleFileNameW( + reinterpret_cast(&__ImageBase), path.data(), DWORD(path.size())); + if(size == 0 || size >= path.size()) + return {}; + path.resize(size); + auto pos = path.find_last_of(L"\\/"); + if(pos == std::wstring::npos) + return {}; + path.resize(pos + 1); + path += L"qdigidoc4.exe"; return path; } + catch (...) { + return {}; + } }; struct __declspec(uuid("4ef3a5aa-125c-45f5-b5fd-d4c478050afa")) diff --git a/extensions/windows/digidoc.ico b/extensions/windows/digidoc.ico deleted file mode 100644 index 658ea2e93..000000000 Binary files a/extensions/windows/digidoc.ico and /dev/null differ diff --git a/extensions/windows/resource.h b/extensions/windows/resource.h deleted file mode 100644 index 30e42c460..000000000 --- a/extensions/windows/resource.h +++ /dev/null @@ -1,22 +0,0 @@ -/* - * EsteidShellExtension - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - */ - -#pragma once - -#define IDB_DIGIDOCICO 201