[svn] GpgEX - r3 - in trunk: . src
svn author marcus
cvs at cvs.gnupg.org
Tue Aug 28 01:43:50 CEST 2007
Author: marcus
Date: 2007-08-28 01:43:19 +0200 (Tue, 28 Aug 2007)
New Revision: 3
Modified:
trunk/README
trunk/src/ChangeLog
trunk/src/Makefile.am
trunk/src/gpgex-class.cc
trunk/src/gpgex-factory.cc
trunk/src/gpgex.cc
trunk/src/gpgex.def
trunk/src/gpgex.h
trunk/src/main.cc
trunk/src/main.h
Log:
2007-08-28 Marcus Brinkmann <marcus at g10code.de>
* Makefile.am (gpgex_LDADD): Add -lole32.
* gpgex.def: Rename functions to not carry the @NR thingie.
* main.h: Many TRACE macros added.
(DEBUG_INIT, DEBUG_CONTEXT_MENU, STRINGIFY, GUID_FMT, GUID_ARG):
New macros.
(_gpgex_debug): New prototype.
* main.cc: Include <stdarg.h>, <stdio.h> and <shlobj.h>. Add
debugging traces.
(debug_lock, debug_flags, debug_file): New statics.
(get_debug_file, debug_init, debug_deinit): New static functions.
(_gpgex_debug): New function.
(DllMain): Call debug_init.
(DllRegisterServer, DllUnregisterServer): Call SHChangeNotify.
* gpgex.h: Include <vector> and <string>. Use std::vector and
std::string namespaces.
(class gpgex_t): New member filenames, and new method reset.
* gpgex.cc: Include <vector>, <string>, <stdexcept> and use
std::vector and std::string namespaces. Add debugging traces.
(gpgex_t::reset): New function.
(gpgex_t::Initialize): Implement dummy function.
(gpgex_t::QueryContextMenu): Implement dummy function.
(gpgex_t::GetCommandString): Implement dummy function.
(gpgex_t::InvokeCommand): Implement dummy function.
* gpgex-factory.cc: Add debugging traces.
* gpgex-class.cc (gpgex_class::init): Implement registration of
shell extension.
(gpgex_class::deinit): Implement corresponding unregistration.
Modified: trunk/README
===================================================================
--- trunk/README 2007-08-23 10:43:51 UTC (rev 2)
+++ trunk/README 2007-08-27 23:43:19 UTC (rev 3)
@@ -4,4 +4,25 @@
This package contains GpgEX, the GNU Privacy Guard extensions for the
Windows Explorer shell.
-FIXME: Add more info.
+Debugging
+=========
+
+A debug file path can be specified with the registry value "GpgEX
+Debug File" in the HKLM\Software\GNU\GnuPG key. To this file logging
+information is appended. Also see:
+
+http://msdn2.microsoft.com/en-us/library/aa969286.aspx
+
+
+BUGS
+====
+
+* DllRegisterServer does not correctly figure out the DLL path name
+ (it catches regsvr32.exe instead). Thus the DLL path is hard coded
+ to "C:\\gpgex.dll" for now. You can change it in the registry by
+ locating
+ "HKCR\CLSID\{CCD955E4-5C16-4A33-AFDA-A8947A94946B}\InprocServer32"
+ and changing the default value of that key.
+
+* DllMain is not invoked for some reason, so i18n is not initialized
+ and debugging output is done inefficiently.
Modified: trunk/src/ChangeLog
===================================================================
--- trunk/src/ChangeLog 2007-08-23 10:43:51 UTC (rev 2)
+++ trunk/src/ChangeLog 2007-08-27 23:43:19 UTC (rev 3)
@@ -1,3 +1,33 @@
+2007-08-28 Marcus Brinkmann <marcus at g10code.de>
+
+ * Makefile.am (gpgex_LDADD): Add -lole32.
+ * gpgex.def: Rename functions to not carry the @NR thingie.
+ * main.h: Many TRACE macros added.
+ (DEBUG_INIT, DEBUG_CONTEXT_MENU, STRINGIFY, GUID_FMT, GUID_ARG):
+ New macros.
+ (_gpgex_debug): New prototype.
+ * main.cc: Include <stdarg.h>, <stdio.h> and <shlobj.h>. Add
+ debugging traces.
+ (debug_lock, debug_flags, debug_file): New statics.
+ (get_debug_file, debug_init, debug_deinit): New static functions.
+ (_gpgex_debug): New function.
+ (DllMain): Call debug_init.
+ (DllRegisterServer, DllUnregisterServer): Call SHChangeNotify.
+ * gpgex.h: Include <vector> and <string>. Use std::vector and
+ std::string namespaces.
+ (class gpgex_t): New member filenames, and new method reset.
+ * gpgex.cc: Include <vector>, <string>, <stdexcept> and use
+ std::vector and std::string namespaces. Add debugging traces.
+ (gpgex_t::reset): New function.
+ (gpgex_t::Initialize): Implement dummy function.
+ (gpgex_t::QueryContextMenu): Implement dummy function.
+ (gpgex_t::GetCommandString): Implement dummy function.
+ (gpgex_t::InvokeCommand): Implement dummy function.
+ * gpgex-factory.cc: Add debugging traces.
+ * gpgex-class.cc (gpgex_class::init): Implement registration of
+ shell extension.
+ (gpgex_class::deinit): Implement corresponding unregistration.
+
2007-08-23 Marcus Brinkmann <marcus at g10code.de>
* Initial commit.
Modified: trunk/src/Makefile.am
===================================================================
--- trunk/src/Makefile.am 2007-08-23 10:43:51 UTC (rev 2)
+++ trunk/src/Makefile.am 2007-08-27 23:43:19 UTC (rev 3)
@@ -29,8 +29,8 @@
#gpgex_LDADD = $(srcdir)/gpgex.def \
# -L . -lshell32 -lgdi32 -lcomdlg32 \
-# -lole32 -loleaut32 -lws2_32 -ladvapi32
-gpgex_LDADD = $(srcdir)/gpgex.def -L . -lshell32 -lws2_32 -luuid
+# -loleaut32 -lws2_32 -ladvapi32
+gpgex_LDADD = $(srcdir)/gpgex.def -L . -lshell32 -lws2_32 -lole32 -luuid
resource.o: versioninfo.rc
Modified: trunk/src/gpgex-class.cc
===================================================================
--- trunk/src/gpgex-class.cc 2007-08-23 10:43:51 UTC (rev 2)
+++ trunk/src/gpgex-class.cc 2007-08-27 23:43:19 UTC (rev 3)
@@ -50,9 +50,9 @@
/* FIXME: Error handling? */
+ /* Set a key for our CLSID. */
strcpy (key, "CLSID\\{" CLSID_GPGEX_STR "}");
RegCreateKey (HKEY_CLASSES_ROOT, key, &key_handle);
-
/* The default value is a human readable name for the class. */
strcpy (value, "GpgEX");
RegSetValueEx (key_handle, 0, 0, REG_SZ, (BYTE *) value, strlen (value) + 1);
@@ -61,13 +61,37 @@
/* The InprocServer32 key holds the path to the server component. */
strcpy (key, "CLSID\\{" CLSID_GPGEX_STR "}\\InprocServer32");
RegCreateKey (HKEY_CLASSES_ROOT, key, &key_handle);
-
+ /* FIXME: We get regsvr32.exe here instead gpgex.dll. */
+#if 0
result = GetModuleFileName (gpgex_server::instance, value, MAX_PATH);
+#endif
+ strcpy (value, "C:\\gpgex.dll");
RegSetValueEx (key_handle, 0, 0, REG_SZ, (BYTE *) value, strlen (value) + 1);
+ /* We also need a threading model. */
+ strcpy (key, "ThreadingModel");
+ strcpy (value, "Apartment");
+ RegSetValueEx (key_handle, key, 0, REG_SZ,
+ (BYTE *) value, strlen (value) + 1);
RegCloseKey (key_handle);
- /* FIXME: Now add the required registry keys for the context menu
- triggers. */
+ strcpy (key, "*\\ShellEx\\ContextMenuHandlers\\GpgEX");
+ RegCreateKey (HKEY_CLASSES_ROOT, key, &key_handle);
+ /* The default value is the CLSID for the class. */
+ strcpy (value, "{" CLSID_GPGEX_STR "}");
+ RegSetValueEx (key_handle, 0, 0, REG_SZ, (BYTE *) value, strlen (value) + 1);
+ RegCloseKey (key_handle);
+
+#if 0
+ /* We also have to approve the shell extension for Windows NT. */
+ strcpy (key, "Software\\Microsoft\\Windows\\CurrentVersion\\Shell Extensions\\Approved");
+ RegCreateKey (HKEY_LOCAL_MACHINE, key, &key_handle);
+ /* The key is the CLSID, the value can be anything. */
+ strcpy (key, "{" CLSID_GPGEX_STR "}");
+ strcpy (value, "GpgEX");
+ RegSetValueEx (key_handle, key, 0, REG_SZ,
+ (BYTE *) value, strlen (value) + 1);
+ RegCloseKey (key_handle);
+#endif
}
@@ -77,9 +101,15 @@
{
/* FIXME: Error handling? */
- /* FIXME: Unregister the required registry keys for the context menu
- triggers. */
+#if 0
+ RegDeleteValue (HKEY_LOCAL_MACHINE,
+ "Software\\Microsoft\\Windows\\CurrentVersion"
+ "\\Shell Extensions\\Approved", "{" CLSID_GPGEX_STR "}");
+#endif
+ RegDeleteKey (HKEY_CLASSES_ROOT,
+ "*\\ShellEx\\ContextMenuHandlers\\GpgEX");
+
/* Delete registry keys in reverse order. */
RegDeleteKey (HKEY_CLASSES_ROOT,
"CLSID\\{" CLSID_GPGEX_STR "}\\InprocServer32");
Modified: trunk/src/gpgex-factory.cc
===================================================================
--- trunk/src/gpgex-factory.cc 2007-08-23 10:43:51 UTC (rev 2)
+++ trunk/src/gpgex-factory.cc 2007-08-27 23:43:19 UTC (rev 3)
@@ -35,8 +35,12 @@
STDMETHODIMP
gpgex_factory_t::QueryInterface (REFIID riid, void **ppv)
{
+#define _TRACE_BEG12(a,b,c,d,e,f) TRACE_BEG12 (a,b,c,d,e,f)
+ _TRACE_BEG12 (DEBUG_INIT, "gpgex_factory_t::QueryInterface", this,
+ "riid=" GUID_FMT ", ppv=%p", GUID_ARG (riid), ppv);
+
if (ppv == NULL)
- return E_INVALIDARG;
+ return TRACE_RES (E_INVALIDARG);
/* Be nice to broken software. */
*ppv = NULL;
@@ -48,20 +52,22 @@
else if (riid == IID_IClassFactory)
*ppv = static_cast<IClassFactory *> (this);
else
- return E_NOINTERFACE;
+ return TRACE_RES (E_NOINTERFACE);
/* We have to acquire a reference to the returned object. We lost
the type information, but we know that all object classes inherit
from IUnknown, which is good enough. */
reinterpret_cast<IUnknown *>(*ppv)->AddRef ();
- return S_OK;
+ return TRACE_RES (S_OK);
}
STDMETHODIMP_(ULONG)
gpgex_factory_t::AddRef (void)
{
+ (void) TRACE (DEBUG_INIT, "gpgex_factory_t::AddRef", this);
+
/* This factory is a singleton and therefore no reference counting
is needed. */
return 1;
@@ -71,6 +77,8 @@
STDMETHODIMP_(ULONG)
gpgex_factory_t::Release (void)
{
+ (void) TRACE (DEBUG_INIT, "gpgex_factory_t::Release", this);
+
/* This factory is a singleton and therefore no reference counting
is needed. */
return 1;
@@ -85,28 +93,36 @@
{
HRESULT result;
+#define _TRACE_BEG13(a,b,c,d,e,f,g) TRACE_BEG13 (a,b,c,d,e,f,g)
+ _TRACE_BEG13 (DEBUG_INIT, "gpgex_factory_t::CreateInstance", this,
+ "punkOuter=%lu, riid=" GUID_FMT ", ppv=%p",
+ punkOuter, GUID_ARG (riid), ppv);
+
/* Be nice to broken software. */
*ppv = NULL;
/* Aggregation is not supported. */
if (punkOuter)
- return CLASS_E_NOAGGREGATION;
+ return TRACE_RES (CLASS_E_NOAGGREGATION);
gpgex_t *gpgex = new gpgex_t;
if (!gpgex)
- return E_OUTOFMEMORY;
+ return TRACE_RES (E_OUTOFMEMORY);
result = gpgex->QueryInterface (riid, ppv);
if (FAILED (result))
delete gpgex;
- return result;
+ return TRACE_RES (result);
}
STDMETHODIMP
gpgex_factory_t::LockServer (BOOL fLock)
{
+ (void) TRACE1 (DEBUG_INIT, "gpgex_factory_t::LockServer", this,
+ "fLock=%s", fLock ? "true" : "false");
+
/* Locking the singleton gpgex factory object acquires a reference
for the server component. */
if (fLock)
Modified: trunk/src/gpgex.cc
===================================================================
--- trunk/src/gpgex.cc 2007-08-23 10:43:51 UTC (rev 2)
+++ trunk/src/gpgex.cc 2007-08-27 23:43:19 UTC (rev 3)
@@ -22,6 +22,13 @@
#include <config.h>
#endif
+#include <vector>
+#include <string>
+#include <stdexcept>
+
+using std::vector;
+using std::string;
+
#include <windows.h>
#include "main.h"
@@ -29,11 +36,23 @@
#include "gpgex.h"
+/* Reset the instance between operations. */
+void
+gpgex_t::reset (void)
+{
+ this->filenames.clear ();
+}
+
+
STDMETHODIMP
gpgex_t::QueryInterface (REFIID riid, void **ppv)
{
+#define _TRACE_BEG12(a,b,c,d,e,f) TRACE_BEG12(a,b,c,d,e,f)
+ _TRACE_BEG12 (DEBUG_INIT, "gpgex_t::QueryInterface", this,
+ "riid=" GUID_FMT ", ppv=%p", GUID_ARG (riid), ppv);
+
if (ppv == NULL)
- return E_INVALIDARG;
+ return TRACE_RES (E_INVALIDARG);
/* Be nice to broken software. */
*ppv = NULL;
@@ -57,20 +76,23 @@
*ppv = static_cast<IContextMenu3 *> (this);
#endif
else
- return E_NOINTERFACE;
+ return TRACE_RES (E_NOINTERFACE);
/* We have to acquire a reference to the returned object. We lost
the type information, but we know that all object classes inherit
from IUnknown, which is good enough. */
reinterpret_cast<IUnknown *>(*ppv)->AddRef ();
- return S_OK;
+ return TRACE_RES (S_OK);
}
STDMETHODIMP_(ULONG)
gpgex_t::AddRef (void)
{
+ (void) TRACE1 (DEBUG_INIT, "gpgex_t::AddRef", this,
+ "new_refcount=%i", this->refcount + 1);
+
return InterlockedIncrement (&this->refcount);
}
@@ -80,6 +102,9 @@
{
LONG count;
+ (void) TRACE1 (DEBUG_INIT, "gpgex_t::Release", this,
+ "new_refcount=%i", this->refcount - 1);
+
count = InterlockedDecrement (&this->refcount);
if (count == 0)
delete this;
@@ -94,36 +119,181 @@
gpgex_t::Initialize (LPCITEMIDLIST pIDFolder, IDataObject *pDataObj,
HKEY hRegKey)
{
- /* FIXME */
- return S_OK;
+ HRESULT err = S_OK;
+
+ TRACE_BEG3 (DEBUG_INIT, "gpgex_t::Initialize", this,
+ "pIDFolder=%p, pDataObj=%p, hRegKey=%p",
+ pIDFolder, pDataObj, hRegKey);
+
+ /* This function is called for the Shortcut (context menu),
+ Drag-and-Drop, and Property Sheet extensions. */
+
+ this->reset ();
+
+ try
+ {
+ if (pDataObj)
+ {
+ /* The data object contains a drop item which we extract. */
+ FORMATETC fe = { CF_HDROP, NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL};
+ STGMEDIUM medium;
+ UINT count;
+
+ if (SUCCEEDED (pDataObj->GetData (&fe, &medium)))
+ {
+ HDROP drop = (HDROP) GlobalLock (medium.hGlobal);
+ unsigned int i;
+
+ /* Now that we have the drop item, we can extract the
+ file names. */
+ count = DragQueryFile (drop, (UINT) -1, NULL, 0);
+ if (count == 0)
+ throw std::invalid_argument ("no filenames");
+
+ try
+ {
+ for (i = 0; i < count; i++)
+ {
+ char filename[MAX_PATH];
+ UINT len;
+ len = DragQueryFile (drop, i,
+ filename, sizeof (filename) - 1);
+ if (len == 0)
+ throw std::invalid_argument ("zero-length filename");
+
+ this->filenames.push_back (filename);
+ }
+ }
+ catch (...)
+ {
+ GlobalUnlock (medium.hGlobal);
+ ReleaseStgMedium (&medium);
+ throw;
+ }
+
+ GlobalUnlock (medium.hGlobal);
+ ReleaseStgMedium (&medium);
+ }
+ }
+ }
+ catch (std::bad_alloc)
+ {
+ err = E_OUTOFMEMORY;
+ }
+ catch (std::invalid_argument &e)
+ {
+ (VOID) TRACE_LOG1 ("exception: E_INVALIDARG: %s", e.what ());
+ err = E_INVALIDARG;
+ }
+ catch (...)
+ {
+ err = E_UNEXPECTED;
+ }
+
+ if (err != S_OK)
+ this->reset ();
+
+ return TRACE_RES (err);
}
/* IContextMenu methods. */
+/* The argument HMENU contains the context menu, and INDEXMENU points
+ to the first index where we can add items. IDCMDFIRST and
+ IDCMDLAST is the range of command ID values which we can use. */
STDMETHODIMP
gpgex_t::QueryContextMenu (HMENU hMenu, UINT indexMenu, UINT idCmdFirst,
UINT idCmdLast, UINT uFlags)
{
- /* FIXME */
- return S_OK;
+ UINT next_cmd = idCmdFirst;
+
+ TRACE_BEG5 (DEBUG_CONTEXT_MENU, "gpgex_t::QueryContextMenu", this,
+ "hMenu=%p, indexMenu=%u, idCmdFirst=%u, idCmdLast=%u, uFlags=%x",
+ hMenu, indexMenu, idCmdFirst, idCmdLast, uFlags);
+
+ /* If the flags include CMF_DEFAULTONLY then nothing should be done. */
+ if (! (uFlags & CMF_DEFAULTONLY))
+ {
+ BOOL res;
+
+ res = InsertMenu (hMenu, indexMenu, MF_BYPOSITION,
+ next_cmd++, _("GpgEX Test Item"));
+ if (! res)
+ return TRACE_RES (HRESULT_FROM_WIN32 (GetLastError ()));
+ }
+
+ /* We should return a HRESULT that indicates success and the offset
+ to the next free command ID after the last one we used, relative
+ to idCmdFirst. In other words: max_used - idCmdFirst + 1. */
+ return TRACE_RES (MAKE_HRESULT (SEVERITY_SUCCESS, FACILITY_NULL,
+ next_cmd - idCmdFirst));
}
+/* Get a verb or help text for the command IDCOMMAND (which is the
+ offset to IDCMDFIRST of QueryContextMenu, ie zero based). UFLAGS
+ has GCS_HELPTEXT set if the help-text is requested (otherwise a
+ verb is requested). If UFLAGS has the GCS_UNICODE bit set, we need
+ to return a wide character string. */
+
STDMETHODIMP
gpgex_t::GetCommandString (UINT idCommand, UINT uFlags, LPUINT lpReserved,
LPSTR pszName, UINT uMaxNameLen)
{
- /* FIXME */
- return S_OK;
+ TRACE_BEG5 (DEBUG_CONTEXT_MENU, "gpgex_t::GetCommandString", this,
+ "idCommand=%u, uFlags=%x, lpReserved=%lu, pszName=%p, "
+ "uMaxNameLen=%u",
+ idCommand, uFlags, lpReserved, pszName, uMaxNameLen);
+
+ if (idCommand != 0)
+ return TRACE_RES (E_INVALIDARG);
+
+ if (! (uFlags & GCS_HELPTEXT))
+ return TRACE_RES (E_INVALIDARG);
+
+ if (uFlags & GCS_UNICODE)
+ lstrcpynW ((LPWSTR) pszName, L"GpgEX help string (unicode)", uMaxNameLen);
+ else
+ lstrcpynA (pszName, "GpgEX help string (ASCII)", uMaxNameLen);
+
+ return TRACE_RES (S_OK);
}
STDMETHODIMP
gpgex_t::InvokeCommand (LPCMINVOKECOMMANDINFO lpcmi)
{
- /* FIXME */
- return S_OK;
+ TRACE_BEG1 (DEBUG_CONTEXT_MENU, "gpgex_t::GetCommandString", this,
+ "lpcmi=%p", lpcmi);
+
+ /* If lpVerb really points to a string, ignore this function call
+ and bail out. */
+ if (HIWORD (lpcmi->lpVerb) != 0)
+ return TRACE_RES (E_INVALIDARG);
+
+ /* Get the command index, which is the offset to IDCMDFIRST of
+ QueryContextMenu, ie zero based). */
+ switch (LOWORD (lpcmi->lpVerb))
+ {
+ case 0:
+ {
+ string msg;
+ unsigned int i;
+
+ msg = "The selected files were:\n\n";
+ for (i = 0; i < this->filenames.size (); i++)
+ msg = msg + this->filenames[i] + '\n';
+
+ MessageBox (lpcmi->hwnd, msg.c_str (), "GpgEX", MB_ICONINFORMATION);
+ }
+ break;
+
+ default:
+ return TRACE_RES (E_INVALIDARG);
+ }
+
+ return TRACE_RES (S_OK);
}
Modified: trunk/src/gpgex.def
===================================================================
--- trunk/src/gpgex.def 2007-08-23 10:43:51 UTC (rev 2)
+++ trunk/src/gpgex.def 2007-08-27 23:43:19 UTC (rev 3)
@@ -2,8 +2,8 @@
DESCRIPTION 'GpgEX - GPG Shell Extensions'
EXPORTS
- DllMain at 12 @1 PRIVATE
- DllCanUnloadNow at 0 @2 PRIVATE
- DllGetClassObject at 12 @3 PRIVATE
- DllRegisterServer at 0 @4 PRIVATE
- DllUnregisterServer at 0 @5 PRIVATE
+ DllMain = DllMain at 12 @1 PRIVATE
+ DllRegisterServer = DllRegisterServer at 0 @2 PRIVATE
+ DllUnregisterServer = DllUnregisterServer at 0 @3 PRIVATE
+ DllCanUnloadNow = DllCanUnloadNow at 0 @4 PRIVATE
+ DllGetClassObject = DllGetClassObject at 12 @5 PRIVATE
Modified: trunk/src/gpgex.h
===================================================================
--- trunk/src/gpgex.h 2007-08-23 10:43:51 UTC (rev 2)
+++ trunk/src/gpgex.h 2007-08-27 23:43:19 UTC (rev 3)
@@ -21,6 +21,12 @@
#ifndef GPGEX_H
#define GPGEX_H
+#include <vector>
+#include <string>
+
+using std::vector;
+using std::string;
+
#include <windows.h>
#include <shlobj.h>
@@ -74,6 +80,9 @@
/* Per-object reference count. */
LONG refcount;
+ /* Support for IShellExtInit. */
+ vector<string> filenames;
+
/* Support for the context menu. */
public:
@@ -90,6 +99,9 @@
gpgex_server::release ();
}
+ /* Reset the instance between operations. */
+ void reset (void);
+
public:
/* IUnknown methods. */
STDMETHODIMP QueryInterface (REFIID riid, void **ppv);
Modified: trunk/src/main.cc
===================================================================
--- trunk/src/main.cc 2007-08-23 10:43:51 UTC (rev 2)
+++ trunk/src/main.cc 2007-08-27 23:43:19 UTC (rev 3)
@@ -21,7 +21,10 @@
#include <config.h>
#endif
+#include <stdarg.h>
+#include <stdio.h>
#include <windows.h>
+#include <shlobj.h>
#include "registry.h"
#include "gpgex-class.h"
@@ -104,22 +107,120 @@
textdomain (PACKAGE_GT);
}
+
+static CRITICAL_SECTION debug_lock;
+/* No flags on means no debugging. */
+static unsigned int debug_flags = 0;
+
+static FILE *debug_file;
+
+
+/* Get the filename of the debug file, if any. */
+static char *
+get_debug_file (void)
+{
+ return read_w32_registry_string ("HKEY_LOCAL_MACHINE", REGKEY,
+ "GpgEX Debug File");
+}
+
+
+static void
+debug_init (void)
+{
+ char *filename;
+
+ /* FIXME: Sanity check due to DllMain not running. */
+ if (debug_file)
+ return;
+
+ InitializeCriticalSection (&debug_lock);
+
+ filename = get_debug_file ();
+ if (!filename)
+ return;
+
+ debug_file = fopen (filename, "a");
+ if (!debug_file)
+ return;
+
+ /* FIXME: Make this configurable eventually. */
+ debug_flags = DEBUG_INIT | DEBUG_CONTEXT_MENU;
+}
+
+
+static void
+debug_deinit (void)
+{
+ if (debug_file)
+ fclose (debug_file);
+}
+
+
+/* Log the formatted string FORMAT at debug level LEVEL or higher. */
+void
+_gpgex_debug (unsigned int flags, const char *format, ...)
+{
+ va_list arg_ptr;
+ int saved_errno;
+
+ saved_errno = errno;
+
+#if 1
+ /* FIXME: WTF. */
+ debug_init ();
+#endif
+
+ if (! (debug_flags & flags))
+ return;
+
+ va_start (arg_ptr, format);
+ EnterCriticalSection (&debug_lock);
+ vfprintf (debug_file, format, arg_ptr);
+ va_end (arg_ptr);
+ if (format && *format && format[strlen (format) - 1] != '\n')
+ putc ('\n', debug_file);
+ LeaveCriticalSection (&debug_lock);
+ fflush (debug_file);
+
+#if 1
+ /* FIXME */
+ fclose (debug_file);
+ debug_file = NULL;
+#endif
+
+ errno = saved_errno;
+}
+
+
/* Entry point called by DLL loader. */
int WINAPI
DllMain (HINSTANCE hinst, DWORD reason, LPVOID reserved)
{
+ /* FIXME: It seems this is never called!!! */
+#if 0
+ TRACE2 (DEBUG_INIT, "DllMain", hinst,
+ "reason=%i, reserved=%p", reason, reserved);
+#endif
+
if (reason == DLL_PROCESS_ATTACH)
{
gpgex_server::instance = hinst;
- /* FIXME: Initialize subsystems. */
-
/* Early initializations of our subsystems. */
i18n_init ();
+
+ debug_init ();
+
+ (void) TRACE0 (DEBUG_INIT, "DllMain", hinst,
+ "reason=DLL_PROCESS_ATTACH");
}
else if (reason == DLL_PROCESS_DETACH)
{
+ (void) TRACE0 (DEBUG_INIT, "DllMain", hinst,
+ "reason=DLL_PROCESS_DETACH");
+
+ debug_deinit ();
}
return TRUE;
@@ -133,6 +234,7 @@
STDAPI
DllCanUnloadNow (void)
{
+ (void) TRACE (DEBUG_INIT, "DllCanUnloadNow", gpgex_server::refcount);
return (gpgex_server::refcount == 0 ? S_OK : S_FALSE);
}
@@ -143,8 +245,15 @@
STDAPI
DllRegisterServer (void)
{
+ /* FIXME: This is wrong!!! The module path will point to
+ regsvr32.exe. */
+ gpgex_server::instance = GetModuleHandle (NULL);
+
gpgex_class::init ();
+ /* Notify the shell about the change. */
+ SHChangeNotify (SHCNE_ASSOCCHANGED, SHCNF_IDLIST, NULL, NULL);
+
return S_OK;
}
@@ -155,6 +264,9 @@
{
gpgex_class::deinit ();
+ /* Notify the shell about the change. */
+ SHChangeNotify (SHCNE_ASSOCCHANGED, SHCNF_IDLIST, NULL, NULL);
+
return S_OK;
}
@@ -166,12 +278,20 @@
STDAPI
DllGetClassObject (REFCLSID rclsid, REFIID riid, LPVOID *ppv)
{
+ /* We have to evaluate the arguments first. */
+#define _TRACE_BEG22(a,b,c,d,e,f) TRACE_BEG22(a,b,c,d,e,f)
+ _TRACE_BEG22 (DEBUG_INIT, "DllGetClassObject", ppv,
+ "rclsid=" GUID_FMT ", riid=" GUID_FMT,
+ GUID_ARG (rclsid), GUID_ARG (riid));
+
if (rclsid == CLSID_gpgex)
- return gpgex_factory.QueryInterface (riid, ppv);
+ {
+ HRESULT err = gpgex_factory.QueryInterface (riid, ppv);
+ return TRACE_RES (err);
+ }
/* Be nice to broken software. */
*ppv = NULL;
- return CLASS_E_CLASSNOTAVAILABLE;
- return 0;
+ return TRACE_RES (CLASS_E_CLASSNOTAVAILABLE);
}
Modified: trunk/src/main.h
===================================================================
--- trunk/src/main.h 2007-08-23 10:43:51 UTC (rev 2)
+++ trunk/src/main.h 2007-08-27 23:43:19 UTC (rev 3)
@@ -60,4 +60,162 @@
}
};
+
+#define DEBUG_INIT 1
+#define DEBUG_CONTEXT_MENU 2
+
+#define STRINGIFY(v) #v
+
+#define GUID_FMT "{%08lX-%04hX-%04hX-%02hhX%02hhX-%02hhX%02hhX%02hhX%02hhX%02hhX%02hhX}"
+#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]
+
+/* Log the formatted string FORMAT in categories FLAGS. */
+void _gpgex_debug (unsigned int flags, const char *format, ...);
+
+#define _TRACE(lvl, name, tag) \
+ int _gpgex_trace_level = lvl; \
+ const char *const _gpgex_trace_func = name; \
+ const char *const _gpgex_trace_tagname = STRINGIFY (tag); \
+ void *_gpgex_trace_tag = (void *) tag
+
+#define TRACE_BEG(lvl, name, tag) \
+ _TRACE (lvl, name, tag); \
+ _gpgex_debug (_gpgex_trace_level, "%s (%s=0x%x): enter\n", \
+ _gpgex_trace_func, _gpgex_trace_tagname, \
+ _gpgex_trace_tag)
+#define TRACE_BEG0(lvl, name, tag, fmt) \
+ _TRACE (lvl, name, tag); \
+ _gpgex_debug (_gpgex_trace_level, "%s (%s=0x%x): enter: " fmt "\n", \
+ _gpgex_trace_func, _gpgex_trace_tagname, \
+ _gpgex_trace_tag)
+#define TRACE_BEG1(lvl, name, tag, fmt, arg1) \
+ _TRACE (lvl, name, tag); \
+ _gpgex_debug (_gpgex_trace_level, "%s (%s=0x%x): enter: " fmt "\n", \
+ _gpgex_trace_func, _gpgex_trace_tagname, \
+ _gpgex_trace_tag, arg1)
+#define TRACE_BEG2(lvl, name, tag, fmt, arg1, arg2) \
+ _TRACE (lvl, name, tag); \
+ _gpgex_debug (_gpgex_trace_level, "%s (%s=0x%x): enter: " fmt "\n", \
+ _gpgex_trace_func, _gpgex_trace_tagname, \
+ _gpgex_trace_tag, arg1, arg2)
+#define TRACE_BEG3(lvl, name, tag, fmt, arg1, arg2, arg3) \
+ _TRACE (lvl, name, tag); \
+ _gpgex_debug (_gpgex_trace_level, "%s (%s=0x%x): enter: " fmt "\n", \
+ _gpgex_trace_func, _gpgex_trace_tagname, \
+ _gpgex_trace_tag, arg1, arg2, arg3)
+#define TRACE_BEG4(lvl, name, tag, fmt, arg1, arg2, arg3, arg4) \
+ _TRACE (lvl, name, tag); \
+ _gpgex_debug (_gpgex_trace_level, "%s (%s=0x%x): enter: " fmt "\n", \
+ _gpgex_trace_func, _gpgex_trace_tagname, \
+ _gpgex_trace_tag, arg1, arg2, arg3, arg4)
+#define TRACE_BEG5(lvl, name, tag, fmt, arg1, arg2, arg3, arg4, arg5) \
+ _TRACE (lvl, name, tag); \
+ _gpgex_debug (_gpgex_trace_level, "%s (%s=0x%x): enter: " fmt "\n", \
+ _gpgex_trace_func, _gpgex_trace_tagname, \
+ _gpgex_trace_tag, arg1, arg2, arg3, arg4, arg5)
+#define TRACE_BEG12(lvl, name, tag, fmt, arg1, arg2, arg3, arg4, \
+ arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12) \
+ _TRACE (lvl, name, tag); \
+ _gpgex_debug (_gpgex_trace_level, "%s (%s=0x%x): enter: " fmt "\n", \
+ _gpgex_trace_func, _gpgex_trace_tagname, \
+ _gpgex_trace_tag, arg1, arg2, arg3, arg4, arg5, arg6, \
+ arg7, arg8, arg9, arg10, arg11, arg12)
+#define TRACE_BEG13(lvl, name, tag, fmt, arg1, arg2, arg3, arg4, \
+ arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, \
+ arg13) \
+ _TRACE (lvl, name, tag); \
+ _gpgex_debug (_gpgex_trace_level, "%s (%s=0x%x): enter: " fmt "\n", \
+ _gpgex_trace_func, _gpgex_trace_tagname, \
+ _gpgex_trace_tag, arg1, arg2, arg3, arg4, arg5, arg6, \
+ arg7, arg8, arg9, arg10, arg11, arg12, arg13)
+#define TRACE_BEG22(lvl, name, tag, fmt, arg1, arg2, arg3, arg4, \
+ arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, \
+ arg13, arg14, arg15, arg16, arg17, arg18, arg19, \
+ arg20, arg21, arg22) \
+ _TRACE (lvl, name, tag); \
+ _gpgex_debug (_gpgex_trace_level, "%s (%s=0x%x): enter: " fmt "\n", \
+ _gpgex_trace_func, _gpgex_trace_tagname, \
+ _gpgex_trace_tag, arg1, arg2, arg3, arg4, arg5, arg6, \
+ arg7, arg8, arg9, arg10, arg11, arg12, arg13, arg14, \
+ arg15, arg16, arg17, arg18, arg19, arg20, arg21, \
+ arg22)
+
+#define TRACE(lvl, name, tag) \
+ (_gpgex_debug (lvl, "%s (%s=0x%x): call\n", \
+ name, STRINGIFY (tag), (void *) tag), 0)
+#define TRACE0(lvl, name, tag, fmt) \
+ (_gpgex_debug (lvl, "%s (%s=0x%x): call: " fmt "\n", \
+ name, STRINGIFY (tag), (void *) tag), 0)
+#define TRACE1(lvl, name, tag, fmt, arg1) \
+ (_gpgex_debug (lvl, "%s (%s=0x%x): call: " fmt "\n", \
+ name, STRINGIFY (tag), (void *) tag, arg1), 0)
+#define TRACE2(lvl, name, tag, fmt, arg1, arg2) \
+ (_gpgex_debug (lvl, "%s (%s=0x%x): call: " fmt "\n", \
+ name, STRINGIFY (tag), (void *) tag, arg1, arg2), 0)
+#define TRACE3(lvl, name, tag, fmt, arg1, arg2, arg3) \
+ (_gpgex_debug (lvl, "%s (%s=0x%x): call: " fmt "\n", \
+ name, STRINGIFY (tag), (void *) tag, arg1, arg2, \
+ arg3), 0)
+#define TRACE6(lvl, name, tag, fmt, arg1, arg2, arg3, arg4, arg5, arg6) \
+ (_gpgex_debug (lvl, "%s (%s=0x%x): call: " fmt "\n", \
+ name, STRINGIFY (tag), (void *) tag, arg1, arg2, arg3, \
+ arg4, arg5, arg6), 0)
+
+#define TRACE_RES(err) \
+ err == S_OK ? (TRACE_SUC ()) : \
+ (_gpgex_debug (_gpgex_trace_level, "%s (%s=0x%x): %s: ec=%x\n", \
+ _gpgex_trace_func, _gpgex_trace_tagname, \
+ _gpgex_trace_tag, \
+ SUCCEEDED (err) ? "leave" : "error", \
+ err), (err))
+
+#define TRACE_SUC() \
+ (_gpgex_debug (_gpgex_trace_level, "%s (%s=0x%x): leave\n", \
+ _gpgex_trace_func, _gpgex_trace_tagname, \
+ _gpgex_trace_tag), 0)
+#define TRACE_SUC0(fmt) \
+ (_gpgex_debug (_gpgex_trace_level, "%s (%s=0x%x): leave: " fmt "\n", \
+ _gpgex_trace_func, _gpgex_trace_tagname, \
+ _gpgex_trace_tag), 0)
+#define TRACE_SUC1(fmt, arg1) \
+ (_gpgex_debug (_gpgex_trace_level, "%s (%s=0x%x): leave: " fmt "\n", \
+ _gpgex_trace_func, _gpgex_trace_tagname, \
+ _gpgex_trace_tag, arg1), 0)
+#define TRACE_SUC2(fmt, arg1, arg2) \
+ (_gpgex_debug (_gpgex_trace_level, "%s (%s=0x%x): leave: " fmt "\n", \
+ _gpgex_trace_func, _gpgex_trace_tagname, \
+ _gpgex_trace_tag, arg1, arg2), 0)
+#define TRACE_SUC5(fmt, arg1, arg2, arg3, arg4, arg5) \
+ (_gpgex_debug (_gpgex_trace_level, "%s (%s=0x%x): leave: " fmt "\n", \
+ _gpgex_trace_func, _gpgex_trace_tagname, \
+ _gpgex_trace_tag, arg1, arg2, arg3, arg4, arg5), 0)
+
+#define TRACE_LOG(fmt) \
+ (_gpgex_debug (_gpgex_trace_level, "%s (%s=0x%x): check: " fmt "\n", \
+ _gpgex_trace_func, _gpgex_trace_tagname, \
+ _gpgex_trace_tag), 0)
+#define TRACE_LOG1(fmt, arg1) \
+ (_gpgex_debug (_gpgex_trace_level, "%s (%s=0x%x): check: " fmt "\n", \
+ _gpgex_trace_func, _gpgex_trace_tagname, \
+ _gpgex_trace_tag, arg1), 0)
+#define TRACE_LOG2(fmt, arg1, arg2) \
+ (_gpgex_debug (_gpgex_trace_level, "%s (%s=0x%x): check: " fmt "\n", \
+ _gpgex_trace_func, _gpgex_trace_tagname, \
+ _gpgex_trace_tag, arg1, arg2), 0)
+#define TRACE_LOG3(fmt, arg1, arg2, arg3) \
+ (_gpgex_debug (_gpgex_trace_level, "%s (%s=0x%x): check: " fmt "\n", \
+ _gpgex_trace_func, _gpgex_trace_tagname, \
+ _gpgex_trace_tag, arg1, arg2, arg3), 0)
+#define TRACE_LOG4(fmt, arg1, arg2, arg3, arg4) \
+ (_gpgex_debug (_gpgex_trace_level, "%s (%s=0x%x): check: " fmt "\n", \
+ _gpgex_trace_func, _gpgex_trace_tagname, \
+ _gpgex_trace_tag, arg1, arg2, arg3, arg4), 0)
+#define TRACE_LOG6(fmt, arg1, arg2, arg3, arg4, arg5, arg6) \
+ (_gpgex_debug (_gpgex_trace_level, "%s (%s=0x%x): check: " fmt "\n", \
+ _gpgex_trace_func, _gpgex_trace_tagname, \
+ _gpgex_trace_tag, arg1, arg2, arg3, arg4, arg5, \
+ arg6), 0)
+
#endif
More information about the Gnupg-commits
mailing list