win32-open3 0.3.1 → 0.3.2

Sign up to get free protection for your applications and to get access to all the features.
data/CHANGES CHANGED
@@ -1,3 +1,9 @@
1
+ == 0.3.2 - 23-Jan-2010
2
+ * Updated the gemspec. The required version is now any version less
3
+ than 1.9.x. This library is for the 1.8.x branch only.
4
+ * The Rakefile now handles the gem building and installation and some
5
+ existing tasks were refactored.
6
+
1
7
  == 0.3.1 - 23-Jun-2009
2
8
  * Updated the license to Artistic 2.0
3
9
  * Set the license in the gemspec.
data/README CHANGED
@@ -1,62 +1,64 @@
1
1
  = Description
2
- This library provides an Open3.popen3 implementation for MS Windows.
2
+ This library provides an Open3.popen3 implementation for MS Windows for
3
+ the Ruby 1.8.x branch.
3
4
 
4
5
  = Prerequisites
5
- Ruby 1.8.2 or later
6
- C++ compiler (if building from source).
6
+ Ruby 1.8.x branch only
7
+ C++ compiler (if building from source)
7
8
 
8
9
  = Installation
9
- rake test (optional)
10
- rake install (non-gem) or rake install_gem (gem)
10
+ gem install win32-open3 # Build and install from source
11
+ gem install win32-open3 --platform mingw32 # Install the binary gem
11
12
 
12
13
  = Synopsis
13
- require 'win32/open3'
14
+ require 'win32/open3'
14
15
 
15
- Open3.popen3('ver'){ |io_in, io_out, io_err|
16
- error = io_err.gets
17
- if error
18
- puts "Error: " + error.chomp
19
- exit
20
- end
21
- puts "Result: " + io_out.readlines.last.chomp
22
- }
16
+ Open3.popen3('ver'){ |io_in, io_out, io_err|
17
+ error = io_err.gets
18
+
19
+ if error
20
+ puts "Error: " + error.chomp
21
+ exit
22
+ end
23
+
24
+ puts "Result: " + io_out.readlines.last.chomp
25
+ }
23
26
 
24
27
  = Notes
25
- This library is not supported on Windows 95, 98, or ME.
26
- This is a stripped down version of Park Heesob's win32_popen library.
28
+ This library is not supported on Windows 95, 98, or ME.
29
+ This is a stripped down version of Park Heesob's win32_popen library.
27
30
 
28
31
  = Developer's Notes
29
- This is a repackaging of Heesob's win32_popen module. The purpose of the
30
- repackaging was to create a unified API between the existing Ruby open3
31
- library and this library.
32
+ This is a repackaging of Heesob's win32_popen module. The purpose of the
33
+ repackaging was to create a unified API between the existing Ruby open3
34
+ library and this library.
32
35
 
33
- The popen2 and posix_popen methods are not included in this release. They
34
- were originally part of the win32_popen module, but have been left out.
35
- They may be added back in at a later date.
36
+ The popen2 and posix_popen methods are not included in this release. They
37
+ were originally part of the win32_popen module, but have been left out.
38
+ They may be added back in at a later date.
36
39
 
37
- There are a couple of differences in the Windows version for open3 (which
38
- also apply to Open4.popen4) - the mode flag and the show flag. For the
39
- mode, you can specify either 't' (text, the default) or 'b' (binary) as a
40
- second argument. For the show flag, you can specify either true or false,
41
- which will show the console window, or not, depending on the value you
42
- pass. The default is false.
40
+ There are a couple of differences in the Windows version for open3 (which
41
+ also apply to Open4.popen4) - the mode flag and the show flag. For the
42
+ mode, you can specify either 't' (text, the default) or 'b' (binary) as a
43
+ second argument. For the show flag, you can specify either true or false,
44
+ which will show the console window, or not, depending on the value you
45
+ pass. The default is false.
43
46
 
44
47
  = Known Issues
45
- I have noticed that this library (and others) may segfault if you are using
46
- the latest version of the Ruby one-click installer and VC++ 7.0 or later.
47
- This appears to be an issue between VC++ 6 (which the installer was built
48
- with) and VC++ 7.0. Your best solution is to either upgrade your C
49
- compiler or to rebuild Ruby from scratch rather than using the installer.
48
+ I have noticed that this library (and others) may segfault if you are using
49
+ the latest version of the Ruby one-click installer and VC++ 7.0 or later.
50
+ This appears to be an issue between VC++ 6 (which the installer was built
51
+ with) and VC++ 7.0. Your best solution is to either upgrade your C
52
+ compiler or to rebuild Ruby from scratch rather than using the installer.
50
53
 
51
54
  = Precompiled binaries
52
-
53
- If you do a typical "gem install win32-open3" you will get a precompiled
54
- binary appropriate for your platform. If you want to build from source,
55
- go the project page and download, download the .zip file, and run the
56
- 'install' Rake task from the command line.
55
+ If you do a typical "gem install win32-open3" you will get a precompiled
56
+ binary appropriate for your platform. If you want to build from source,
57
+ go the project page and download, download the .zip file, and run the
58
+ 'install' Rake task from the command line.
57
59
 
58
60
  = Future Plans
59
- Replace the current implementation with a pure Ruby version.
61
+ Replace the current implementation with a pure Ruby version, if possible.
60
62
 
61
63
  = More Documentation
62
- See the doc/open3.txt file for more details.
64
+ See the doc/open3.txt file for more details.
data/Rakefile CHANGED
@@ -4,100 +4,95 @@ require 'rake/testtask'
4
4
  require 'rbconfig'
5
5
  include Config
6
6
 
7
+ make = CONFIG['MAKEFILES'].nil? ? 'nmake' : 'make'
8
+
7
9
  desc 'Install the win32-open3 library'
8
10
  task :install => [:build] do
9
- Dir.chdir('ext'){
10
- sh 'nmake install'
11
- }
12
- end
13
-
14
- desc 'Install the win32-open3 library as a gem'
15
- task :install_gem do
16
- ruby 'win32-open3.gemspec'
17
- file = Dir["*.gem"].first
18
- sh "gem install #{file}"
11
+ Dir.chdir('ext'){
12
+ sh "#{make} install"
13
+ }
19
14
  end
20
15
 
21
16
  desc "Clean any build files for win32-open3"
22
17
  task :clean do
23
- Dir.chdir('ext') do
24
- if File.exists?('open3.so') || File.exists?('win32/open3.so')
25
- sh 'nmake distclean'
26
- rm 'win32/open3.so' if File.exists?('win32/open3.so')
27
- end
28
- end
18
+ Dir.chdir('ext') do
19
+ if File.exists?('open3.so') || File.exists?('win32/open3.so')
20
+ sh "#{make} distclean"
21
+ rm 'win32/open3.so' if File.exists?('win32/open3.so')
22
+ end
23
+ end
24
+ rm_rf 'lib'
29
25
  end
30
26
 
31
27
  desc "Build win32-open3 (but don't install it)"
32
28
  task :build => [:clean] do
33
- Dir.chdir('ext') do
34
- ruby 'extconf.rb'
35
- sh 'nmake'
36
- mv 'open3.so', 'win32' # For the test suite
37
- end
29
+ Dir.chdir('ext') do
30
+ ruby 'extconf.rb'
31
+ sh make
32
+ mv 'open3.so', 'win32' # For the test suite
33
+ end
38
34
  end
39
35
 
40
36
  desc "Run the sample program"
41
37
  task :example => [:build] do |t|
42
- Dir.chdir('examples'){
43
- sh 'ruby -I../ext open3_test.rb'
44
- }
38
+ Dir.chdir('examples'){
39
+ sh 'ruby -I../ext open3_test.rb'
40
+ }
45
41
  end
46
42
 
47
- desc "Build a binary gem"
48
- task :build_binary_gem => [:build] do
49
- mkdir_p 'lib/win32'
50
- mv 'ext/win32/open3.so', 'lib/win32'
43
+ namespace 'gem' do
44
+ desc 'Clean any build files and remove the .gem file'
45
+ task :clean do
46
+ Dir["*.gem"].each{ |f| File.delete(f) }
47
+ Dir.chdir('ext') do
48
+ if File.exists?('open3.so') || File.exists?('win32/open3.so')
49
+ sh "#{make} distclean"
50
+ rm 'win32/open3.so' if File.exists?('win32/open3.so')
51
+ end
52
+ end
53
+ end
51
54
 
52
- task :build_binary_gem => [:clean]
55
+ desc 'Build the gem'
56
+ task :build => [:clean] do
57
+ spec = eval(IO.read('win32-open3.gemspec'))
58
+ Gem::Builder.new(spec).build
59
+ end
53
60
 
54
- spec = Gem::Specification.new do |gem|
55
- gem.name = "win32-open3"
56
- gem.version = "0.3.0"
57
- gem.authors = ["Park Heesob", "Daniel Berger"]
58
- gem.email = "djberg96@gmail.com"
59
- gem.homepage = "http://www.rubyforge.org/projects/win32utils"
60
- gem.rubyforge_project = "win32utils"
61
- gem.platform = Gem::Platform::CURRENT
62
- gem.summary = 'Provides an Open3.popen3 implementation for MS Windows'
63
- gem.has_rdoc = true
64
- gem.test_files = Dir['test/test*']
61
+ desc 'Install the win32-open3 library as a gem'
62
+ task :install => [:build] do
63
+ file = Dir["*.gem"].first
64
+ sh "gem install #{file}"
65
+ end
65
66
 
66
- files = Dir["lib/win32/open3.so"] + Dir["test/*"]
67
- files.delete_if{ |f| f.include?('CVS') }
68
- gem.files = files
67
+ desc 'Build a binary gem'
68
+ task :binary => [:clean] do
69
+ Dir.chdir('ext') do
70
+ ruby 'extconf.rb'
71
+ sh make
72
+ end
69
73
 
70
- gem.extra_rdoc_files = [
71
- 'README',
72
- 'CHANGES',
73
- 'MANIFEST',
74
- 'doc/open3.txt',
75
- 'ext/win32/open3.c'
76
- ]
74
+ mkdir_p 'lib/win32'
75
+ mv 'ext/open3.so', 'lib/win32'
77
76
 
78
- gem.rubyforge_project = 'win32utils'
79
- gem.required_ruby_version = '>= 1.8.2'
77
+ spec = eval(IO.read('win32-open3.gemspec'))
78
+ spec.extensions = nil
79
+ spec.platform = Gem::Platform::CURRENT
80
80
 
81
- gem.description = <<-EOF
82
- The win32-open3 library provides a working implemetation of the open3
83
- library for MS Windows. In addition, it provides the Open4 class, which
84
- also returns pid information.
85
-
86
- Note that this library is largely unnecessary with Ruby 1.9.x because of
87
- its support for native threads.
88
- EOF
89
- end
81
+ spec.files = Dir['**/*'].reject{ |file|
82
+ file.include?('ext') || file.include?('git')
83
+ }
90
84
 
91
- Gem::Builder.new(spec).build
85
+ Gem::Builder.new(spec).build
86
+ end
92
87
  end
93
88
 
94
89
  Rake::TestTask.new('test') do |test|
95
- task :test => [:build]
96
- test.libs << 'ext'
97
- test.warning = true
98
- test.verbose = true
90
+ task :test => [:build]
91
+ test.libs << 'ext'
92
+ test.warning = true
93
+ test.verbose = true
99
94
  end
100
95
 
101
96
  task :test do
102
- Rake.application[:clean].execute
97
+ Rake.application[:clean].execute
103
98
  end
@@ -1,79 +1,79 @@
1
1
  = Description
2
- An open3 library for MS Windows.
2
+ An open3 library for MS Windows for the Ruby 1.8.x branch.
3
3
 
4
4
  = Synopsis
5
- require 'win32/open3'
5
+ require 'win32/open3'
6
6
 
7
- Open3.popen3('ver'){ |io_in, io_out, io_err|
8
- error = io_err.gets
9
- if error
10
- puts "Error: " + error.chomp
11
- exit
12
- end
13
- puts "Result: " + io_out.readlines.last.chomp
14
- }
7
+ Open3.popen3('ver'){ |io_in, io_out, io_err|
8
+ error = io_err.gets
9
+ if error
10
+ puts "Error: " + error.chomp
11
+ exit
12
+ end
13
+ puts "Result: " + io_out.readlines.last.chomp
14
+ }
15
15
 
16
16
  = Module functions
17
17
  Open3.popen3(command, mode='t', show=false)
18
18
 
19
19
  Open3.popen3(command, mode='t', show=false){ |io_in, io_out, io_err| ... }
20
20
 
21
- Executes 'command', returning an array of three IO handles representing
22
- STDIN, STDOUT and STDERR, respectively. In block form these IO handles
23
- are yielded back to the block and automatically closed at the end of the
24
- block.
21
+ Executes 'command', returning an array of three IO handles representing
22
+ STDIN, STDOUT and STDERR, respectively. In block form these IO handles
23
+ are yielded back to the block and automatically closed at the end of the
24
+ block.
25
25
 
26
- You may optionally pass a mode flag of 't' (text, the default) or 'b'
27
- (binary) to this method.
26
+ You may optionally pass a mode flag of 't' (text, the default) or 'b'
27
+ (binary) to this method.
28
28
 
29
- If the 'show' variable is set to true, then a console window is shown.
29
+ If the 'show' variable is set to true, then a console window is shown.
30
30
 
31
31
  Open4.popen4(command, mode='t', show=false)
32
32
 
33
33
  Open4.popen4(command, mode='t', show=false){ |io_in, io_out, io_err, pid| ... }
34
34
 
35
- Executes 'command', returning an array consisting of three IO handles,
36
- representing STDIN, STDOUT and STDERR, respectively, as well as the PID
37
- of the newly generated process. In block form these IO handles and pid
38
- are yielded back to the block and automatically closed at the end of the
39
- block.
35
+ Executes 'command', returning an array consisting of three IO handles,
36
+ representing STDIN, STDOUT and STDERR, respectively, as well as the PID
37
+ of the newly generated process. In block form these IO handles and pid
38
+ are yielded back to the block and automatically closed at the end of the
39
+ block.
40
40
 
41
- You may optionally pass a mode flag of 't' (text, the default) or 'b'
42
- (binary) to this method.
41
+ You may optionally pass a mode flag of 't' (text, the default) or 'b'
42
+ (binary) to this method.
43
43
 
44
- If the 'show' variable is set to true, then a console window is shown.
44
+ If the 'show' variable is set to true, then a console window is shown.
45
45
 
46
46
  = Notes
47
- This is a remake of Park Heesob's win32_popen package. It has been reworked
48
- in order to make the API (nearly) identical to the Open3 package currently
49
- included in the Ruby standard library.
47
+ This is a remake of Park Heesob's win32_popen package. It has been reworked
48
+ in order to make the API (nearly) identical to the Open3 package currently
49
+ included in the Ruby standard library.
50
50
 
51
- For now only the popen3 and popen4 methods have been included. In later
52
- releases we will probably add the popen2 and posix_popen methods back in.
51
+ For now only the popen3 and popen4 methods have been included. In later
52
+ releases we will probably add the popen2 and posix_popen methods back in.
53
53
 
54
- Ruby 1.9.x users will not generally need this library because of its support
55
- for native threads. That means you can use the open3 library that ships as
56
- part of the standard library.
54
+ Ruby 1.9.x users will not generally need this library because of its support
55
+ for native threads. That means you can use the open3 library that ships as
56
+ part of the standard library.
57
57
 
58
58
  = Acknowledgements
59
- Thanks go to Samuel Tesla and John-Mason Shackelford for their patches that
60
- enabled us to set Process::Status.
59
+ Thanks go to Samuel Tesla and John-Mason Shackelford for their patches that
60
+ enabled us to set Process::Status.
61
61
 
62
62
  = Known Bugs
63
- None that I know of. Please log any other bug reports on the RubyForge
64
- project page at http://www.rubyforge.net/projects/win32utils.
63
+ None that I know of. Please log any other bug reports on the RubyForge
64
+ project page at http://www.rubyforge.net/projects/win32utils.
65
65
 
66
66
  = License
67
- Artistic 2.0
67
+ Artistic 2.0
68
68
 
69
69
  = Copyright
70
- (C) 2003-2009 Daniel J. Berger, All Rights Reserved .
70
+ (C) 2003-2010 Daniel J. Berger, All Rights Reserved .
71
71
 
72
72
  = Warranty
73
- This package is provided "as is" and without any express or
74
- implied warranties, including, without limitation, the implied
75
- warranties of merchantability and fitness for a particular purpose.
76
-
73
+ This package is provided "as is" and without any express or
74
+ implied warranties, including, without limitation, the implied
75
+ warranties of merchantability and fitness for a particular purpose.
76
+
77
77
  = Authors
78
- Park Heesob
79
- Daniel J. Berger
78
+ Park Heesob
79
+ Daniel J. Berger
@@ -1,4 +1,5 @@
1
1
  require 'mkmf'
2
2
 
3
+ have_header('ruby/io.h')
3
4
  have_type('rb_pid_t', 'ruby.h') # For 1.8.3 and later
4
5
  create_makefile('win32/open3', 'win32')
@@ -4,8 +4,14 @@
4
4
  * Source for the win32-open3 extension.
5
5
  ***************************************************/
6
6
  #include "ruby.h"
7
+
8
+ #ifdef HAVE_RUBY_IO_H
9
+ #include "ruby/io.h"
10
+ #else
7
11
  #include "rubysig.h"
8
12
  #include "rubyio.h"
13
+ #endif
14
+
9
15
  #include "open3.h"
10
16
 
11
17
  #include <malloc.h>
@@ -14,11 +20,26 @@
14
20
  #include <fcntl.h>
15
21
  #include <sys/stat.h>
16
22
 
17
- /* Necessary to work with Ruby 1.8.3 or later */
23
+ // Necessary to work with Ruby 1.8.3 or later
18
24
  #ifdef HAVE_TYPE_RB_PID_T
19
25
  #define pid_t rb_pid_t
20
26
  #endif
21
27
 
28
+ // Ruby 1.9.x
29
+ #ifndef RSTRING_PTR
30
+ #define RSTRING_PTR(s) (RSTRING(s)->ptr)
31
+ #endif
32
+ #ifndef RSTRING_LEN
33
+ #define RSTRING_LEN(s) (RSTRING(s)->len)
34
+ #endif
35
+
36
+ #ifndef RARRAY_PTR
37
+ #define RARRAY_PTR(a) (RARRAY(a)->ptr)
38
+ #endif
39
+ #ifndef RARRAY_LEN
40
+ #define RARRAY_LEN(a) (RARRAY(a)->len)
41
+ #endif
42
+
22
43
  static VALUE win32_last_status = Qnil;
23
44
  static HANDLE pid_handle = NULL;
24
45
 
@@ -85,8 +106,8 @@ static VALUE io_close(VALUE val) {
85
106
  int i;
86
107
 
87
108
  for(i = 0; i < 3; i++){
88
- if(rb_funcall(RARRAY(val)->ptr[i], rb_intern("closed?"), 0) == Qfalse)
89
- rb_funcall(RARRAY(val)->ptr[i], rb_intern("close"), 0);
109
+ if(rb_funcall(RARRAY_PTR(val)[i], rb_intern("closed?"), 0) == Qfalse)
110
+ rb_funcall(RARRAY_PTR(val)[i], rb_intern("close"), 0);
90
111
  }
91
112
 
92
113
  return Qnil;
@@ -266,7 +287,7 @@ static void win32_set_last_status(const int status, const int pid)
266
287
 
267
288
  static void win32_pipe_finalize(OpenFile *file, int noraise)
268
289
  {
269
- int status;
290
+ DWORD status;
270
291
 
271
292
  if(file->f){
272
293
  fclose(file->f);
@@ -1,42 +1,36 @@
1
1
  require 'rubygems'
2
2
 
3
- spec = Gem::Specification.new do |gem|
4
- gem.name = 'win32-open3'
5
- gem.version = '0.3.1'
6
- gem.authors = ['Park Heesob', 'Daniel J. Berger']
7
- gem.email = 'djberg96@gmail.com'
8
- gem.homepage = 'http://www.rubyforge.org/projects/win32utils'
9
- gem.platform = Gem::Platform::RUBY
10
- gem.summary = 'Provides an Open3.popen3 implementation for MS Windows'
11
- gem.test_file = 'test/test_win32_open3.rb'
12
- gem.has_rdoc = true
13
- gem.license = 'Artistic 2.0'
3
+ Gem::Specification.new do |spec|
4
+ spec.name = 'win32-open3'
5
+ spec.version = '0.3.2'
6
+ spec.authors = ['Park Heesob', 'Daniel J. Berger']
7
+ spec.email = 'djberg96@gmail.com'
8
+ spec.homepage = 'http://www.rubyforge.org/projects/win32utils'
9
+ spec.platform = Gem::Platform::RUBY
10
+ spec.summary = 'Provides an Open3.popen3 implementation for MS Windows'
11
+ spec.test_file = 'test/test_win32_open3.rb'
12
+ spec.has_rdoc = true
13
+ spec.license = 'Artistic 2.0'
14
+ spec.extensions = ['ext/extconf.rb']
15
+ spec.files = Dir['**/*'].reject{ |f| f.include?('git') }
14
16
 
15
- gem.extra_rdoc_files = [
16
- 'CHANGES',
17
- 'README',
18
- 'MANIFEST',
19
- 'doc/open3.txt',
20
- 'ext/win32/open3.c'
21
- ]
17
+ spec.extra_rdoc_files = [
18
+ 'CHANGES',
19
+ 'README',
20
+ 'MANIFEST',
21
+ 'doc/open3.txt',
22
+ 'ext/win32/open3.c'
23
+ ]
22
24
 
23
- gem.rubyforge_project = 'win32utils'
24
- gem.required_ruby_version = '>= 1.8.2'
25
+ spec.rubyforge_project = 'win32utils'
26
+ spec.required_ruby_version = '< 1.9.0'
25
27
 
26
- gem.description = <<-EOF
27
- The win32-open3 library provides a working implemetation of the open3
28
- library for MS Windows. In addition, it provides the Open4 class, which
29
- also returns pid information.
28
+ spec.description = <<-EOF
29
+ The win32-open3 library provides a working implementation of the open3
30
+ library for MS Windows. In addition, it provides the Open4 class, which
31
+ also returns pid information.
30
32
 
31
- Note that this library is largely unnecessary with Ruby 1.9.x because of
32
- its support for native threads.
33
- EOF
34
-
35
- gem.extensions = ['ext/extconf.rb']
36
- gem.files = Dir['**/*'].delete_if{ |f| f.include?('CVS') }
37
- end
38
-
39
- if $PROGRAM_NAME == __FILE__
40
- Gem.manage_gems if Gem::RubyGemsVersion.to_f < 1.0
41
- Gem::Builder.new(spec).build
33
+ Note that this library is unnecessary with Ruby 1.9.x because of its
34
+ support for native threads.
35
+ EOF
42
36
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: win32-open3
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.1
4
+ version: 0.3.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Park Heesob
@@ -10,11 +10,11 @@ autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
12
 
13
- date: 2009-06-23 00:00:00 -06:00
13
+ date: 2010-01-23 00:00:00 -07:00
14
14
  default_executable:
15
15
  dependencies: []
16
16
 
17
- description: " The win32-open3 library provides a working implemetation of the open3\n library for MS Windows. In addition, it provides the Open4 class, which\n also returns pid information.\n \n Note that this library is largely unnecessary with Ruby 1.9.x because of\n its support for native threads.\n"
17
+ description: " The win32-open3 library provides a working implementation of the open3\n library for MS Windows. In addition, it provides the Open4 class, which\n also returns pid information.\n \n Note that this library is unnecessary with Ruby 1.9.x because of its\n support for native threads.\n"
18
18
  email: djberg96@gmail.com
19
19
  executables: []
20
20
 
@@ -49,9 +49,9 @@ require_paths:
49
49
  - lib
50
50
  required_ruby_version: !ruby/object:Gem::Requirement
51
51
  requirements:
52
- - - ">="
52
+ - - <
53
53
  - !ruby/object:Gem::Version
54
- version: 1.8.2
54
+ version: 1.9.0
55
55
  version:
56
56
  required_rubygems_version: !ruby/object:Gem::Requirement
57
57
  requirements:
@@ -62,7 +62,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
62
62
  requirements: []
63
63
 
64
64
  rubyforge_project: win32utils
65
- rubygems_version: 1.3.4
65
+ rubygems_version: 1.3.5
66
66
  signing_key:
67
67
  specification_version: 3
68
68
  summary: Provides an Open3.popen3 implementation for MS Windows