gnetworking.h.in: move "#undef interface"
[platform/upstream/glib.git] / gio / win32 / gwin32directorymonitor.c
index 4590ff6..b5f192e 100644 (file)
  * 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., 59 Temple Place, Suite 330,
- * Boston, MA 02111-1307, USA.
+ * Public License along with this library; if not, see <http://www.gnu.org/licenses/>.
  *
  * Author: Vlad Grecescu <b100dian@gmail.com>
  * 
  */
 
-#define _WIN32_WINNT 0x0400
-
 #include "config.h"
 #include "gwin32directorymonitor.h"
-#include "giomodule.h"
 #include <windows.h>
 
 G_DEFINE_TYPE_WITH_CODE (GWin32DirectoryMonitor,
@@ -64,9 +59,29 @@ g_win32_directory_monitor_finalize (GObject *base)
 {
   GWin32DirectoryMonitor *self;
   self = G_WIN32_DIRECTORY_MONITOR (base);
-  
-  g_free (self->priv->file_notify_buffer);
-  g_free (self->priv);
+
+  if (self->priv->hDirectory == INVALID_HANDLE_VALUE)
+    {
+      /* If we don't have a directory handle we can free
+       * self->priv->file_notify_buffer and self->priv here. The
+       * callback won't be called obviously any more (and presumably
+       * never has been called).
+       */
+      g_free (self->priv->file_notify_buffer);
+      self->priv->file_notify_buffer = NULL;
+      g_free (self->priv);
+    }
+  else
+    {
+      /* If we have a directory handle, the OVERLAPPED struct is
+       * passed once more to the callback as a result of the
+       * CloseHandle() done in the cancel method, so self->priv has to
+       * be kept around. The GWin32DirectoryMonitor object is
+       * disappearing, so can't leave a pointer to it in
+       * self->priv->self.
+       */
+      self->priv->self = NULL;
+    }
 
   if (G_OBJECT_CLASS (g_win32_directory_monitor_parent_class)->finalize)
     (*G_OBJECT_CLASS (g_win32_directory_monitor_parent_class)->finalize) (base);
@@ -78,7 +93,13 @@ g_win32_directory_monitor_cancel (GFileMonitor *base)
   GWin32DirectoryMonitor *self;
   self = G_WIN32_DIRECTORY_MONITOR (base);
 
-  /* This triggers a last callback() with nBytes=0 */ 
+  /* This triggers a last callback() with nBytes==0. */
+
+  /* Actually I am not so sure about that, it seems to trigger a last
+   * callback allright, but the way to recognize that it is the final
+   * one is not to check for nBytes==0, I think that was a
+   * misunderstanding.
+   */ 
   if (self->priv->hDirectory != INVALID_HANDLE_VALUE)
     CloseHandle (self->priv->hDirectory);
 
@@ -94,7 +115,7 @@ g_win32_directory_monitor_callback (DWORD        error,
 {
   gulong offset;
   PFILE_NOTIFY_INFORMATION pfile_notify_walker;
-  gulong file_name_len;
+  glong file_name_len;
   gchar *file_name;
   gchar *path;
   GFile *file;
@@ -110,23 +131,30 @@ g_win32_directory_monitor_callback (DWORD        error,
       G_FILE_MONITOR_EVENT_CREATED, /* FILE_ACTION_RENAMED_NEW_NAME */
     };
 
-  if (!nBytes) /* Monitor was cancelled/finalized */
-    return;
-
-  if (g_file_monitor_is_cancelled (G_FILE_MONITOR (priv->self)))
-    return; /* and ReadDirectoryChangesW doesn't get called this time */
+  /* If priv->self is NULL the GWin32DirectoryMonitor object has been destroyed. */
+  if (priv->self == NULL ||
+      g_file_monitor_is_cancelled (priv->self) ||
+      priv->file_notify_buffer == NULL)
+    {
+      g_free (priv->file_notify_buffer);
+      g_free (priv);
+      return;
+    }
 
   offset = 0;
   do {
     pfile_notify_walker = (PFILE_NOTIFY_INFORMATION)(priv->file_notify_buffer + offset);
+    if (pfile_notify_walker->Action > 0)
+      {
+       file_name = g_utf16_to_utf8 (pfile_notify_walker->FileName, pfile_notify_walker->FileNameLength / sizeof(WCHAR), NULL, &file_name_len, NULL);
+       path = g_build_filename(G_LOCAL_DIRECTORY_MONITOR (priv->self)->dirname, file_name, NULL);
+       file = g_file_new_for_path (path);
+       g_file_monitor_emit_event (priv->self, file, NULL, events [pfile_notify_walker->Action]);
+       g_object_unref (file);
+       g_free (path);
+       g_free (file_name);
+      }
     offset += pfile_notify_walker->NextEntryOffset;
-    file_name = g_utf16_to_utf8 (pfile_notify_walker->FileName, pfile_notify_walker->FileNameLength / sizeof(WCHAR), NULL, &file_name_len, NULL);
-    path = g_build_filename(G_LOCAL_DIRECTORY_MONITOR (priv->self)->dirname, file_name, NULL);
-    file = g_file_new_for_path (path);
-    g_file_monitor_emit_event (priv->self, file, NULL, events [pfile_notify_walker->Action]);
-    g_object_unref (file);
-    g_free (path);
-    g_free (file_name);
   } while (pfile_notify_walker->NextEntryOffset);
 
   ReadDirectoryChangesW (priv->hDirectory,
@@ -151,7 +179,6 @@ g_win32_directory_monitor_constructor (GType                  type,
   GObjectClass *parent_class;
   GWin32DirectoryMonitor *self;
   wchar_t *wdirname;
-  gboolean result;
 
   klass = G_WIN32_DIRECTORY_MONITOR_CLASS (g_type_class_peek (G_TYPE_WIN32_DIRECTORY_MONITOR));
   parent_class = G_OBJECT_CLASS (g_type_class_peek_parent (klass));
@@ -174,17 +201,17 @@ g_win32_directory_monitor_constructor (GType                  type,
       return obj;
     }
 
-  result = ReadDirectoryChangesW (self->priv->hDirectory,
-                                 (gpointer)self->priv->file_notify_buffer,
-                                 self->priv->buffer_allocated_bytes,
-                                 FALSE, 
-                                 FILE_NOTIFY_CHANGE_FILE_NAME |
-                                 FILE_NOTIFY_CHANGE_DIR_NAME |
-                                 FILE_NOTIFY_CHANGE_ATTRIBUTES |
-                                 FILE_NOTIFY_CHANGE_SIZE,
-                                 &self->priv->buffer_filled_bytes,
-                                 &self->priv->overlapped,
-                                 g_win32_directory_monitor_callback);
+  ReadDirectoryChangesW (self->priv->hDirectory,
+                         (gpointer)self->priv->file_notify_buffer,
+                         self->priv->buffer_allocated_bytes,
+                         FALSE,
+                         FILE_NOTIFY_CHANGE_FILE_NAME |
+                         FILE_NOTIFY_CHANGE_DIR_NAME |
+                         FILE_NOTIFY_CHANGE_ATTRIBUTES |
+                         FILE_NOTIFY_CHANGE_SIZE,
+                         &self->priv->buffer_filled_bytes,
+                         &self->priv->overlapped,
+                         g_win32_directory_monitor_callback);
   /* Ignore errors */
 
   return obj;