Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse code

Add GWin32InputStream and GWin32OutputStream classes

Correspond to GUnixInputStream and GUnixOutputStream. No true async
support though. But that is how the Win32 API is, for files not
explicitly opened for so-called overlapped IO.

The API to create these streams takes Win32 HANDLEs. Not file
descriptors, because file descriptors are specific to the C library
used. The user code and GLib might be using different C libraries.

Also add a test program for the new classes, and a gio-windows-2.0.pc
file.
  • Loading branch information...
commit 9af8b8321146cddbe5bee09e972507f023e58ce0 1 parent 48cd4cb
tml1024 authored April 19, 2010
5  Makefile.am
@@ -53,6 +53,7 @@ EXTRA_DIST += 			\
53 53
 	gthread-2.0.pc.in	\
54 54
 	gio-2.0.pc.in		\
55 55
 	gio-unix-2.0.pc.in	\
  56
+	gio-windows-2.0.pc.in	\
56 57
 	glib-2.0-uninstalled.pc.in 	\
57 58
 	gobject-2.0-uninstalled.pc.in 	\
58 59
 	gmodule-2.0-uninstalled.pc.in	\
@@ -108,6 +109,10 @@ if OS_UNIX
108 109
 pkgconfig_DATA += gio-unix-2.0.pc
109 110
 endif
110 111
 
  112
+if OS_WIN32
  113
+pkgconfig_DATA += gio-windows-2.0.pc
  114
+endif
  115
+
111 116
 $(pkgconfig_DATA): config.status
112 117
 
113 118
 # install mkinstalldirs for glib-gettextize's benefit
4  build/win32/vs9/glib.vsprops
@@ -204,6 +204,10 @@ copy ..\..\..\gio\gvolumemonitor.h $(OutDir)\include\glib-2.0\gio

204 204
 copy ..\..\..\gio\gzlibcompressor.h $(OutDir)\include\glib-2.0\gio

205 205
 copy ..\..\..\gio\gzlibdecompressor.h $(OutDir)\include\glib-2.0\gio

206 206
 
  207
+mkdir $(OutDir)\include\gio-win32-2.0\gio

  208
+copy ..\..\..\gio\gwin32inputstream.h $(OutDir)\include\gio-win32-2.0\gio

  209
+copy ..\..\..\gio\gwin32outputstream.h $(OutDir)\include\gio-win32-2.0\gio

  210
+
207 211
 mkdir $(OutDir)\lib\glib-2.0\include

208 212
 copy ..\..\..\glibconfig.h $(OutDir)\lib\glib-2.0\include

209 213
 
1  configure.in
@@ -3510,6 +3510,7 @@ gobject-2.0.pc
3510 3510
 gobject-2.0-uninstalled.pc
3511 3511
 gio-2.0.pc
3512 3512
 gio-unix-2.0.pc
  3513
+gio-windows-2.0.pc
3513 3514
 gio-2.0-uninstalled.pc
3514 3515
 gio-unix-2.0-uninstalled.pc
3515 3516
 glib-zip
11  gio-windows-2.0.pc.in
... ...
@@ -0,0 +1,11 @@
  1
+prefix=@prefix@
  2
+exec_prefix=@exec_prefix@
  3
+libdir=@libdir@
  4
+includedir=@includedir@
  5
+
  6
+Name: GIO Windows specific APIs
  7
+Description: Windows specific headers for glib I/O library
  8
+Version: @VERSION@
  9
+Requires: gobject-2.0,gmodule-no-export-2.0,gio-2.0
  10
+Libs: -L${libdir} -lgio-2.0
  11
+Cflags: -I${includedir}/gio-win32-2.0/
11  gio/Makefile.am
@@ -202,6 +202,15 @@ win32_sources = \
202 202
 	gwin32resolver.h \
203 203
 	gwin32volumemonitor.c \
204 204
 	gwin32volumemonitor.h \
  205
+	gwin32inputstream.c \
  206
+	gwin32outputstream.c \
  207
+	gwin32outputstream.h \
  208
+	$(NULL)
  209
+
  210
+giowin32includedir=$(includedir)/gio-win32-2.0/gio
  211
+giowin32include_HEADERS = \
  212
+	gwin32inputstream.h \
  213
+	gwin32outputstream.h \
205 214
 	$(NULL)
206 215
 
207 216
 endif
@@ -509,7 +518,7 @@ dist-hook: $(BUILT_EXTRA_DIST) ../build/win32/vs9/gio.vcproj
509 518
 	  cp $$d/$$f $(distdir) || exit 1; done
510 519
 
511 520
 ../build/win32/vs9/gio.vcproj: $(top_srcdir)/build/win32/vs9/gio.vcprojin
512  
-	for F in $(libgio_2_0_la_SOURCES); do \
  521
+	for F in $(libgio_2_0_la_SOURCES) $(win32_sources); do \
513 522
 		case $$F in \
514 523
 		*.c) echo '   <File RelativePath="..\..\..\gio\'$$F'" />' \
515 524
 		     ;; \
27  gio/gio.symbols
@@ -611,6 +611,9 @@ g_io_stream_clear_pending
611 611
 #if IN_FILE(__G_IO_ERROR_C__)
612 612
 g_io_error_quark
613 613
 g_io_error_from_errno
  614
+#ifdef G_OS_WIN32
  615
+g_io_error_from_win32_error
  616
+#endif
614 617
 #endif
615 618
 #endif
616 619
 
@@ -827,6 +830,30 @@ g_unix_output_stream_get_fd
827 830
 #endif
828 831
 #endif
829 832
 
  833
+#if IN_HEADER(__G_WIN32_INPUT_STREAM_H__)
  834
+#if IN_FILE(__G_WIN32_INPUT_STREAM_C__)
  835
+#ifdef G_OS_WIN32
  836
+g_win32_input_stream_get_type  G_GNUC_CONST
  837
+g_win32_input_stream_new
  838
+g_win32_input_stream_set_close_handle
  839
+g_win32_input_stream_get_close_handle
  840
+g_win32_input_stream_get_handle
  841
+#endif /* G_OS_WIN32 */
  842
+#endif
  843
+#endif
  844
+
  845
+#if IN_HEADER(__G_WIN32_OUTPUT_STREAM_H__)
  846
+#if IN_FILE(__G_WIN32_OUTPUT_STREAM_C__)
  847
+#ifdef G_OS_WIN32
  848
+g_win32_output_stream_get_type  G_GNUC_CONST
  849
+g_win32_output_stream_new
  850
+g_win32_output_stream_set_close_handle
  851
+g_win32_output_stream_get_close_handle
  852
+g_win32_output_stream_get_handle
  853
+#endif /* G_OS_WIN32 */
  854
+#endif
  855
+#endif
  856
+
830 857
 #if IN_HEADER(__G_MOUNT_H__)
831 858
 #if IN_FILE(__G_MOUNT_C__)
832 859
 g_mount_get_type  G_GNUC_CONST
27  gio/gioerror.c
@@ -206,5 +206,32 @@ g_io_error_from_errno (gint err_no)
206 206
     }
207 207
 }
208 208
 
  209
+#ifdef G_OS_WIN32
  210
+
  211
+/**
  212
+ * g_io_error_from_win32_error:
  213
+ * @error_code: Windows error number.
  214
+ *
  215
+ * Converts some common error codes into GIO error codes. The
  216
+ * fallback value G_IO_ERROR_FAILED is returned for error codes not
  217
+ * handled.
  218
+ *
  219
+ * Returns: #GIOErrorEnum value for the given error number.
  220
+ *
  221
+ * Since: 2.26
  222
+ **/
  223
+GIOErrorEnum
  224
+g_io_error_from_win32_error (gint error_code)
  225
+{
  226
+  switch (error_code)
  227
+    {
  228
+    default:
  229
+      return G_IO_ERROR_FAILED;
  230
+      break;
  231
+    }
  232
+}
  233
+
  234
+#endif
  235
+
209 236
 #define __G_IO_ERROR_C__
210 237
 #include "gioaliasdef.c"
4  gio/gioerror.h
@@ -43,6 +43,10 @@ G_BEGIN_DECLS
43 43
 GQuark       g_io_error_quark      (void);
44 44
 GIOErrorEnum g_io_error_from_errno (gint err_no);
45 45
 
  46
+#ifdef G_OS_WIN32
  47
+GIOErrorEnum g_io_error_from_win32_error (gint error_code);
  48
+#endif
  49
+
46 50
 G_END_DECLS
47 51
 
48 52
 #endif /* __G_IO_ERROR_H__ */
359  gio/gwin32inputstream.c
... ...
@@ -0,0 +1,359 @@
  1
+/* GIO - GLib Input, Output and Streaming Library
  2
+ *
  3
+ * Copyright (C) 2006-2010 Red Hat, Inc.
  4
+ *
  5
+ * This library is free software; you can redistribute it and/or
  6
+ * modify it under the terms of the GNU Lesser General Public
  7
+ * License as published by the Free Software Foundation; either
  8
+ * version 2 of the License, or (at your option) any later version.
  9
+ *
  10
+ * This library is distributed in the hope that it will be useful,
  11
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  13
+ * Lesser General Public License for more details.
  14
+ *
  15
+ * You should have received a copy of the GNU Lesser General
  16
+ * Public License along with this library; if not, write to the
  17
+ * Free Software Foundation, Inc., 59 Temple Place, Suite 330,
  18
+ * Boston, MA 02111-1307, USA.
  19
+ *
  20
+ * Author: Alexander Larsson <alexl@redhat.com>
  21
+ * Author: Tor Lillqvist <tml@iki.fi>
  22
+ */
  23
+
  24
+#include "config.h"
  25
+
  26
+#include <windows.h>
  27
+
  28
+#include <io.h>
  29
+
  30
+#include <glib.h>
  31
+#include "gioerror.h"
  32
+#include "gsimpleasyncresult.h"
  33
+#include "gwin32inputstream.h"
  34
+#include "gcancellable.h"
  35
+#include "gasynchelper.h"
  36
+#include "glibintl.h"
  37
+
  38
+#include "gioalias.h"
  39
+
  40
+/**
  41
+ * SECTION:gwin32inputstream
  42
+ * @short_description: Streaming input operations for Windows file handles
  43
+ * @include: gio/gwin32inputstream.h
  44
+ * @see_also: #GInputStream
  45
+ *
  46
+ * #GWin32InputStream implements #GInputStream for reading from a
  47
+ * Windows file handle.
  48
+ *
  49
+ * Note that <filename>&lt;gio/gwin32inputstream.h&gt;</filename> belongs
  50
+ * to the Windows-specific GIO interfaces, thus you have to use the
  51
+ * <filename>gio-windows-2.0.pc</filename> pkg-config file when using it.
  52
+ */
  53
+
  54
+enum {
  55
+  PROP_0,
  56
+  PROP_HANDLE,
  57
+  PROP_CLOSE_HANDLE
  58
+};
  59
+
  60
+G_DEFINE_TYPE (GWin32InputStream, g_win32_input_stream, G_TYPE_INPUT_STREAM);
  61
+
  62
+struct _GWin32InputStreamPrivate {
  63
+  HANDLE handle;
  64
+  gboolean close_handle;
  65
+};
  66
+
  67
+static void     g_win32_input_stream_set_property (GObject              *object,
  68
+						   guint                 prop_id,
  69
+						   const GValue         *value,
  70
+						   GParamSpec           *pspec);
  71
+static void     g_win32_input_stream_get_property (GObject              *object,
  72
+						   guint                 prop_id,
  73
+						   GValue               *value,
  74
+						   GParamSpec           *pspec);
  75
+static gssize   g_win32_input_stream_read         (GInputStream         *stream,
  76
+						   void                 *buffer,
  77
+						   gsize                 count,
  78
+						   GCancellable         *cancellable,
  79
+						   GError              **error);
  80
+static gboolean g_win32_input_stream_close        (GInputStream         *stream,
  81
+						   GCancellable         *cancellable,
  82
+						   GError              **error);
  83
+
  84
+static void
  85
+g_win32_input_stream_finalize (GObject *object)
  86
+{
  87
+  G_OBJECT_CLASS (g_win32_input_stream_parent_class)->finalize (object);
  88
+}
  89
+
  90
+static void
  91
+g_win32_input_stream_class_init (GWin32InputStreamClass *klass)
  92
+{
  93
+  GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
  94
+  GInputStreamClass *stream_class = G_INPUT_STREAM_CLASS (klass);
  95
+
  96
+  g_type_class_add_private (klass, sizeof (GWin32InputStreamPrivate));
  97
+
  98
+  gobject_class->get_property = g_win32_input_stream_get_property;
  99
+  gobject_class->set_property = g_win32_input_stream_set_property;
  100
+  gobject_class->finalize = g_win32_input_stream_finalize;
  101
+
  102
+  stream_class->read_fn = g_win32_input_stream_read;
  103
+  stream_class->close_fn = g_win32_input_stream_close;
  104
+
  105
+  /**
  106
+   * GWin32InputStream:handle:
  107
+   *
  108
+   * The handle that the stream reads from.
  109
+   *
  110
+   * Since: 2.26
  111
+   */
  112
+  g_object_class_install_property (gobject_class,
  113
+				   PROP_HANDLE,
  114
+				   g_param_spec_pointer ("handle",
  115
+							 P_("File handle"),
  116
+							 P_("The file handle to read from"),
  117
+							 G_PARAM_READABLE | G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_NAME | G_PARAM_STATIC_NICK | G_PARAM_STATIC_BLURB));
  118
+
  119
+  /**
  120
+   * GWin32InputStream:close-handle:
  121
+   *
  122
+   * Whether to close the file handle when the stream is closed.
  123
+   *
  124
+   * Since: 2.26
  125
+   */
  126
+  g_object_class_install_property (gobject_class,
  127
+				   PROP_CLOSE_HANDLE,
  128
+				   g_param_spec_boolean ("close-handle",
  129
+							 P_("Close file handle"),
  130
+							 P_("Whether to close the file handle when the stream is closed"),
  131
+							 TRUE,
  132
+							 G_PARAM_READABLE | G_PARAM_WRITABLE | G_PARAM_STATIC_NAME | G_PARAM_STATIC_NICK | G_PARAM_STATIC_BLURB));
  133
+}
  134
+
  135
+static void
  136
+g_win32_input_stream_set_property (GObject         *object,
  137
+				   guint            prop_id,
  138
+				   const GValue    *value,
  139
+				   GParamSpec      *pspec)
  140
+{
  141
+  GWin32InputStream *win32_stream;
  142
+
  143
+  win32_stream = G_WIN32_INPUT_STREAM (object);
  144
+
  145
+  switch (prop_id)
  146
+    {
  147
+    case PROP_HANDLE:
  148
+      win32_stream->priv->handle = g_value_get_pointer (value);
  149
+      break;
  150
+    case PROP_CLOSE_HANDLE:
  151
+      win32_stream->priv->close_handle = g_value_get_boolean (value);
  152
+      break;
  153
+    default:
  154
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
  155
+      break;
  156
+    }
  157
+}
  158
+
  159
+static void
  160
+g_win32_input_stream_get_property (GObject    *object,
  161
+				   guint       prop_id,
  162
+				   GValue     *value,
  163
+				   GParamSpec *pspec)
  164
+{
  165
+  GWin32InputStream *win32_stream;
  166
+
  167
+  win32_stream = G_WIN32_INPUT_STREAM (object);
  168
+
  169
+  switch (prop_id)
  170
+    {
  171
+    case PROP_HANDLE:
  172
+      g_value_set_pointer (value, win32_stream->priv->handle);
  173
+      break;
  174
+    case PROP_CLOSE_HANDLE:
  175
+      g_value_set_boolean (value, win32_stream->priv->close_handle);
  176
+      break;
  177
+    default:
  178
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
  179
+    }
  180
+}
  181
+
  182
+static void
  183
+g_win32_input_stream_init (GWin32InputStream *win32_stream)
  184
+{
  185
+  win32_stream->priv = G_TYPE_INSTANCE_GET_PRIVATE (win32_stream,
  186
+						    G_TYPE_WIN32_INPUT_STREAM,
  187
+						    GWin32InputStreamPrivate);
  188
+
  189
+  win32_stream->priv->handle = NULL;
  190
+  win32_stream->priv->close_handle = TRUE;
  191
+}
  192
+
  193
+/**
  194
+ * g_win32_input_stream_new:
  195
+ * @handle: a Win32 file handle
  196
+ * @close_fd: %TRUE to close the handle when done
  197
+ *
  198
+ * Creates a new #GWin32InputStream for the given @fd.
  199
+ *
  200
+ * If @close_handle is %TRUE, the handle will be closed
  201
+ * when the stream is closed.
  202
+ *
  203
+ * Note that "handle" here means a Win32 HANDLE, not a "file descriptor"
  204
+ * as used in the Windows C libraries.
  205
+ *
  206
+ * Returns: a new #GWin32InputStream
  207
+ **/
  208
+GInputStream *
  209
+g_win32_input_stream_new (void     *handle,
  210
+			  gboolean close_handle)
  211
+{
  212
+  GWin32InputStream *stream;
  213
+
  214
+  g_return_val_if_fail (handle != NULL, NULL);
  215
+
  216
+  stream = g_object_new (G_TYPE_WIN32_INPUT_STREAM,
  217
+			 "handle", handle,
  218
+			 "close-handle", close_handle,
  219
+			 NULL);
  220
+
  221
+  return G_INPUT_STREAM (stream);
  222
+}
  223
+
  224
+/**
  225
+ * g_win32_input_stream_set_close_handle:
  226
+ * @stream: a #GWin32InputStream
  227
+ * @close_handle: %TRUE to close the handle when done
  228
+ *
  229
+ * Sets whether the handle of @stream shall be closed
  230
+ * when the stream is closed.
  231
+ *
  232
+ * Since: 2.26
  233
+ */
  234
+void
  235
+g_win32_input_stream_set_close_handle (GWin32InputStream *stream,
  236
+				       gboolean          close_handle)
  237
+{
  238
+  g_return_if_fail (G_IS_WIN32_INPUT_STREAM (stream));
  239
+
  240
+  close_handle = close_handle != FALSE;
  241
+  if (stream->priv->close_handle != close_handle)
  242
+    {
  243
+      stream->priv->close_handle = close_handle;
  244
+      g_object_notify (G_OBJECT (stream), "close-handle");
  245
+    }
  246
+}
  247
+
  248
+/**
  249
+ * g_win32_input_stream_get_close_handle:
  250
+ * @stream: a #GWin32InputStream
  251
+ *
  252
+ * Returns whether the handle of @stream will be
  253
+ * closed when the stream is closed.
  254
+ *
  255
+ * Return value: %TRUE if the handle is closed when done
  256
+ *
  257
+ * Since: 2.26
  258
+ */
  259
+gboolean
  260
+g_win32_input_stream_get_close_handle (GWin32InputStream *stream)
  261
+{
  262
+  g_return_val_if_fail (G_IS_WIN32_INPUT_STREAM (stream), FALSE);
  263
+
  264
+  return stream->priv->close_handle;
  265
+}
  266
+
  267
+/**
  268
+ * g_win32_input_stream_get_handle:
  269
+ * @stream: a #GWin32InputStream
  270
+ *
  271
+ * Return the Windows file handle that the stream reads from.
  272
+ *
  273
+ * Return value: The file handle of @stream
  274
+ *
  275
+ * Since: 2.26
  276
+ */
  277
+void *
  278
+g_win32_input_stream_get_handle (GWin32InputStream *stream)
  279
+{
  280
+  g_return_val_if_fail (G_IS_WIN32_INPUT_STREAM (stream), NULL);
  281
+
  282
+  return stream->priv->handle;
  283
+}
  284
+
  285
+static gssize
  286
+g_win32_input_stream_read (GInputStream  *stream,
  287
+			   void          *buffer,
  288
+			   gsize          count,
  289
+			   GCancellable  *cancellable,
  290
+			   GError       **error)
  291
+{
  292
+  GWin32InputStream *win32_stream;
  293
+  BOOL res;
  294
+  DWORD nbytes, nread;
  295
+
  296
+  win32_stream = G_WIN32_INPUT_STREAM (stream);
  297
+
  298
+  if (g_cancellable_set_error_if_cancelled (cancellable, error))
  299
+    return -1;
  300
+
  301
+  if (count > G_MAXINT)
  302
+    nbytes = G_MAXINT;
  303
+  else
  304
+    nbytes = count;
  305
+
  306
+  res = ReadFile (win32_stream->priv->handle, buffer, nbytes, &nread, NULL);
  307
+  if (!res)
  308
+    {
  309
+      int errsv = GetLastError ();
  310
+      gchar *emsg;
  311
+
  312
+      if (errsv == ERROR_HANDLE_EOF ||
  313
+	  errsv == ERROR_BROKEN_PIPE)
  314
+	return 0;
  315
+
  316
+      emsg = g_win32_error_message (errsv);
  317
+      g_set_error (error, G_IO_ERROR,
  318
+		   g_io_error_from_win32_error (errsv),
  319
+		   _("Error reading from handle: %s"),
  320
+		   emsg);
  321
+      g_free (emsg);
  322
+      return -1;
  323
+    }
  324
+
  325
+  return nread;
  326
+}
  327
+
  328
+static gboolean
  329
+g_win32_input_stream_close (GInputStream  *stream,
  330
+			   GCancellable  *cancellable,
  331
+			   GError       **error)
  332
+{
  333
+  GWin32InputStream *win32_stream;
  334
+  BOOL res;
  335
+
  336
+  win32_stream = G_WIN32_INPUT_STREAM (stream);
  337
+
  338
+  if (!win32_stream->priv->close_handle)
  339
+    return TRUE;
  340
+
  341
+  res = CloseHandle (win32_stream->priv->handle);
  342
+  if (!res)
  343
+    {
  344
+      int errsv = GetLastError ();
  345
+      gchar *emsg = g_win32_error_message (errsv);
  346
+
  347
+      g_set_error (error, G_IO_ERROR,
  348
+		   g_io_error_from_win32_error (errsv),
  349
+		   _("Error closing handle: %s"),
  350
+		   emsg);
  351
+      g_free (emsg);
  352
+      return FALSE;
  353
+    }
  354
+
  355
+  return TRUE;
  356
+}
  357
+
  358
+#define __G_WIN32_INPUT_STREAM_C__
  359
+#include "gioaliasdef.c"
79  gio/gwin32inputstream.h
... ...
@@ -0,0 +1,79 @@
  1
+/* GIO - GLib Input, Output and Streaming Library
  2
+ *
  3
+ * Copyright (C) 2006-2010 Red Hat, Inc.
  4
+ *
  5
+ * This library is free software; you can redistribute it and/or
  6
+ * modify it under the terms of the GNU Lesser General Public
  7
+ * License as published by the Free Software Foundation; either
  8
+ * version 2 of the License, or (at your option) any later version.
  9
+ *
  10
+ * This library is distributed in the hope that it will be useful,
  11
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  13
+ * Lesser General Public License for more details.
  14
+ *
  15
+ * You should have received a copy of the GNU Lesser General
  16
+ * Public License along with this library; if not, write to the
  17
+ * Free Software Foundation, Inc., 59 Temple Place, Suite 330,
  18
+ * Boston, MA 02111-1307, USA.
  19
+ *
  20
+ * Author: Alexander Larsson <alexl@redhat.com>
  21
+ * Author: Tor Lillqvist <tml@iki.fi>
  22
+ */
  23
+
  24
+#ifndef __G_WIN32_INPUT_STREAM_H__
  25
+#define __G_WIN32_INPUT_STREAM_H__
  26
+
  27
+#include <gio/gio.h>
  28
+
  29
+G_BEGIN_DECLS
  30
+
  31
+#define G_TYPE_WIN32_INPUT_STREAM         (g_win32_input_stream_get_type ())
  32
+#define G_WIN32_INPUT_STREAM(o)           (G_TYPE_CHECK_INSTANCE_CAST ((o), G_TYPE_WIN32_INPUT_STREAM, GWin32InputStream))
  33
+#define G_WIN32_INPUT_STREAM_CLASS(k)     (G_TYPE_CHECK_CLASS_CAST((k), G_TYPE_WIN32_INPUT_STREAM, GWin32InputStreamClass))
  34
+#define G_IS_WIN32_INPUT_STREAM(o)        (G_TYPE_CHECK_INSTANCE_TYPE ((o), G_TYPE_WIN32_INPUT_STREAM))
  35
+#define G_IS_WIN32_INPUT_STREAM_CLASS(k)  (G_TYPE_CHECK_CLASS_TYPE ((k), G_TYPE_WIN32_INPUT_STREAM))
  36
+#define G_WIN32_INPUT_STREAM_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), G_TYPE_WIN32_INPUT_STREAM, GWin32InputStreamClass))
  37
+
  38
+/**
  39
+ * GWin32InputStream:
  40
+ *
  41
+ * Implements #GInputStream for reading from selectable Windows file handles
  42
+ **/
  43
+typedef struct _GWin32InputStream         GWin32InputStream;
  44
+typedef struct _GWin32InputStreamClass    GWin32InputStreamClass;
  45
+typedef struct _GWin32InputStreamPrivate  GWin32InputStreamPrivate;
  46
+
  47
+struct _GWin32InputStream
  48
+{
  49
+  GInputStream parent_instance;
  50
+
  51
+  /*< private >*/
  52
+  GWin32InputStreamPrivate *priv;
  53
+};
  54
+
  55
+struct _GWin32InputStreamClass
  56
+{
  57
+  GInputStreamClass parent_class;
  58
+
  59
+  /*< private >*/
  60
+  /* Padding for future expansion */
  61
+  void (*_g_reserved1) (void);
  62
+  void (*_g_reserved2) (void);
  63
+  void (*_g_reserved3) (void);
  64
+  void (*_g_reserved4) (void);
  65
+  void (*_g_reserved5) (void);
  66
+};
  67
+
  68
+GType          g_win32_input_stream_get_type         (void) G_GNUC_CONST;
  69
+
  70
+GInputStream * g_win32_input_stream_new              (void              *handle,
  71
+						      gboolean           close_handle);
  72
+void           g_win32_input_stream_set_close_handle (GWin32InputStream *stream,
  73
+						      gboolean           close_handle);
  74
+gboolean       g_win32_input_stream_get_close_handle (GWin32InputStream *stream);
  75
+void          *g_win32_input_stream_get_handle       (GWin32InputStream *stream);
  76
+
  77
+G_END_DECLS
  78
+
  79
+#endif /* __G_WIN32_INPUT_STREAM_H__ */
359  gio/gwin32outputstream.c
... ...
@@ -0,0 +1,359 @@
  1
+/* GIO - GLib Input, Output and Streaming Library
  2
+ *
  3
+ * Copyright (C) 2006-2010 Red Hat, Inc.
  4
+ *
  5
+ * This library is free software; you can redistribute it and/or
  6
+ * modify it under the terms of the GNU Lesser General Public
  7
+ * License as published by the Free Software Foundation; either
  8
+ * version 2 of the License, or (at your option) any later version.
  9
+ *
  10
+ * This library is distributed in the hope that it will be useful,
  11
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  13
+ * Lesser General Public License for more details.
  14
+ *
  15
+ * You should have received a copy of the GNU Lesser General
  16
+ * Public License along with this library; if not, write to the
  17
+ * Free Software Foundation, Inc., 59 Temple Place, Suite 330,
  18
+ * Boston, MA 02111-1307, USA.
  19
+ *
  20
+ * Author: Alexander Larsson <alexl@redhat.com>
  21
+ * Author: Tor Lillqvist <tml@iki.fi>
  22
+ */
  23
+
  24
+#include "config.h"
  25
+
  26
+#include <windows.h>
  27
+
  28
+#include <io.h>
  29
+
  30
+#include <glib.h>
  31
+#include <glib/gstdio.h>
  32
+#include "gioerror.h"
  33
+#include "gwin32outputstream.h"
  34
+#include "gcancellable.h"
  35
+#include "gsimpleasyncresult.h"
  36
+#include "gasynchelper.h"
  37
+#include "glibintl.h"
  38
+
  39
+#include "gioalias.h"
  40
+
  41
+/**
  42
+ * SECTION:gwin32outputstream
  43
+ * @short_description: Streaming output operations for Windows file handles
  44
+ * @include: gio/gwin32outputstream.h
  45
+ * @see_also: #GOutputStream
  46
+ *
  47
+ * #GWin32OutputStream implements #GOutputStream for writing to a
  48
+ * Windows file handle.
  49
+ *
  50
+ * Note that <filename>&lt;gio/gwin32outputstream.h&gt;</filename> belongs
  51
+ * to the Windows-specific GIO interfaces, thus you have to use the
  52
+ * <filename>gio-windows-2.0.pc</filename> pkg-config file when using it.
  53
+ */
  54
+
  55
+enum {
  56
+  PROP_0,
  57
+  PROP_HANDLE,
  58
+  PROP_CLOSE_HANDLE
  59
+};
  60
+
  61
+G_DEFINE_TYPE (GWin32OutputStream, g_win32_output_stream, G_TYPE_OUTPUT_STREAM);
  62
+
  63
+
  64
+struct _GWin32OutputStreamPrivate {
  65
+  HANDLE handle;
  66
+  gboolean close_handle;
  67
+};
  68
+
  69
+static void     g_win32_output_stream_set_property (GObject              *object,
  70
+						    guint                 prop_id,
  71
+						    const GValue         *value,
  72
+						    GParamSpec           *pspec);
  73
+static void     g_win32_output_stream_get_property (GObject              *object,
  74
+						    guint                 prop_id,
  75
+						    GValue               *value,
  76
+						    GParamSpec           *pspec);
  77
+static gssize   g_win32_output_stream_write        (GOutputStream        *stream,
  78
+						    const void           *buffer,
  79
+						    gsize                 count,
  80
+						    GCancellable         *cancellable,
  81
+						    GError              **error);
  82
+static gboolean g_win32_output_stream_close        (GOutputStream        *stream,
  83
+						    GCancellable         *cancellable,
  84
+						    GError              **error);
  85
+
  86
+
  87
+static void
  88
+g_win32_output_stream_finalize (GObject *object)
  89
+{
  90
+  G_OBJECT_CLASS (g_win32_output_stream_parent_class)->finalize (object);
  91
+}
  92
+
  93
+static void
  94
+g_win32_output_stream_class_init (GWin32OutputStreamClass *klass)
  95
+{
  96
+  GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
  97
+  GOutputStreamClass *stream_class = G_OUTPUT_STREAM_CLASS (klass);
  98
+
  99
+  g_type_class_add_private (klass, sizeof (GWin32OutputStreamPrivate));
  100
+
  101
+  gobject_class->get_property = g_win32_output_stream_get_property;
  102
+  gobject_class->set_property = g_win32_output_stream_set_property;
  103
+  gobject_class->finalize = g_win32_output_stream_finalize;
  104
+
  105
+  stream_class->write_fn = g_win32_output_stream_write;
  106
+  stream_class->close_fn = g_win32_output_stream_close;
  107
+
  108
+   /**
  109
+   * GWin32OutputStream:handle:
  110
+   *
  111
+   * The file handle that the stream writes to.
  112
+   *
  113
+   * Since: 2.26
  114
+   */
  115
+  g_object_class_install_property (gobject_class,
  116
+				   PROP_HANDLE,
  117
+				   g_param_spec_pointer ("handle",
  118
+							 P_("File handle"),
  119
+							 P_("The file handle to write to"),
  120
+							 G_PARAM_READABLE | G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_NAME | G_PARAM_STATIC_NICK | G_PARAM_STATIC_BLURB));
  121
+
  122
+  /**
  123
+   * GWin32OutputStream:close-handle:
  124
+   *
  125
+   * Whether to close the file handle when the stream is closed.
  126
+   *
  127
+   * Since: 2.26
  128
+   */
  129
+  g_object_class_install_property (gobject_class,
  130
+				   PROP_CLOSE_HANDLE,
  131
+				   g_param_spec_boolean ("close-handle",
  132
+							 P_("Close file handle"),
  133
+							 P_("Whether to close the file handle when the stream is closed"),
  134
+							 TRUE,
  135
+							 G_PARAM_READABLE | G_PARAM_WRITABLE | G_PARAM_STATIC_NAME | G_PARAM_STATIC_NICK | G_PARAM_STATIC_BLURB));
  136
+}
  137
+
  138
+static void
  139
+g_win32_output_stream_set_property (GObject         *object,
  140
+				    guint            prop_id,
  141
+				    const GValue    *value,
  142
+				    GParamSpec      *pspec)
  143
+{
  144
+  GWin32OutputStream *win32_stream;
  145
+
  146
+  win32_stream = G_WIN32_OUTPUT_STREAM (object);
  147
+
  148
+  switch (prop_id)
  149
+    {
  150
+    case PROP_HANDLE:
  151
+      win32_stream->priv->handle = g_value_get_pointer (value);
  152
+      break;
  153
+    case PROP_CLOSE_HANDLE:
  154
+      win32_stream->priv->close_handle = g_value_get_boolean (value);
  155
+      break;
  156
+    default:
  157
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
  158
+      break;
  159
+    }
  160
+}
  161
+
  162
+static void
  163
+g_win32_output_stream_get_property (GObject    *object,
  164
+				    guint       prop_id,
  165
+				    GValue     *value,
  166
+				    GParamSpec *pspec)
  167
+{
  168
+  GWin32OutputStream *win32_stream;
  169
+
  170
+  win32_stream = G_WIN32_OUTPUT_STREAM (object);
  171
+
  172
+  switch (prop_id)
  173
+    {
  174
+    case PROP_HANDLE:
  175
+      g_value_set_pointer (value, win32_stream->priv->handle);
  176
+      break;
  177
+    case PROP_CLOSE_HANDLE:
  178
+      g_value_set_boolean (value, win32_stream->priv->close_handle);
  179
+      break;
  180
+    default:
  181
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
  182
+    }
  183
+}
  184
+
  185
+static void
  186
+g_win32_output_stream_init (GWin32OutputStream *win32_stream)
  187
+{
  188
+  win32_stream->priv = G_TYPE_INSTANCE_GET_PRIVATE (win32_stream,
  189
+						    G_TYPE_WIN32_OUTPUT_STREAM,
  190
+						    GWin32OutputStreamPrivate);
  191
+
  192
+  win32_stream->priv->handle = NULL;
  193
+  win32_stream->priv->close_handle = TRUE;
  194
+}
  195
+
  196
+/**
  197
+ * g_win32_output_stream_new:
  198
+ * @handle: a Win32 file handle
  199
+ * @close_handle: %TRUE to close the handle when done
  200
+ *
  201
+ * Creates a new #GWin32OutputStream for the given @handle.
  202
+ *
  203
+ * If @close_handle, is %TRUE, the handle will be closed when the
  204
+ * output stream is destroyed.
  205
+ *
  206
+ * Returns: a new #GOutputStream
  207
+ *
  208
+ * Since: 2.26
  209
+**/
  210
+GOutputStream *
  211
+g_win32_output_stream_new (void    *handle,
  212
+			   gboolean close_handle)
  213
+{
  214
+  GWin32OutputStream *stream;
  215
+
  216
+  g_return_val_if_fail (handle != NULL, NULL);
  217
+
  218
+  stream = g_object_new (G_TYPE_WIN32_OUTPUT_STREAM,
  219
+			 "handle", handle,
  220
+			 "close-handle", close_handle,
  221
+			 NULL);
  222
+
  223
+  return G_OUTPUT_STREAM (stream);
  224
+}
  225
+
  226
+/**
  227
+ * g_win32_output_stream_set_close_handle:
  228
+ * @stream: a #GWin32OutputStream
  229
+ * @close_handle: %TRUE to close the handle when done
  230
+ *
  231
+ * Sets whether the handle of @stream shall be closed when the stream
  232
+ * is closed.
  233
+ *
  234
+ * Since: 2.26
  235
+ */
  236
+void
  237
+g_win32_output_stream_set_close_handle (GWin32OutputStream *stream,
  238
+					gboolean           close_handle)
  239
+{
  240
+  g_return_if_fail (G_IS_WIN32_OUTPUT_STREAM (stream));
  241
+
  242
+  close_handle = close_handle != FALSE;
  243
+  if (stream->priv->close_handle != close_handle)
  244
+    {
  245
+      stream->priv->close_handle = close_handle;
  246
+      g_object_notify (G_OBJECT (stream), "close-handle");
  247
+    }
  248
+}
  249
+
  250
+/**
  251
+ * g_win32_output_stream_get_close_handle:
  252
+ * @stream: a #GWin32OutputStream
  253
+ *
  254
+ * Returns whether the handle of @stream will be closed when the
  255
+ * stream is closed.
  256
+ *
  257
+ * Return value: %TRUE if the handle is closed when done
  258
+ *
  259
+ * Since: 2.26
  260
+ */
  261
+gboolean
  262
+g_win32_output_stream_get_close_handle (GWin32OutputStream *stream)
  263
+{
  264
+  g_return_val_if_fail (G_IS_WIN32_OUTPUT_STREAM (stream), FALSE);
  265
+
  266
+  return stream->priv->close_handle;
  267
+}
  268
+
  269
+/**
  270
+ * g_win32_output_stream_get_handle:
  271
+ * @stream: a #GWin32OutputStream
  272
+ *
  273
+ * Return the Windows handle that the stream writes to.
  274
+ *
  275
+ * Return value: The handle descriptor of @stream
  276
+ *
  277
+ * Since: 2.26
  278
+ */
  279
+void *
  280
+g_win32_output_stream_get_handle (GWin32OutputStream *stream)
  281
+{
  282
+  g_return_val_if_fail (G_IS_WIN32_OUTPUT_STREAM (stream), NULL);
  283
+
  284
+  return stream->priv->handle;
  285
+}
  286
+
  287
+static gssize
  288
+g_win32_output_stream_write (GOutputStream  *stream,
  289
+			    const void     *buffer,
  290
+			    gsize           count,
  291
+			    GCancellable   *cancellable,
  292
+			    GError        **error)
  293
+{
  294
+  GWin32OutputStream *win32_stream;
  295
+  BOOL res;
  296
+  DWORD nbytes, nwritten;
  297
+
  298
+  win32_stream = G_WIN32_OUTPUT_STREAM (stream);
  299
+
  300
+  if (g_cancellable_set_error_if_cancelled (cancellable, error))
  301
+    return -1;
  302
+
  303
+  if (count > G_MAXINT)
  304
+    nbytes = G_MAXINT;
  305
+  else
  306
+    nbytes = count;
  307
+
  308
+  res = WriteFile (win32_stream->priv->handle, buffer, nbytes, &nwritten, NULL);
  309
+  if (!res)
  310
+    {
  311
+      int errsv = GetLastError ();
  312
+      gchar *emsg = g_win32_error_message (errsv);
  313
+
  314
+      if (errsv == ERROR_HANDLE_EOF)
  315
+	return 0;
  316
+
  317
+      g_set_error (error, G_IO_ERROR,
  318
+		   g_io_error_from_win32_error (errsv),
  319
+		   _("Error writing to handle: %s"),
  320
+		   emsg);
  321
+      g_free (emsg);
  322
+      return -1;
  323
+    }
  324
+
  325
+  return nwritten;
  326
+}
  327
+
  328
+static gboolean
  329
+g_win32_output_stream_close (GOutputStream  *stream,
  330
+			     GCancellable   *cancellable,
  331
+			     GError        **error)
  332
+{
  333
+  GWin32OutputStream *win32_stream;
  334
+  BOOL res;
  335
+
  336
+  win32_stream = G_WIN32_OUTPUT_STREAM (stream);
  337
+
  338
+  if (!win32_stream->priv->close_handle)
  339
+    return TRUE;
  340
+
  341
+  res = CloseHandle (win32_stream->priv->handle);
  342
+  if (!res)
  343
+    {
  344
+      int errsv = GetLastError ();
  345
+      gchar *emsg = g_win32_error_message (errsv);
  346
+
  347
+      g_set_error (error, G_IO_ERROR,
  348
+		   g_io_error_from_win32_error (errsv),
  349
+		   _("Error closing handle: %s"),
  350
+		   emsg);
  351
+      g_free (emsg);
  352
+      return FALSE;
  353
+    }
  354
+
  355
+  return TRUE;
  356
+}
  357
+
  358
+#define __G_WIN32_OUTPUT_STREAM_C__
  359
+#include "gioaliasdef.c"
78  gio/gwin32outputstream.h
... ...
@@ -0,0 +1,78 @@
  1
+/* GIO - GLib Input, Output and Streaming Library
  2
+ *
  3
+ * Copyright (C) 2006-2010 Red Hat, Inc.
  4
+ *
  5
+ * This library is free software; you can redistribute it and/or
  6
+ * modify it under the terms of the GNU Lesser General Public
  7
+ * License as published by the Free Software Foundation; either
  8
+ * version 2 of the License, or (at your option) any later version.
  9
+ *
  10
+ * This library is distributed in the hope that it will be useful,
  11
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  13
+ * Lesser General Public License for more details.
  14
+ *
  15
+ * You should have received a copy of the GNU Lesser General
  16
+ * Public License along with this library; if not, write to the
  17
+ * Free Software Foundation, Inc., 59 Temple Place, Suite 330,
  18
+ * Boston, MA 02111-1307, USA.
  19
+ *
  20
+ * Author: Alexander Larsson <alexl@redhat.com>
  21
+ * Author: Tor Lillqvist <tml@iki.fi>
  22
+ */
  23
+
  24
+#ifndef __G_WIN32_OUTPUT_STREAM_H__
  25
+#define __G_WIN32_OUTPUT_STREAM_H__
  26
+
  27
+#include <gio/gio.h>
  28
+
  29
+G_BEGIN_DECLS
  30
+
  31
+#define G_TYPE_WIN32_OUTPUT_STREAM         (g_win32_output_stream_get_type ())
  32
+#define G_WIN32_OUTPUT_STREAM(o)           (G_TYPE_CHECK_INSTANCE_CAST ((o), G_TYPE_WIN32_OUTPUT_STREAM, GWin32OutputStream))
  33
+#define G_WIN32_OUTPUT_STREAM_CLASS(k)     (G_TYPE_CHECK_CLASS_CAST((k), G_TYPE_WIN32_OUTPUT_STREAM, GWin32OutputStreamClass))
  34
+#define G_IS_WIN32_OUTPUT_STREAM(o)        (G_TYPE_CHECK_INSTANCE_TYPE ((o), G_TYPE_WIN32_OUTPUT_STREAM))
  35
+#define G_IS_WIN32_OUTPUT_STREAM_CLASS(k)  (G_TYPE_CHECK_CLASS_TYPE ((k), G_TYPE_WIN32_OUTPUT_STREAM))
  36
+#define G_WIN32_OUTPUT_STREAM_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), G_TYPE_WIN32_OUTPUT_STREAM, GWin32OutputStreamClass))
  37
+
  38
+/**
  39
+ * GWin32OutputStream:
  40
+ *
  41
+ * Implements #GOutputStream for outputting to Windows file handles
  42
+ **/
  43
+typedef struct _GWin32OutputStream         GWin32OutputStream;
  44
+typedef struct _GWin32OutputStreamClass    GWin32OutputStreamClass;
  45
+typedef struct _GWin32OutputStreamPrivate  GWin32OutputStreamPrivate;
  46
+
  47
+struct _GWin32OutputStream
  48
+{
  49
+  GOutputStream parent_instance;
  50
+
  51
+  /*< private >*/
  52
+  GWin32OutputStreamPrivate *priv;
  53
+};
  54
+
  55
+struct _GWin32OutputStreamClass
  56
+{
  57
+  GOutputStreamClass parent_class;
  58
+
  59
+  /*< private >*/
  60
+  /* Padding for future expansion */
  61
+  void (*_g_reserved1) (void);
  62
+  void (*_g_reserved2) (void);
  63
+  void (*_g_reserved3) (void);
  64
+  void (*_g_reserved4) (void);
  65
+  void (*_g_reserved5) (void);
  66
+};
  67
+
  68
+GType           g_win32_output_stream_get_type         (void) G_GNUC_CONST;
  69
+
  70
+GOutputStream * g_win32_output_stream_new              (void               *handle,
  71
+							gboolean            close_handle);
  72
+void            g_win32_output_stream_set_close_handle (GWin32OutputStream *stream,
  73
+							gboolean           close_handle);
  74
+gboolean        g_win32_output_stream_get_close_handle (GWin32OutputStream *stream);
  75
+void           *g_win32_output_stream_get_handle       (GWin32OutputStream *stream);
  76
+G_END_DECLS
  77
+
  78
+#endif /* __G_WIN32_OUTPUT_STREAM_H__ */
8  gio/tests/Makefile.am
@@ -47,6 +47,10 @@ if OS_UNIX
47 47
 TEST_PROGS += live-g-file desktop-app-info unix-fd #unix-streams
48 48
 endif
49 49
 
  50
+if OS_WIN32
  51
+TEST_PROGS += win32-streams
  52
+endif
  53
+
50 54
 memory_input_stream_SOURCES	  = memory-input-stream.c
51 55
 memory_input_stream_LDADD	  = $(progs_ldadd)
52 56
 
@@ -90,6 +94,10 @@ unix_streams_SOURCES	  = unix-streams.c
90 94
 unix_streams_LDADD	  = $(progs_ldadd) \
91 95
 	$(top_builddir)/gthread/libgthread-2.0.la
92 96
 
  97
+win32_streams_SOURCES	  = win32-streams.c
  98
+win32_streams_LDADD	  = $(progs_ldadd) \
  99
+	$(top_builddir)/gthread/libgthread-2.0.la
  100
+
93 101
 unix_fd_SOURCES	  = unix-fd.c
94 102
 unix_fd_LDADD	  = $(progs_ldadd)
95 103
 
292  gio/tests/win32-streams.c
... ...
@@ -0,0 +1,292 @@
  1
+/* GLib testing framework examples and tests
  2
+ * Copyright (C) 2008 Red Hat, Inc
  3
+ *
  4
+ * This work is provided "as is"; redistribution and modification
  5
+ * in whole or in part, in any medium, physical or electronic is
  6
+ * permitted without restriction.
  7
+ *
  8
+ * This work is distributed in the hope that it will be useful,
  9
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
  10
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  11
+ *
  12
+ * In no event shall the authors or contributors be liable for any
  13
+ * direct, indirect, incidental, special, exemplary, or consequential
  14
+ * damages (including, but not limited to, procurement of substitute
  15
+ * goods or services; loss of use, data, or profits; or business
  16
+ * interruption) however caused and on any theory of liability, whether
  17
+ * in contract, strict liability, or tort (including negligence or
  18
+ * otherwise) arising in any way out of the use of this software, even
  19
+ * if advised of the possibility of such damage.
  20
+ */
  21
+
  22
+#include <glib/glib.h>
  23
+#include <gio/gio.h>
  24
+#include <gio/gwin32inputstream.h>
  25
+#include <gio/gwin32outputstream.h>
  26
+#include <stdlib.h>
  27
+#include <string.h>
  28
+#include <fcntl.h>
  29
+#include <io.h>
  30
+
  31
+#include <windows.h>
  32
+
  33
+#define DATA "abcdefghijklmnopqrstuvwxyz"
  34
+
  35
+int writer_pipe[2], reader_pipe[2];
  36
+GCancellable *writer_cancel, *reader_cancel, *main_cancel;
  37
+GMainLoop *loop;
  38
+
  39
+static gpointer
  40
+writer_thread (gpointer user_data)
  41
+{
  42
+  GOutputStream *out;
  43
+  gssize nwrote, offset;
  44
+  GError *err = NULL;
  45
+  HANDLE out_handle;
  46
+
  47
+  g_assert (DuplicateHandle (GetCurrentProcess (),
  48
+			     (HANDLE) (gintptr) _get_osfhandle (writer_pipe[1]),
  49
+			     GetCurrentProcess (),
  50
+			     &out_handle,
  51
+			     0, FALSE,
  52
+			     DUPLICATE_SAME_ACCESS));
  53
+  close (writer_pipe[1]);
  54
+
  55
+  out = g_win32_output_stream_new (out_handle, TRUE);
  56
+  do
  57
+    {
  58
+      g_usleep (10);
  59
+
  60
+      offset = 0;
  61
+      while (offset < (gssize) sizeof (DATA))
  62
+	{
  63
+	  nwrote = g_output_stream_write (out, DATA + offset,
  64
+					  sizeof (DATA) - offset,
  65
+					  writer_cancel, &err);
  66
+	  if (nwrote <= 0 || err != NULL)
  67
+	    break;
  68
+	  offset += nwrote;
  69
+	}
  70
+
  71
+      g_assert (nwrote > 0 || err != NULL);
  72
+    }
  73
+  while (err == NULL);
  74
+
  75
+  if (g_cancellable_is_cancelled (writer_cancel))
  76
+    {
  77
+      g_cancellable_cancel (main_cancel);
  78
+      g_object_unref (out);
  79
+      return NULL;
  80
+    }
  81
+
  82
+  g_warning ("writer: %s", err->message);
  83
+  g_assert_not_reached ();
  84
+}
  85
+
  86
+static gpointer
  87
+reader_thread (gpointer user_data)
  88
+{
  89
+  GInputStream *in;
  90
+  gssize nread = 0, total;
  91
+  GError *err = NULL;
  92
+  char buf[sizeof (DATA)];
  93
+  HANDLE in_handle;
  94
+
  95
+  g_assert (DuplicateHandle (GetCurrentProcess (),
  96
+			     (HANDLE) (gintptr) _get_osfhandle (reader_pipe[0]),
  97
+			     GetCurrentProcess (),
  98
+			     &in_handle,
  99
+			     0, FALSE,
  100
+			     DUPLICATE_SAME_ACCESS));
  101
+  close (reader_pipe[0]);
  102
+
  103
+  in = g_win32_input_stream_new (in_handle, TRUE);
  104
+
  105
+  do
  106
+    {
  107
+      total = 0;
  108
+      while (total < (gssize) sizeof (DATA))