Page Menu
Home
GnuPG
Search
Configure Global Search
Log In
Files
F34113489
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Award Token
Size
17 KB
Subscribers
None
View Options
diff --git a/src/gpga/CMakeLists.txt b/src/gpga/CMakeLists.txt
index 1e8e8c3..3502ad1 100644
--- a/src/gpga/CMakeLists.txt
+++ b/src/gpga/CMakeLists.txt
@@ -1,28 +1,29 @@
# Copyright (C) 2018 Andre Heinecke <aheinecke@gnupg.com>
#
# This file is Free Software under the GNU GPL (v>=2)
# and comes with ABSOLUTELY NO WARRANTY!
# See LICENSE.txt for details.
set(EXECUTABLE_NAME "gpga")
set(EXECUTABLE_SRC
flange.cpp
../util/debug.cpp
../util/w32-util.cpp
gpga.def
+ gpgshellfolder.cpp
)
add_library (${EXECUTABLE_NAME}
${EXECUTABLE_SRC}
)
target_link_libraries(${EXECUTABLE_NAME}
PRIVATE Gpgmepp
)
set_target_properties(${EXECUTABLE_NAME} PROPERTIES LINK_FLAGS "-municode")
set_target_properties(${EXECUTABLE_NAME} PROPERTIES PREFIX "")
install(TARGETS ${EXECUTABLE_NAME} DESTINATION bin)
diff --git a/src/gpga/flange.cpp b/src/gpga/flange.cpp
index b77d6e5..15c5144 100644
--- a/src/gpga/flange.cpp
+++ b/src/gpga/flange.cpp
@@ -1,271 +1,277 @@
/* Copyright (C) 2018 by Andre Heinecke <aheinecke@gnupg.com>
*
* This file is Free Software under the GNU GPL (v>=2)
* and comes with ABSOLUTELY NO WARRANTY!
* See LICENSE.txt for details.
*/
#include "flange.h"
#include "debug.h"
#include "comhelp.h"
#include "w32-util.h"
+#include "gpgshellfolder.h"
#include "shlobj.h"
/** @file Code to flange to the Windows explorer.
*
* This file contains the Windows and COM API requirements
* to properly work as an explorer extension.
*/
#ifndef INITGUID
/* Include every header that defines a GUID below this
macro. Otherwise the GUID's will only be declared and
not defined. */
#define INITGUID
#endif
#include <initguid.h>
#define MY_CLSID_STR "CCD955E4-5C16-4A33-AFDA-A8947A94946C"
DEFINE_GUID(MY_CLSID, 0xCCD955E4, 0x5C16, 0x4A33,
0xAF, 0xDA, 0xA8, 0x94, 0x7A, 0x94, 0x94, 0x6C);
#define MY_PROGID "GpgArchive"
static HINSTANCE s_hinst;
static FlangeFactory *s_factory;
static void init_logging()
{
static bool wasDone;
if (!wasDone) {
gpgrt_log_set_sink("c:\\tmp\\gpga.txt", nullptr, -1);
wasDone = true;
}
}
/* Here we go */
STDAPI DllGetClassObject (REFCLSID rclsid, REFIID riid, LPVOID* ppv)
{
init_logging ();
- log_debug ("Get class object for clsid'" GUID_FMT "'",
- GUID_ARG(riid));
if (!ppv) {
return E_POINTER;
}
*ppv = nullptr;
if (rclsid == MY_CLSID) {
return FlangeFactory::instance()->QueryInterface(riid, ppv);
}
+ log_debug ("Get class object for nonimp clsid'" GUID_FMT "'",
+ GUID_ARG(riid));
+
return CLASS_E_CLASSNOTAVAILABLE;
}
STDMETHODIMP FlangeFactory::LockServer (BOOL lock)
{
if (lock) {
AddRef();
} else {
Release();
}
return S_OK;
}
-STDMETHODIMP FlangeFactory::CreateInstance (LPUNKNOWN unknown,
+STDMETHODIMP FlangeFactory::CreateInstance (LPUNKNOWN,
REFIID riid,
LPVOID* ppvObj)
{
- log_debug ("CreateInstance with id '" GUID_FMT "'",
- GUID_ARG(riid));
+ if (riid == IID_IShellFolder) {
+ auto folder = new GpgShellFolder();
+ return folder->QueryInterface (riid, ppvObj);
+ }
+ log_debug ("CreateInstance with unimplemented id '" GUID_FMT "'",
+ GUID_ARG(riid));
return E_NOINTERFACE;
}
STDMETHODIMP FlangeFactory::QueryInterface (REFIID riid, void **ppv)
{
- log_debug ("QueryInterface:'" GUID_FMT "'",
- GUID_ARG(riid));
-
if (!ppv) {
return E_POINTER;
}
*ppv = nullptr;
/* The static casts ensure that the virtual function table
layout of the returned object is correct. */
- if (riid == IID_IUnknown)
+ if (riid == IID_IUnknown) {
*ppv = static_cast<IUnknown *> (this);
- else if (riid == IID_IClassFactory)
+ } else if (riid == IID_IClassFactory) {
*ppv = static_cast<IClassFactory *> (this);
- else
+ } else {
+ log_debug("QueryInterface with unknwon interface: '" GUID_FMT "'",
+ GUID_ARG(riid));
return E_NOINTERFACE;
+ }
reinterpret_cast<IUnknown *>(*ppv)->AddRef ();
return S_OK;
}
FlangeFactory *FlangeFactory::instance()
{
if (!s_factory) {
s_factory = new FlangeFactory();
}
return s_factory;
}
STDMETHODIMP_(ULONG) FlangeFactory::Release()
{
ULONG lCount = --m_lRef;
if (!lCount) {
delete this;
}
return lCount;
}
FlangeFactory::~FlangeFactory()
{
s_factory = nullptr;
}
STDAPI DllCanUnloadNow()
{
return s_factory == nullptr;
}
STDAPI DllUnregisterServer()
{
HKEY root_key;
if (W32::isElevated()) {
root_key = HKEY_LOCAL_MACHINE;
} else {
root_key = HKEY_CURRENT_USER;
}
log_debug("Un Registering shell extension.");
RegDeleteKeyA(root_key, "Software\\Classes\\.gpga");
RegDeleteKeyA(root_key, "Software\\Classes\\GPGArchive");
RegDeleteKeyA(root_key, "Software\\Classes\\CLSID\\{" MY_CLSID_STR "}");
}
STDAPI DllRegisterServer()
{
const char *root_key;
const auto gpg4windir = W32::getGpg4winDir();
init_logging ();
log_debug ("Debug");
if (gpg4windir.empty()) {
STRANGEPOINT;
return FALSE;
}
char module_path[MAX_PATH + 1];
if (!s_hinst || GetModuleFileNameA (s_hinst, module_path,
MAX_PATH) == MAX_PATH) {
STRANGEPOINT;
return FALSE;
}
if (W32::isElevated()) {
root_key = "HKEY_LOCAL_MACHINE";
} else {
root_key = "HKEY_CURRENT_USER";
}
log_debug("Registering shell extension.");
/* Tar file is: {2B3256E4-49AA-11D3-8229-0050AE509054} */
/* Register File extension */
if (!W32::writeRegStr(root_key, "Software\\Classes\\.gpga",
nullptr, MY_PROGID)) {
STRANGEPOINT;
return FALSE;
}
if (!W32::writeRegStr(root_key, "Software\\Classes\\GPGArchive",
nullptr, "GnuPG Archive Extension")) {
STRANGEPOINT;
return FALSE;
}
if (!W32::writeRegStr(root_key, "Software\\Classes\\GPGArchive",
"FriendlyTypeName", "GnuPG Archive")) {
STRANGEPOINT;
return FALSE;
}
if (!W32::writeRegStr(root_key, "Software\\Classes\\GPGArchive\\ShellEx",
nullptr, "")) {
STRANGEPOINT;
return FALSE;
}
if (!W32::writeRegStr(root_key, "Software\\Classes\\GPGArchive\\CLSID",
nullptr, "{" MY_CLSID_STR "}")) {
STRANGEPOINT;
return FALSE;
}
if (!W32::writeRegStr(root_key, "Software\\Classes\\GPGArchive\\CLSID",
nullptr, "{" MY_CLSID_STR "}")) {
STRANGEPOINT;
return FALSE;
}
if (!W32::writeRegStr(root_key, "Software\\Classes\\CLSID\\{" MY_CLSID_STR "}",
nullptr, "GnuPG Archive Extension")) {
STRANGEPOINT;
return FALSE;
}
std::string iconPath = gpg4windir + "\\share\\gpg4win\\file-ext.ico";
if (!W32::writeRegStr(root_key, "Software\\Classes\\CLSID\\{" MY_CLSID_STR "}",
"Default Icon", iconPath.c_str())) {
STRANGEPOINT;
return FALSE;
}
if (!W32::writeRegStr(root_key, "Software\\Classes\\CLSID\\{" MY_CLSID_STR "}\\InprocServer32",
nullptr, module_path)) {
STRANGEPOINT;
return FALSE;
}
if (!W32::writeRegStr(root_key, "Software\\Classes\\CLSID\\{" MY_CLSID_STR "}\\InprocServer32",
"ThreadingModel", "Apartment")) {
STRANGEPOINT;
return FALSE;
}
if (!W32::writeRegStr(root_key, "Software\\Classes\\CLSID\\{" MY_CLSID_STR "}\\ProgID",
nullptr, MY_PROGID)) {
STRANGEPOINT;
return FALSE;
}
if (!W32::writeRegStr(root_key, "Software\\Classes\\CLSID\\{" MY_CLSID_STR "}\\Implemented Categories\\"
"{00021490-0000-0000-C000-000000000046}",
nullptr, "Browsable Shell Extension")) {
STRANGEPOINT;
return FALSE;
}
/* See: https://msdn.microsoft.com/en-us/library/windows/desktop/cc144093(v=vs.85).aspx */
if (!W32::writeRegDword(root_key, "Software\\Classes\\CLSID\\{" MY_CLSID_STR "}\\ShellFolder",
"Attributes", SFGAO_FOLDER | SFGAO_CANRENAME | SFGAO_CANDELETE)) {
STRANGEPOINT;
return FALSE;
}
/* Notify the shell about the change. */
SHChangeNotify (SHCNE_ASSOCCHANGED, SHCNF_IDLIST, NULL, NULL);
}
STDAPI DllMain (HINSTANCE hinst, DWORD reason, LPVOID)
{
if (reason == DLL_PROCESS_ATTACH) {
s_hinst = hinst;
// Do init of GPGME
init_logging ();
} else if (reason == DLL_PROCESS_DETACH) {
log_debug ("Detached");
}
return TRUE;
}
diff --git a/src/gpga/gpgshellfolder.cpp b/src/gpga/gpgshellfolder.cpp
new file mode 100644
index 0000000..17caeb7
--- /dev/null
+++ b/src/gpga/gpgshellfolder.cpp
@@ -0,0 +1,146 @@
+/* Copyright (C) 2018 by Andre Heinecke <aheinecke@gnupg.com>
+ *
+ * This file is Free Software under the GNU GPL (v>=2)
+ * and comes with ABSOLUTELY NO WARRANTY!
+ * See LICENSE.txt for details.
+ */
+
+#include "gpgshellfolder.h"
+#include "debug.h"
+
+GpgShellFolder::~GpgShellFolder()
+{
+}
+
+STDMETHODIMP GpgShellFolder::QueryInterface (REFIID riid, void **ppv)
+{
+ if (!ppv) {
+ return E_POINTER;
+ }
+
+ *ppv = nullptr;
+
+ /* The static casts ensure that the virtual function table
+ layout of the returned object is correct. */
+ if (riid == IID_IUnknown) {
+ *ppv = static_cast<IUnknown *> (this);
+ } else if (riid == IID_IShellFolder) {
+ *ppv = static_cast<IShellFolder*> (this);
+ } else {
+ log_debug("QueryInterface with unknwon interface: '" GUID_FMT "'",
+ GUID_ARG(riid));
+ return E_NOINTERFACE;
+ }
+
+ reinterpret_cast<IUnknown *>(*ppv)->AddRef ();
+
+ return S_OK;
+}
+
+ULONG STDMETHODCALLTYPE GpgShellFolder::Release()
+{
+ ULONG lCount = --m_lRef;
+ if (!lCount) {
+ delete this;
+ }
+ return lCount;
+}
+
+HRESULT STDMETHODCALLTYPE GpgShellFolder::ParseDisplayName(HWND hwnd,
+ IBindCtx *pbc,
+ LPWSTR pszDisplayName,
+ ULONG *pchEaten,
+ PIDLIST_RELATIVE *ppidl,
+ ULONG *pdwAttributes)
+{
+ TRACEPOINT;
+ return S_OK;
+}
+
+
+HRESULT STDMETHODCALLTYPE GpgShellFolder::EnumObjects(HWND hwnd,
+ SHCONTF grfFlags,
+ IEnumIDList **ppenumIDList)
+{
+ TRACEPOINT;
+ return S_OK;
+}
+
+
+HRESULT STDMETHODCALLTYPE GpgShellFolder::BindToObject(PCUIDLIST_RELATIVE pidl,
+ IBindCtx *pbc,
+ REFIID riid,
+ void **ppv)
+{
+ TRACEPOINT;
+ return S_OK;
+}
+
+
+HRESULT STDMETHODCALLTYPE GpgShellFolder::BindToStorage(PCUIDLIST_RELATIVE pidl,
+ IBindCtx *pbc,
+ REFIID riid,
+ void **ppv)
+{
+ TRACEPOINT;
+ return S_OK;
+}
+
+
+HRESULT STDMETHODCALLTYPE GpgShellFolder::CompareIDs(LPARAM lParam,
+ PCUIDLIST_RELATIVE pidl1,
+ PCUIDLIST_RELATIVE pidl2)
+{
+ TRACEPOINT;
+ return S_OK;
+}
+
+
+HRESULT STDMETHODCALLTYPE GpgShellFolder::CreateViewObject(HWND hwndOwner,
+ REFIID riid,
+ void **ppv)
+{
+ TRACEPOINT;
+ return S_OK;
+}
+
+
+HRESULT STDMETHODCALLTYPE GpgShellFolder::GetAttributesOf(UINT cidl,
+ PCUITEMID_CHILD_ARRAY apidl,
+ SFGAOF *rgfInOut)
+{
+ TRACEPOINT;
+ return S_OK;
+}
+
+
+HRESULT STDMETHODCALLTYPE GpgShellFolder::GetUIObjectOf(HWND hwndOwner,
+ UINT cidl,
+ PCUITEMID_CHILD_ARRAY apidl,
+ REFIID riid,
+ UINT *rgfReserved,
+ void **ppv)
+{
+ TRACEPOINT;
+ return S_OK;
+}
+
+
+HRESULT STDMETHODCALLTYPE GpgShellFolder::GetDisplayNameOf(PCUITEMID_CHILD pidl,
+ SHGDNF uFlags,
+ STRRET *pName)
+{
+ TRACEPOINT;
+ return S_OK;
+}
+
+
+HRESULT STDMETHODCALLTYPE GpgShellFolder::SetNameOf(HWND hwnd,
+ PCUITEMID_CHILD pidl,
+ LPCWSTR pszName,
+ SHGDNF uFlags,
+ PITEMID_CHILD *ppidlOut)
+{
+ TRACEPOINT;
+ return S_OK;
+}
diff --git a/src/gpga/gpgshellfolder.h b/src/gpga/gpgshellfolder.h
new file mode 100644
index 0000000..4e3ad22
--- /dev/null
+++ b/src/gpga/gpgshellfolder.h
@@ -0,0 +1,77 @@
+#ifndef GPGSHELLFOLDER_H
+#define GPGSHELLFOLDER_H
+/* Copyright (C) 2018 by Andre Heinecke <aheinecke@gnupg.com>
+ *
+ * This file is Free Software under the GNU GPL (v>=2)
+ * and comes with ABSOLUTELY NO WARRANTY!
+ * See LICENSE.txt for details.
+ */
+#include <windows.h>
+#include <shlobj.h>
+
+class GpgShellFolder: public IShellFolder
+{
+public:
+ GpgShellFolder(): m_lRef(0) {}
+
+ virtual ~GpgShellFolder();
+
+ /* IUnknown */
+ STDMETHODIMP QueryInterface (REFIID riid, LPVOID* ppvObj);
+ STDMETHODIMP_(ULONG) AddRef() { ++m_lRef; return m_lRef; };
+ STDMETHODIMP_(ULONG) Release();
+
+ /* IShellFolder*/
+ HRESULT STDMETHODCALLTYPE ParseDisplayName(HWND hwnd,
+ IBindCtx *pbc,
+ LPWSTR pszDisplayName,
+ ULONG *pchEaten,
+ PIDLIST_RELATIVE *ppidl,
+ ULONG *pdwAttributes);
+
+ HRESULT STDMETHODCALLTYPE EnumObjects(HWND hwnd,
+ SHCONTF grfFlags,
+ IEnumIDList **ppenumIDList);
+
+ HRESULT STDMETHODCALLTYPE BindToObject(PCUIDLIST_RELATIVE pidl,
+ IBindCtx *pbc,
+ REFIID riid,
+ void **ppv);
+
+ HRESULT STDMETHODCALLTYPE BindToStorage(PCUIDLIST_RELATIVE pidl,
+ IBindCtx *pbc,
+ REFIID riid,
+ void **ppv);
+
+ HRESULT STDMETHODCALLTYPE CompareIDs(LPARAM lParam,
+ PCUIDLIST_RELATIVE pidl1,
+ PCUIDLIST_RELATIVE pidl2);
+
+ HRESULT STDMETHODCALLTYPE CreateViewObject(HWND hwndOwner,
+ REFIID riid,
+ void **ppv);
+
+ HRESULT STDMETHODCALLTYPE GetAttributesOf(UINT cidl,
+ PCUITEMID_CHILD_ARRAY apidl,
+ SFGAOF *rgfInOut);
+
+ HRESULT STDMETHODCALLTYPE GetUIObjectOf(HWND hwndOwner,
+ UINT cidl,
+ PCUITEMID_CHILD_ARRAY apidl,
+ REFIID riid,
+ UINT *rgfReserved,
+ void **ppv);
+
+ HRESULT STDMETHODCALLTYPE GetDisplayNameOf(PCUITEMID_CHILD pidl,
+ SHGDNF uFlags,
+ STRRET *pName);
+
+ HRESULT STDMETHODCALLTYPE SetNameOf(HWND hwnd,
+ PCUITEMID_CHILD pidl,
+ LPCWSTR pszName,
+ SHGDNF uFlags,
+ PITEMID_CHILD *ppidlOut);
+private:
+ ULONG m_lRef;
+};
+#endif // GPGSHELLFOLDER_H
diff --git a/src/util/debug.h b/src/util/debug.h
index e68fca4..5d6257a 100644
--- a/src/util/debug.h
+++ b/src/util/debug.h
@@ -1,29 +1,31 @@
#ifndef GPG4WIN_DEBUG_H
#define GPG4WIN_DEBUG_H
/* Copyright (C) 2018 by Andre Heinecke <aheinecke@gnupg.com>
*
* This file is Free Software under the GNU GPL (v>=2)
* and comes with ABSOLUTELY NO WARRANTY!
* See LICENSE.txt for details.
*/
#include <gpg-error.h>
const char *log_srcname (const char *s);
#define SRCNAME log_srcname (__FILE__)
#define log_debug(format, ...) \
gpgrt_log_debug("%s:%s: " format, SRCNAME, __func__, ##__VA_ARGS__)
#define STRANGEPOINT log_debug ("%s:%s:%d:UNEXPECTED", \
__LINE__);
+#define TRACEPOINT log_debug ("%s:%s:%d:TRACE");
+
#define GUID_FMT "{%08lX-%04hX-%04hX-%02hX%02hX-%02hX%02hX%02hX%02hX%02hX%02hX}"
#define GUID_ARG(x) (x).Data1, (x).Data2, (x).Data3, (x).Data4[0], \
(x).Data4[1], (x).Data4[2], (x).Data4[3], (x).Data4[4], \
(x).Data4[5], (x).Data4[6], (x).Data4[7]
#endif // GPG4WIN_DEBUG_H
File Metadata
Details
Attached
Mime Type
text/x-diff
Expires
Fri, Dec 5, 5:50 PM (1 d, 20 h)
Storage Engine
local-disk
Storage Format
Raw Data
Storage Handle
21/fa/9cbcbfc575901ffac6f42a10acd9
Attached To
rGTO Gpg4win-Tools
Event Timeline
Log In to Comment