Skip to content

Commit 3ef4484

Browse files
authored
New shell extension for MSIX packages (#1356)
IB-8590 Signed-off-by: Raul Metsma <[email protected]>
1 parent a3955d7 commit 3ef4484

File tree

11 files changed

+406
-272
lines changed

11 files changed

+406
-272
lines changed

AppxManifest.xml.cmake

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,13 @@
11
<?xml version="1.0" encoding="utf-8"?>
22
<Package xmlns="http://schemas.microsoft.com/appx/manifest/foundation/windows10"
3+
xmlns:com="http://schemas.microsoft.com/appx/manifest/com/windows10"
34
xmlns:desktop="http://schemas.microsoft.com/appx/manifest/desktop/windows10"
5+
xmlns:desktop4="http://schemas.microsoft.com/appx/manifest/desktop/windows10/4"
6+
xmlns:desktop5="http://schemas.microsoft.com/appx/manifest/desktop/windows10/5"
47
xmlns:rescap="http://schemas.microsoft.com/appx/manifest/foundation/windows10/restrictedcapabilities"
58
xmlns:uap="http://schemas.microsoft.com/appx/manifest/uap/windows10"
69
xmlns:uap3="http://schemas.microsoft.com/appx/manifest/uap/windows10/3"
7-
IgnorableNamespaces="desktop uap uap3 rescap">
10+
IgnorableNamespaces="com desktop desktop4 desktop5 rescap uap uap3">
811
<Identity Name="RiigiInfossteemiAmet.DigiDoc4client" ProcessorArchitecture="${PLATFORM}" Version="${PROJECT_VERSION}.0"
912
Publisher="CN=8BBBE4D8-620A-4884-A12A-72F1A2030D8B" />
1013
<Properties>
@@ -54,6 +57,22 @@
5457
</uap:SupportedFileTypes>
5558
</uap3:FileTypeAssociation>
5659
</uap3:Extension>
60+
<desktop4:Extension Category="windows.fileExplorerContextMenus">
61+
<desktop4:FileExplorerContextMenus>
62+
<desktop5:ItemType Type="*">
63+
<desktop5:Verb Id="DigiDocSign" Clsid="4ef3a5aa-125c-45f5-b5fd-d4c478050afa"/>
64+
<desktop5:Verb Id="DigiDocEnc" Clsid="bb67aa19-089b-4ec9-a059-13d985987cdc"/>
65+
</desktop5:ItemType>
66+
</desktop4:FileExplorerContextMenus>
67+
</desktop4:Extension>
68+
<com:Extension Category="windows.comServer">
69+
<com:ComServer>
70+
<com:SurrogateServer DisplayName="DigiDoc4 Shell Extension">
71+
<com:Class Id="4ef3a5aa-125c-45f5-b5fd-d4c478050afa" Path="EsteidShellExtensionV2.dll" ThreadingModel="STA"/>
72+
<com:Class Id="bb67aa19-089b-4ec9-a059-13d985987cdc" Path="EsteidShellExtensionV2.dll" ThreadingModel="STA"/>
73+
</com:SurrogateServer>
74+
</com:ComServer>
75+
</com:Extension>
5776
</Extensions>
5877
</Application>
5978
<Application Id="DigidocTool" Executable="digidoc-tool.exe" EntryPoint="Windows.FullTrustApplication">

client/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -272,6 +272,7 @@ elseif(WIN32)
272272
COMMAND ${CMAKE_COMMAND} -E make_directory appx
273273
COMMAND ${CMAKE_COMMAND} -E copy AppxManifest.xml appx
274274
COMMAND ${CMAKE_COMMAND} -E copy $<TARGET_FILE:${PROJECT_NAME}> appx
275+
COMMAND ${CMAKE_COMMAND} -E copy $<TARGET_FILE:EsteidShellExtensionV2> appx
275276
COMMAND ${CMAKE_COMMAND} -E copy ${LIBS_PATH}/libcrypto-3${OPENSSL_SUFFIX}.dll appx
276277
COMMAND ${CMAKE_COMMAND} -E copy ${LIBS_PATH}/libssl-3${OPENSSL_SUFFIX}.dll appx
277278
COMMAND ${CMAKE_COMMAND} -E copy ${LIBS_PATH}/zlib$<$<CONFIG:Debug>:d>1.dll appx

extensions/windows/CMakeLists.txt

Lines changed: 25 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,8 @@
11
cmake_minimum_required(VERSION 3.16)
22
project(EsteidShellExtension VERSION 3.13.9)
33
add_library(${PROJECT_NAME} SHARED
4-
dllmain.cpp
54
EsteidShellExtension.def
6-
EsteidShlExt.cpp
5+
EsteidShellExtension.cpp
76
EsteidShellExtension.rc
87
)
98
target_compile_definitions(${PROJECT_NAME} PRIVATE
@@ -19,7 +18,30 @@ set_target_properties(${PROJECT_NAME} PROPERTIES
1918
INTERPROCEDURAL_OPTIMIZATION YES
2019
COMPILE_OPTIONS "/guard:cf"
2120
LINK_OPTIONS "/guard:cf"
22-
LINK_LIBRARIES "uxtheme;RuntimeObject"
21+
LINK_LIBRARIES "uxtheme;RuntimeObject;Shlwapi"
22+
SKIP_AUTOMOC ON
23+
)
24+
25+
add_library(${PROJECT_NAME}V2 SHARED
26+
EsteidShellExtension.def
27+
EsteidShellExtensionV2.cpp
28+
EsteidShellExtension.rc
29+
)
30+
target_compile_definitions(${PROJECT_NAME}V2 PRIVATE
31+
_UNICODE
32+
UNICODE
33+
_WINDLL
34+
WIN32_LEAN_AND_MEAN
35+
NO_ICON
36+
VERSION=${PROJECT_VERSION_MAJOR},${PROJECT_VERSION_MINOR},${PROJECT_VERSION_PATCH},${BUILD_NUMBER}
37+
VERSION_STR="${VERSION}"
38+
)
39+
set_target_properties(${PROJECT_NAME}V2 PROPERTIES
40+
MSVC_RUNTIME_LIBRARY "MultiThreaded$<$<CONFIG:Debug>:Debug>"
41+
INTERPROCEDURAL_OPTIMIZATION YES
42+
COMPILE_OPTIONS "/guard:cf"
43+
LINK_OPTIONS "/guard:cf"
44+
LINK_LIBRARIES "uxtheme;RuntimeObject;Shlwapi"
2345
SKIP_AUTOMOC ON
2446
)
2547

extensions/windows/EsteidShlExt.cpp renamed to extensions/windows/EsteidShellExtension.cpp

Lines changed: 123 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,39 @@
1-
// EsteidShlExt.cpp : Implementation of CEsteidShlExt
2-
// http://msdn.microsoft.com/en-us/library/bb757020.aspx
1+
/*
2+
* EsteidShellExtension
3+
*
4+
* This library is free software; you can redistribute it and/or
5+
* modify it under the terms of the GNU Lesser General Public
6+
* License as published by the Free Software Foundation; either
7+
* version 2.1 of the License, or (at your option) any later version.
8+
*
9+
* This library is distributed in the hope that it will be useful,
10+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
11+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12+
* Lesser General Public License for more details.
13+
*
14+
* You should have received a copy of the GNU Lesser General Public
15+
* License along with this library; if not, write to the Free Software
16+
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
17+
*
18+
*/
319

4-
#include "EsteidShlExt.h"
520
#include "resource.h"
621

22+
#include <unknwn.h>
23+
#include <winrt/base.h>
724
#include <shellapi.h>
25+
#include <ShlObj.h>
826
#include <shlwapi.h>
927
#include <uxtheme.h>
1028

11-
extern HINSTANCE instanceHandle;
29+
#include <string>
30+
#include <vector>
1231

13-
typedef DWORD ARGB;
32+
extern "C" IMAGE_DOS_HEADER __ImageBase;
1433

15-
bool HasAlpha(ARGB *pargb, const SIZE &sizeImage, int cxRow)
34+
using ARGB = DWORD;
35+
36+
static bool HasAlpha(ARGB *pargb, const SIZE &sizeImage, int cxRow)
1637
{
1738
ULONG cxDelta = cxRow - sizeImage.cx;
1839
for(ULONG y = sizeImage.cy; y; --y)
@@ -27,18 +48,19 @@ bool HasAlpha(ARGB *pargb, const SIZE &sizeImage, int cxRow)
2748
return false;
2849
}
2950

30-
BITMAPINFO InitBitmapInfo(const SIZE &sizeImage)
51+
static BITMAPINFO InitBitmapInfo(const SIZE &sizeImage)
3152
{
32-
BITMAPINFO pbmi{{sizeof(BITMAPINFOHEADER)}};
33-
pbmi.bmiHeader.biPlanes = 1;
34-
pbmi.bmiHeader.biCompression = BI_RGB;
35-
pbmi.bmiHeader.biWidth = sizeImage.cx;
36-
pbmi.bmiHeader.biHeight = sizeImage.cy;
37-
pbmi.bmiHeader.biBitCount = 32;
38-
return pbmi;
53+
return {{
54+
.biSize = sizeof(BITMAPINFOHEADER),
55+
.biWidth = sizeImage.cx,
56+
.biHeight = sizeImage.cy,
57+
.biPlanes = 1,
58+
.biBitCount = 32,
59+
.biCompression = BI_RGB,
60+
}};
3961
}
4062

41-
HRESULT ConvertToPARGB32(HDC hdc, ARGB *pargb, HBITMAP hbmp, const SIZE &sizeImage, int cxRow)
63+
static HRESULT ConvertToPARGB32(HDC hdc, ARGB *pargb, HBITMAP hbmp, const SIZE &sizeImage, int cxRow)
4264
{
4365
BITMAPINFO bmi = InitBitmapInfo(sizeImage);
4466
HRESULT hr = E_OUTOFMEMORY;
@@ -68,7 +90,7 @@ HRESULT ConvertToPARGB32(HDC hdc, ARGB *pargb, HBITMAP hbmp, const SIZE &sizeIma
6890
return hr;
6991
}
7092

71-
HRESULT ConvertBufferToPARGB32(HPAINTBUFFER hPaintBuffer, HDC hdc, HICON hicon, const SIZE &sizeIcon)
93+
static HRESULT ConvertBufferToPARGB32(HPAINTBUFFER hPaintBuffer, HDC hdc, HICON hicon, const SIZE &sizeIcon)
7294
{
7395
RGBQUAD *prgbQuad;
7496
int cxRow = 0;
@@ -91,10 +113,42 @@ HRESULT ConvertBufferToPARGB32(HPAINTBUFFER hPaintBuffer, HDC hdc, HICON hicon,
91113
return hr;
92114
}
93115

116+
struct
117+
#ifdef _WIN64
118+
__declspec(uuid("5606A547-759D-43DA-AEEB-D3BF1D1E816D"))
119+
#else
120+
__declspec(uuid("310AAB39-76FE-401B-8A7F-0F578C5F6AB5"))
121+
#endif
122+
CEsteidShlExt : public winrt::implements<CEsteidShlExt, IShellExtInit, IContextMenu>
123+
{
124+
CEsteidShlExt();
125+
~CEsteidShlExt() override;
126+
127+
// IShellExtInit
128+
STDMETHODIMP Initialize(LPCITEMIDLIST pidlFolder, LPDATAOBJECT pdtobj, HKEY hkeyProgID) final;
129+
130+
// IContextMenu
131+
STDMETHODIMP QueryContextMenu(HMENU, UINT, UINT, UINT, UINT) final;
132+
STDMETHODIMP InvokeCommand(LPCMINVOKECOMMANDINFO) final;
133+
STDMETHODIMP GetCommandString(UINT_PTR, UINT, UINT *, LPSTR, UINT) final;
134+
135+
private:
136+
enum : uint8_t {
137+
MENU_SIGN = 0,
138+
MENU_ENCRYPT = 1,
139+
};
140+
141+
static bool WINAPI FindRegistryInstallPath(std::wstring &path);
142+
STDMETHODIMP ExecuteDigidocclient(LPCMINVOKECOMMANDINFO pCmdInfo, bool crypto = false);
143+
144+
HBITMAP m_DigidocBmp = nullptr;
145+
std::vector<std::wstring> m_Files;
146+
};
147+
94148
CEsteidShlExt::CEsteidShlExt()
95149
{
96150
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))
151+
if(HICON hIcon = (HICON)LoadImage(reinterpret_cast<HMODULE>(&__ImageBase), MAKEINTRESOURCE(IDB_DIGIDOCICO), IMAGE_ICON, sizeIcon.cx, sizeIcon.cy, LR_DEFAULTCOLOR|LR_CREATEDIBSECTION))
98152
{
99153
if(HDC hdcDest = CreateCompatibleDC(nullptr))
100154
{
@@ -211,9 +265,17 @@ STDMETHODIMP CEsteidShlExt::GetCommandString(
211265
// supplied buffer.
212266
if (uFlags & GCS_HELPTEXT) {
213267
if (uFlags & GCS_UNICODE) {
214-
LPCWSTR szText = idCmd == MENU_SIGN
215-
? L"Allkirjasta valitud failid digitaalselt"
216-
: L"Krüpteeri valitud failid";
268+
LPCWSTR szText = idCmd == MENU_ENCRYPT ? L"Encrypt selected files" : L"Digitally sign selected files";
269+
switch(PRIMARYLANGID(GetUserDefaultUILanguage()))
270+
{
271+
case LANG_ESTONIAN:
272+
szText = idCmd == MENU_ENCRYPT ? L"Krüpteeri valitud failid" : L"Allkirjasta valitud failid digitaalselt";
273+
break;
274+
case LANG_RUSSIAN:
275+
szText = idCmd == MENU_ENCRYPT ? L"Зашифровать выбранные файлы" : L"Цифровая подпись выбранных файлов";
276+
break;
277+
default: break;
278+
}
217279
// We need to cast pszName to a Unicode string, and then use the
218280
// Unicode string copy API.
219281
lstrcpynW(LPWSTR(pszName), szText, int(cchMax));
@@ -256,7 +318,7 @@ STDMETHODIMP CEsteidShlExt::ExecuteDigidocclient(LPCMINVOKECOMMANDINFO /* pCmdIn
256318
// Read the location of the installation from registry
257319
if (!FindRegistryInstallPath(path)) {
258320
// .. and fall back to directory where shellext resides if not found from registry
259-
GetModuleFileName(instanceHandle, path.data(), path.size());
321+
GetModuleFileName(reinterpret_cast<HMODULE>(&__ImageBase), path.data(), path.size());
260322
path.resize(path.find_last_of(L'\\') + 1);
261323
}
262324

@@ -291,3 +353,43 @@ STDMETHODIMP CEsteidShlExt::InvokeCommand(LPCMINVOKECOMMANDINFO pCmdInfo)
291353
return E_INVALIDARG;
292354
}
293355
}
356+
357+
struct CEsteidShlExtFactory : winrt::implements<CEsteidShlExtFactory, IClassFactory>
358+
{
359+
STDMETHODIMP CreateInstance(
360+
IUnknown *pUnkOuter, REFIID riid, LPVOID *ppvObject) noexcept final try {
361+
if(!ppvObject)
362+
return E_POINTER;
363+
*ppvObject = nullptr;
364+
if(pUnkOuter)
365+
return CLASS_E_NOAGGREGATION;
366+
return winrt::make<CEsteidShlExt>().as(riid, ppvObject);
367+
} catch (...) {
368+
return winrt::to_hresult();
369+
}
370+
371+
STDMETHODIMP LockServer(BOOL /*fLock*/) noexcept final {
372+
return S_OK;
373+
}
374+
};
375+
376+
// Used to determine whether the DLL can be unloaded by OLE
377+
STDMETHODIMP DllCanUnloadNow()
378+
{
379+
if (winrt::get_module_lock())
380+
return S_FALSE;
381+
winrt::clear_factory_cache();
382+
return S_OK;
383+
}
384+
385+
// Returns a class factory to create an object of the requested type
386+
//STDAPI DllGetClassObject(REFCLSID rclsid, REFIID riid, LPVOID *result)
387+
STDMETHODIMP DllGetClassObject(const GUID &clsid, const GUID &iid, LPVOID *result) try
388+
{
389+
*result = nullptr;
390+
if (clsid == __uuidof(CEsteidShlExt))
391+
return winrt::make<CEsteidShlExtFactory>().as(iid, result);
392+
return winrt::hresult_class_not_available().to_abi();
393+
} catch (...) {
394+
return winrt::to_hresult();
395+
}

0 commit comments

Comments
 (0)