[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