├── .expeditor ├── config.yml ├── run_windows_tests.ps1 ├── update_version.sh └── verify.pipeline.yml ├── .github ├── CODEOWNERS ├── ISSUE_TEMPLATE.md └── PULL_REQUEST_TEMPLATE.md ├── .gitignore ├── .rspec ├── CHANGELOG.md ├── CODE_OF_CONDUCT.md ├── Gemfile ├── README.md ├── Rakefile ├── VERSION ├── doc ├── daemon.txt └── service.txt ├── examples ├── demo_daemon.rb ├── demo_daemon_ctl.rb └── demo_services.rb ├── lib ├── win32-daemon.rb ├── win32-service.rb └── win32 │ ├── daemon.rb │ ├── service.rb │ └── windows │ ├── constants.rb │ ├── functions.rb │ ├── structs.rb │ └── version.rb ├── spec └── unit │ └── win32 │ └── service_spec.rb ├── tasks └── rspec.rb ├── test ├── test_win32_daemon.rb ├── test_win32_service.rb ├── test_win32_service_close_service_handle.rb ├── test_win32_service_configure.rb ├── test_win32_service_create.rb ├── test_win32_service_info.rb └── test_win32_service_status.rb └── win32-service.gemspec /.expeditor/config.yml: -------------------------------------------------------------------------------- 1 | # Documentation available at https://expeditor.chef.io/docs/getting-started/ 2 | --- 3 | 4 | # Slack channel in Chef Software slack to send notifications about build failures, etc 5 | slack: 6 | notify_channel: 7 | - sustaining-notify 8 | - chef-infra-notify 9 | 10 | # This publish is triggered by the `built_in:publish_rubygems` artifact_action. 11 | rubygems: 12 | - win32-service 13 | 14 | release_branches: 15 | - main: 16 | version_constraint: "*" 17 | 18 | github: 19 | # This deletes the GitHub PR branch after successfully merged into the release branch 20 | delete_branch_on_merge: true 21 | # The tag format to use (e.g. v1.0.0) 22 | version_tag_format: "win32-service-{{version}}" 23 | # allow bumping the minor release via label 24 | minor_bump_labels: 25 | - "Expeditor: Bump Version Minor" 26 | # allow bumping the major release via label 27 | major_bump_labels: 28 | - "Expeditor: Bump Version Major" 29 | 30 | changelog: 31 | rollup_header: Changes not yet released to rubygems.org 32 | 33 | 34 | subscriptions: 35 | # These actions are taken, in order they are specified, anytime a Pull Request is merged. 36 | - workload: pull_request_merged:{{github_repo}}:{{release_branch}}:* 37 | actions: 38 | - built_in:bump_version: 39 | ignore_labels: 40 | - "Expeditor: Skip Version Bump" 41 | - "Expeditor: Skip All" 42 | - bash:.expeditor/update_version.sh: 43 | only_if: built_in:bump_version 44 | - built_in:update_changelog: 45 | ignore_labels: 46 | - "Expeditor: Skip Changelog" 47 | - "Expeditor: Skip All" 48 | - built_in:build_gem: 49 | only_if: built_in:bump_version 50 | 51 | - workload: project_promoted:{{agent_id}}:* 52 | actions: 53 | - built_in:rollover_changelog 54 | - built_in:publish_rubygems 55 | 56 | pipelines: 57 | - verify: 58 | description: Pull Request validation tests 59 | public: true 60 | -------------------------------------------------------------------------------- /.expeditor/run_windows_tests.ps1: -------------------------------------------------------------------------------- 1 | # Stop script execution when a non-terminating error occurs 2 | $ErrorActionPreference = "Stop" 3 | 4 | # This will run ruby test on windows platform 5 | 6 | Write-Output "--- Bundle install" 7 | 8 | bundle config --local path vendor/bundle 9 | If ($lastexitcode -ne 0) { Exit $lastexitcode } 10 | 11 | bundle install --jobs=7 --retry=3 12 | If ($lastexitcode -ne 0) { Exit $lastexitcode } 13 | 14 | Write-Output "--- Bundle Execute" 15 | 16 | bundle exec rake 17 | If ($lastexitcode -ne 0) { Exit $lastexitcode } -------------------------------------------------------------------------------- /.expeditor/update_version.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # 3 | # After a PR merge, Chef Expeditor will bump the PATCH version in the VERSION file. 4 | # It then executes this file to update any other files/components with that new version. 5 | # 6 | 7 | set -evx 8 | 9 | sed -i -r "s/^(\s*)VERSION = \".+\"/\1VERSION = \"$(cat VERSION)\"/" lib/win32/windows/version.rb 10 | 11 | # Once Expeditor finshes executing this script, it will commit the changes and push 12 | # the commit as a new tag corresponding to the value in the VERSION file. 13 | -------------------------------------------------------------------------------- /.expeditor/verify.pipeline.yml: -------------------------------------------------------------------------------- 1 | --- 2 | expeditor: 3 | defaults: 4 | buildkite: 5 | retry: 6 | automatic: 7 | limit: 1 8 | timeout_in_minutes: 30 9 | 10 | steps: 11 | 12 | - label: run-specs-ruby-3.0-windows 13 | commands: 14 | - .expeditor/run_windows_tests.ps1 15 | 16 | expeditor: 17 | executor: 18 | docker: 19 | host_os: windows 20 | shell: ["powershell", "-Command"] 21 | image: rubydistros/windows-2019:3.0 22 | 23 | - label: run-specs-ruby-3.1-windows 24 | commands: 25 | - .expeditor/run_windows_tests.ps1 26 | 27 | expeditor: 28 | executor: 29 | docker: 30 | host_os: windows 31 | shell: ["powershell", "-Command"] 32 | image: rubydistros/windows-2019:3.1 -------------------------------------------------------------------------------- /.github/CODEOWNERS: -------------------------------------------------------------------------------- 1 | # Order is important. The last matching pattern has the most precedence. 2 | 3 | * @chef/chef-infra-reviewers @chef/chef-infra-approvers @chef/chef-infra-owners 4 | .expeditor/** @chef/infra-packages 5 | *.md @chef/docs-team -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | ## Description 2 | 3 | 4 | ## Gem Version 5 | 6 | 7 | ## Windows Version 8 | 9 | 10 | ## Replication Case 11 | 13 | -------------------------------------------------------------------------------- /.github/PULL_REQUEST_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | ### Description 2 | 3 | [Please describe what this change achieves] 4 | 5 | ### Issues Resolved 6 | 7 | [List any existing issues this PR resolves, or any Discourse or 8 | StackOverflow discussions that are relevant] 9 | 10 | ### Check List 11 | 12 | - [ ] New functionality includes tests 13 | - [ ] All tests pass 14 | - [ ] All commits have been signed-off for the Developer Certificate of Origin. See 15 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .autotest 2 | coverage 3 | .DS_Store 4 | pkg 5 | */tags 6 | *~ 7 | 8 | # you should check in your Gemfile.lock in applications, and not in gems 9 | Gemfile.lock 10 | Gemfile.local 11 | 12 | # Do not check in the .bundle directory, or any of the files inside it. Those files are specific to each particular machine, and are used to persist installation options between runs of the bundle install command. 13 | .bundle 14 | 15 | # ignore some common Bundler 'binstubs' directory names 16 | # http://gembundler.com/man/bundle-exec.1.html 17 | b/ 18 | binstubs/ 19 | 20 | # RVM and RBENV ruby version files 21 | .rbenv-version 22 | .rvmrc 23 | 24 | # Documentation 25 | _site/* 26 | .yardoc/ 27 | doc/ 28 | -------------------------------------------------------------------------------- /.rspec: -------------------------------------------------------------------------------- 1 | --color 2 | -fd 3 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # win32-service Change Log 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | ## [win32-service-2.3.2](https://github.com/chef/win32-service/tree/win32-service-2.3.2) (2021-11-08) 11 | 12 | #### Merged Pull Requests 13 | - daemon: Enable to handle user defined control codes [#74](https://github.com/chef/win32-service/pull/74) ([ashie](https://github.com/ashie)) 14 | - Add PR testing in Buildkite [#75](https://github.com/chef/win32-service/pull/75) ([tas50](https://github.com/tas50)) 15 | - Resolve the majority of chefstyle violations [#76](https://github.com/chef/win32-service/pull/76) ([tas50](https://github.com/tas50)) 16 | 17 | 18 | ## [win32-service-2.2.0](https://github.com/chef/win32-service/tree/win32-service-2.2.0) (2020-11-20) 19 | 20 | #### Merged Pull Requests 21 | - Refactor ::status with new methods [#64](https://github.com/chef/win32-service/pull/64) ([jasonwbarnett](https://github.com/jasonwbarnett)) 22 | 23 | ## [win32-service-2.1.6](https://github.com/chef/win32-service/tree/win32-service-2.1.6) (2020-08-17) 24 | 25 | #### Merged Pull Requests 26 | - Optimize requires for non-omnibus installs [#72](https://github.com/chef/win32-service/pull/72) ([tas50](https://github.com/tas50)) 27 | 28 | ## [win32-service-2.1.5](https://github.com/chef/win32-service/tree/win32-service-2.1.5) (2020-01-30) 29 | 30 | #### Merged Pull Requests 31 | - removed secondary SERVICE_STATUS_PROCESS class from structs [#71](https://github.com/chef/win32-service/pull/71) ([Dreweasland](https://github.com/Dreweasland)) 32 | 33 | ## [win32-service-2.1.4](https://github.com/chef/win32-service/tree/win32-service-2.1.4) (2019-04-17) 34 | 35 | #### Merged Pull Requests 36 | - Require Ruby 2.3 + misc changes [#63](https://github.com/chef/win32-service/pull/63) ([tas50](https://github.com/tas50)) 37 | - Bugfix: NoMethodError in Win32::Service.new [#67](https://github.com/chef/win32-service/pull/67) ([jasonwbarnett](https://github.com/jasonwbarnett)) 38 | 39 | ## [win32-service-2.1.2](https://github.com/chef/win32-service/tree/win32-service-2.1.2) (2019-03-22) 40 | 41 | #### Merged Pull Requests 42 | - Slim our gem size and unify our rake tasks [#54](https://github.com/chef/win32-service/pull/54) ([tas50](https://github.com/tas50)) 43 | - Require Ruby 2.2 or later [#58](https://github.com/chef/win32-service/pull/58) ([tas50](https://github.com/tas50)) 44 | - Add ::delayed_start method [#59](https://github.com/chef/win32-service/pull/59) ([jasonwbarnett](https://github.com/jasonwbarnett)) 45 | - DRY up the calls to ::CloseServiceHandle [#61](https://github.com/chef/win32-service/pull/61) ([jasonwbarnett](https://github.com/jasonwbarnett)) 46 | - Add open_sc_manager and open_service helpers + add in rspec testing [#62](https://github.com/chef/win32-service/pull/62) ([jasonwbarnett](https://github.com/jasonwbarnett)) 47 | - Bugfix: restore original behavior of ::delayed_start [#65](https://github.com/chef/win32-service/pull/65) ([jasonwbarnett](https://github.com/jasonwbarnett)) 48 | 49 | ## [win32-service-1.0.1](https://github.com/chef/win32-service/tree/win32-service-1.0.1) (2018-06-29) 50 | 51 | ## 0.8.10 - 11-Dec-2016 52 | * Fixed a bug where action resolution information was not correct. Thanks go 53 | to BXII-Dave for the spot and patch. 54 | 55 | ## 0.8.9 - 26-Jun-2016 56 | * Added the ffi-win32-extensions dependency. 57 | * Changed the way service dependencies are determined. 58 | * Removed the helper.rb file since it's no longer used. 59 | 60 | ## 0.8.8 - 24-Jun-2016 61 | * Fixed the function prototypes for CreateEvent and AdjustTokenPrivileges 62 | where I was using :bool instead of :int. 63 | * Updated the various FFI module wrapper names so that they're more distinctly 64 | namespaced. Avoids a clash with the win32-eventlog gem, and possibly others. 65 | * Discovered more places where QueryServiceConfig2 could fail while attempting 66 | to get failure actions and delayed auto start info. Instead of failing, 67 | these now set their respective data to nil. 68 | * A timeout value in our main observer thread was increased to potentially 69 | improve performance. Feedback welcome. 70 | * This gem is now signed. 71 | * Added the win32-service.rb and win32-daemon.rb files for convenience. 72 | * Use require_relative internally. 73 | * Added win32-security as a development dependency. It was already being used 74 | for tests but now it's actually part of the gemspec. 75 | * Many tests are now skipped unless run with administrative privileges, either 76 | because they require it, or because they otherwise take too long. 77 | * Gem related tasks in the Rakefile now assume Rubygems 2.x. 78 | * Added an appveyor.yml file. 79 | * The DemoDaemon example will create C:/Tmp if it doesn't already exist. 80 | 81 | ## 0.8.7 - 14-Jul-2014 82 | * Fixed a bug in the SERVICE_DELAYED_AUTO_START_INFO struct. It now returns 0 83 | or 1, though it still accepts true or false as arguments. Thanks go to 84 | Kartik Null Cating-Subramanian for the spot. 85 | 86 | ## 0.8.6 - 21-Aug-2014 87 | * Some internal changes that make stopping a service more robust. Thanks go 88 | to Ethan J. Brown for the patches. 89 | * Renamed the constants module to avoid name clashes. Thanks go to Michael 90 | Smith for the spot. 91 | 92 | ## 0.8.5 - 2-Jul-2014 93 | * The service type for Service.new no longer defaults to being an interactive 94 | process. This could cause process credential issues and wasn't very 95 | useful in practice anyway. Thanks go to Pierre Ynard for the report. 96 | * More tests skipped unless run with admin privileges. 97 | * Use relative_require instead of doing things manually. 98 | * Minor memory efficieny improvements. 99 | * Skip errors on ERROR_RESOURCE_TYPE_NOT_FOUND when getting service config info. Thanks go to Rob Reynolds for the patch. 100 | 101 | ## 0.8.4 - 23-Jan-2014 102 | * Cleaned up some unused and/or misnamed variables. 103 | * Automatically require devkit in Rakefile if mingw. 104 | * Added a patch that warns, instead of fails, if a resource is misconfigured 105 | in the Service.services method. Thanks go to Josh Cooper for the patch. 106 | * Fixed the service test that ensures that trying to start an already running 107 | service will raise an error. Thanks again to Jim Arnold for the patch. 108 | 109 | ## 0.8.3 - 1-Nov-2013 110 | * Fixed a bug where a service's state could be changed when merely 111 | interrogating the service. Thanks go to Glenn Sarti / Puppet Labs 112 | for the spot. 113 | * Fixed a bug where attempting to get the description of a service that 114 | has no description could raise an error. Now an empty string is returned. 115 | 116 | ## 0.8.2 - 13-Aug-2013 117 | * Fixed a bug in the Service.start method where it was not handling arguments 118 | properly. Thanks go to Sean Karlage for the spot. 119 | 120 | ## 0.8.1 - 2-Aug-2013 121 | * Fixed the failure actions code for the Service#configure method 122 | so that it is also using FFI. 123 | * An internal fix for the Daemon class was added. In short, you no longer 124 | need to, nor should you, call exit! in a service_stop method. Thanks go 125 | to Adrian Candaten for pointing out the issue in general. 126 | * Made FFI functions private. 127 | * Added Rake as a development dependency. 128 | * Removed an internal helper function that was no longer being used. 129 | 130 | ## 0.8.0 - 19-Jun-2013 131 | * Converted all code to use FFI. This includes the Daemon code, which means 132 | that it also now works with JRuby. 133 | 134 | ## 0.7.2 - 7-Sep-2011 135 | * Now works with mingw compiler by skipping __try and __finally if using 136 | mingw, or using them with mingw if the seh.h header is found. 137 | * The binary gem now contains binaries for both Ruby 1.8.7 and 1.9.2 using 138 | a simple wrapper. 139 | * Updated some Rake tasks. 140 | 141 | ## 0.7.1 - 9-Feb-2010 142 | * Compatibility fixes for 1.9.x. 143 | * Fixed a bug where the controls_accepted struct member was always nil. This 144 | has been fixed and now always returns an array. 145 | * Added 'pre-shutdown' as possible values for the list of controls accepted. 146 | * Changed test-unit from a runtime dependency to a development dependency. 147 | * Some tests were refactored to be more reliable. 148 | * Refactored the Rakefile and gemspec. 149 | 150 | ## 0.7.0 - 30-Jun-2009 151 | * INTERFACE CHANGE: The Service.new and Service.configure methods now accept 152 | a single hash argument only. The :service_name key is mandatory, while the 153 | :host key is optional. 154 | * Fixed a bug in the Service.services method where a segfault would occur if 155 | the binary_path_name was greater than 260 characters. The buffer size has 156 | been increased to 1024 characters. Thanks go to Dan Daniels for the spot. 157 | * Altered the Daemon class so that the Ruby interpreter was not invoked within 158 | the Service_Main function. The functions that close stdin, stdout and stderr 159 | are now called within the mainloop method. Thanks go to Tim Hanson for the 160 | spot and the patch. 161 | * Eliminated a minor build warning in daemon.c 162 | * License changed to Artistic 2.0, with corresponding gemspec update. 163 | * Added an uninstall rake task. 164 | * Updated the service_stop method in the demo_daemon.rb file, and added some 165 | additional comments. 166 | * The test files were renamed. 167 | * Several tests were updated and refactored to use Test::Unit 2.x. That 168 | library is now a dependency. 169 | * The 'uninstall' Rakefile task is now more verbose. 170 | 171 | ## 0.6.1 - 1-Jan-2008 172 | * The Service.services method now handles the scenario where a particular 173 | service may still exist, but its underlying registry entry has been deleted. 174 | In this case, most ServiceInfo struct members are set to nil and a warning 175 | is issued. 176 | * RDoc updates. 177 | 178 | ## 0.6.0 - 25-Nov-2007 179 | * The Service control class is now pure Ruby. The Daemon class is still C, 180 | however. That may change in the future. This means the windows-pr 181 | library is now a prerequisite. 182 | * The Service.new method has been altered in a way that is not backwards 183 | compatible. It is now the same as Service.create. 184 | * The Service.start method now properly handles arguments to the 185 | Daemon#service_main method. 186 | * The Daemon source code is now separate from the Service control class 187 | source code. That means you must require them separately, as needed. 188 | * The Daemon class should be much more responsive to service events now, 189 | especially service_stop. Many thanks go to Kevin Burge for the patch. 190 | * Added the Daemon.mainloop method as a shortcut for Daemon.new.mainloop. 191 | * The Daemon class now redirects STDIN, STDOUT and STDERR to the NUL device 192 | if they're still associated with a terminal when the service starts. This 193 | should help prevent Errno::EBADF errors. 194 | * The Service.services class method now supports the group parameter for 195 | versions of Ruby built with older compilers, i.e. it will now work with 196 | the one-click Ruby installer. 197 | * The Service.getdisplayname method was changed to Service.get_display_name. 198 | An alias has been provided for backwards compatibility. 199 | * The Service.getservicename method was changed to Service.get_service_name. 200 | An alias has been provided for backwards compatibility. 201 | * Added the Service.config_info method. 202 | * The Service.create and Service.configure methods now allow you to set 203 | failure actions, failure commands, and reset/retry periods. 204 | * Improved test suite. 205 | * Changed 'tdaemon.rb', 'tdaemon_ctl.rb' and 'service_test.rb' to 206 | 'demo_daemon.rb', 'demo_daemon_ctl.rb' and 'demo_services.rb', respectively. 207 | * Some refactoring and updates to the demo daemon and demo daemon controller 208 | examples. 209 | * The Win32Service struct is now ServiceInfo. 210 | * ServiceError is now Service::Error. 211 | * DaemonError is now Daemon::Error. 212 | * Some documentation improvements, corrections and updates. 213 | 214 | ## 0.5.2 - 25-Nov-2006 215 | * Fixed a bug in the Daemon class where the service event handling methods 216 | (most notably service_stop) did not work properly due to thread blocking 217 | issues. Many thanks go to Patrick Hurley for the patch. 218 | * Added the Daemon#running? method as helper method for your service_main 219 | method. 220 | * The 'interactive?' struct member is now just 'interactive'. This was 221 | supposed to have been in the last release but was somehow missed. Sorry. 222 | * Scrapped the old daemon_test.rb file and split it into two new files - 223 | tdaemon.rb and tdaemon_ctl.rb. In the process a few bugs were fixed. 224 | * Added a gemspec. 225 | * Documentation and test suite updates. 226 | 227 | ## 0.5.1 - 18-Jun-2006 228 | * Added the Service.open method. 229 | * The Service.new method now accepts a block, and automatically closes itself 230 | at the end of the block. 231 | * Fixed in a bug in the Service.create method where setting dependencies 232 | was not working properly. Thanks go to Scott Harper for the spot. 233 | * The 'interactive?' struct member is now just 'interactive' since Ruby no 234 | longer supports question marks in struct member names. UGH. 235 | * The block for Service#configure_service is no longer optional. 236 | * Replaced ClipSrv with W32Time for most of the test methods in tc_service.rb 237 | because it had a dependency that is disabled on most systems. 238 | * Added a tweak to the extconf.rb file to help with the test suite. 239 | * Some documentation updates and corrections. 240 | 241 | ## 0.5.0 - 26-Nov-2005 242 | * Added a service_init hook, and (internally) altered the way the service 243 | starts. This was done to deal with services that need to perform any 244 | initialization in the Daemon itself before the service starts. Previously 245 | this would result in the service timing out during startup. 246 | 247 | Thanks go to Jamey Cribbs for spotting the problem. 248 | 249 | * Modified the Daemon example, adding a service_init hook that does about 10 250 | seconds worth of initialization before finally starting. See the comments 251 | in examples\daemon_test.rb for more information. 252 | * Minor test and README changes. 253 | 254 | ## 0.4.6 - 24-May-2005 255 | * Fixed an initialization bug that could cause Daemons to fail unless the 256 | win32-service package was the last package require'd. 257 | * Altered the Service.start method. It now takes any number of arguments 258 | (after the service and host name). These arguments are passed to the 259 | service's Service_Main() function. 260 | * The Service.services method now returns an Array of ServiceStruct's in 261 | non-block form. 262 | * The Service.start, Service.pause, Service.resume, Service.stop and 263 | Service.delete methods now return the class (self), not 'true'. 264 | * Added the ability to add or configure the service description in 265 | Service#create_service or Service#configure, respectively. 266 | * Fixed a bug in the Service.start method where false positives could result. 267 | * Updated the ServiceStatus struct to include pid and service_flags on Win2k 268 | or later. 269 | * Unicode is now the default setting as far as internal string handling. It 270 | will still work fine with 'regular' text. 271 | * Added safe string handling for string input values. 272 | * Added rdoc comments into the C source. 273 | * Made the service.txt and daemon.txt files rdoc friendly. 274 | * Removed the service.rd and daemon.rd files. If you want html documentation, 275 | run rdoc over the service.txt and daemon.txt files. 276 | * The dreaded "code cleanup". 277 | 278 | ## 0.4.5 - 28-Feb-2005 279 | * Fixed an accessor bug in Service#create. Thanks go to Nathaniel Talbott 280 | for the spot. 281 | * Eliminated a warning that appeared starting in Ruby 1.8.2 regarding Struct 282 | redefinitions. 283 | * Moved 'examples' directory to toplevel directory. 284 | * Deleted the 'test2.rb' example. This was supplanted by the 'daemon_test.rb' 285 | script. 286 | * Renamed the 'test.rb' file to 'services_test.rb'. 287 | * Made this document rdoc friendly. 288 | 289 | ## 0.4.4 - 27-Aug-2004 290 | * Modified the Service class to use the newer allocation framework. The 291 | Daemon class already used this, hence no major version bump. 292 | * Fixed in a bug in the create_service() method with regards to the 293 | 'dependencies' option and null arguments (you no longer need to specify 294 | an empty array). 295 | 296 | ## 0.4.3 - 14-Aug-2004 297 | * Fixed the Daemon class by adding back the constants it needed in order to 298 | run. I accidentally broke this when I changed the Daemon class from being 299 | a subclass of Service to being its own class. 300 | * Added a separate test suite for the Daemon class, tc_daemon.rb, to help 301 | me from making that mistake ever again. :) 302 | * Updated the daemon_test.rb script a bit to report error messages should 303 | any occur. 304 | * Minor doc updates 305 | 306 | ## 0.4.2 - 10-Jul-2004 307 | * The Daemon class is no longer a subclass of Service. 308 | * Added the 'pid' and 'service_flags' struct members to the Win32Service 309 | struct. These members are only available to folks using Windows 2000 or 310 | later and who compile with VC++ 7.0 or later (including the .NET SDK). 311 | * The Service.services method now accepts a group name as an optional third 312 | argument. Again, you must be using Windows 2000 or later and compile with 313 | VC++ 7.0 or later (including the .NET SDK). 314 | * The deprecated STR2CSTR() functions were replaced with StringValuePtr(). 315 | This also means that as of this version, win32-service requires Ruby 316 | 1.8.0 or greater. 317 | * Moved the sample programs to doc/examples 318 | * Removed the .html files under /doc. You can generate that on your own if 319 | you like. 320 | 321 | ## 0.4.1 - 14-Mar-2004 322 | * Added the exists? class method and corresponding test suite additions. 323 | * Pushed the ServiceError and DaemonError classes under the Win32 module. 324 | * Normalized tc_service.rb so that it can be run outside of the test directory 325 | more easily. 326 | 327 | ## 0.4.0 - 9-Feb-2004 328 | * Changed "worker" method to "service_main" method. 329 | * Added event hooks for stop, pause, resume, etc. See the documentation for 330 | further details. (Thanks Park Heesob) 331 | * Some of the Daemon functions were raising ServiceError. They have been 332 | changed to DaemonError. 333 | * Updated the daemon_test.rb file to use the new event hooks. 334 | * Documentation additions and updates. 335 | 336 | ## 0.3.0 - 31-Jan-2004 337 | * Added a Daemon subclass. This allows you to run Ruby programs as a service. 338 | Please see the documentation for more details. (Thanks Park Heesob). This 339 | should be considered an ALPHA release. 340 | * The Win32ServiceError class has been renamed to just ServiceError. I felt 341 | the "Win32" was redundant, given that it's already under the Win32 module. 342 | * In some cases a bogus error description was being returned because the 343 | GetLastError() function was being called too late. This has been fixed. 344 | (Thanks Park Heesob). 345 | * The explicit garbage collection has been removed because what I thought was 346 | a memory leak was not, in fact, a memory leak. In addition, it was hurting 347 | performance badly. 348 | * The "\r\n" is now automatically stripped from error messages. This was 349 | causing slightly garbled error messages. (Thanks Park Heesob). 350 | * Added explicit closing of the Service Control Manager handle in the 351 | services() function for those rare cases where it may fail while reading 352 | service information. 353 | * Made some of the error strings a bit more descriptive. 354 | * Test suite and documentation additions, including a sample daemon program 355 | in the test directory called "daemon_test.rb". 356 | 357 | ## 0.2.2 - 15-Jan-2004 358 | * Fixed a mistake in the service_init declaration within Init_service(). 359 | * Fixed bug in the service_init function with regards to desired access. 360 | * Modified service_free() function to explicitly set the hSCManager handle 361 | to NULL and modified the service_close() method to test hSCManager handle 362 | for NULL value. This should eliminate accidentally trying to close an 363 | already closed handle, which may have happened as the result of a free() 364 | call. (Thanks Park Heesob). 365 | * Added explicit garbage collection in Service.services() method. 366 | * More explicit about closing open HANDLE's when error conditions arise. 367 | 368 | ## 0.2.1 - 2-Nov-2003 369 | * Made the exported less redundant and less verbose, e.g. 370 | Service::SERVICE_DISABLED is now just Service::DISABLED. The same is true 371 | for the service control constants, i.e. the 'SC_' has been removed. 372 | * Corresponding test suite changes. 373 | 374 | ## 0.2.0 - 16-Oct-2003 375 | * The constructor has been changed. It now only takes a machine name and a 376 | desired access for arguments. The keyword arguments are now part of the 377 | create_service method() and only in block form. See the documentation for 378 | more details. 379 | * Added a configure_service() and close() instance methods. 380 | * Added several new constants to allow finer control over created and 381 | configured services. 382 | * Added Win32ServiceError as an exception. All failures now raise this 383 | error instead of a vanilla StandardError. 384 | * Moved some common code into the service.h file. 385 | 386 | ## 0.1.0 - 10-Oct-2003 387 | - Initial release -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | Please refer to the Chef Community Code of Conduct at https://www.chef.io/code-of-conduct/ 2 | -------------------------------------------------------------------------------- /Gemfile: -------------------------------------------------------------------------------- 1 | source "https://rubygems.org" 2 | 3 | # Specify your gem's dependencies in win32-service.gemspec 4 | gemspec 5 | 6 | group(:development, :test) do 7 | gem "chefstyle", "1.6.2" 8 | gem "rake" 9 | end 10 | 11 | group :debug do 12 | gem "pry" 13 | gem "pry-byebug" 14 | gem "rb-readline" 15 | end -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # win32-service 2 | 3 | [![Gem Version](https://badge.fury.io/rb/win32-service.svg)](https://badge.fury.io/rb/win32-service) 4 | 5 | The win32-service library allows you to control or create MS Windows services. 6 | 7 | ## Installation 8 | 9 | gem install win32-service 10 | 11 | ## Usage 12 | 13 | ```ruby 14 | require 'win32/service' 15 | 16 | # Iterate over the available services 17 | Win32::Service.services do |service| 18 | p service 19 | end 20 | ``` 21 | 22 | ## More Documentation 23 | 24 | Please see the documentation in the 'doc' directory, or the gem documentation that was installed when you installed this library as a gem. 25 | 26 | ## Known Issues 27 | 28 | ### Problem: 29 | 30 | Service.delete causes "Unable to delete: The specified service has been marked for deletion." 31 | 32 | ### Troubleshooting: 33 | 34 | This can be caused by one of two things. Either you attempted to delete a running service without stopping it first, or you have the Services Administrative Tool (GUI) open. In the former case, the solution is to first stop the service if it's running. In the latter, close the Services GUI admin tool before deleting. 35 | 36 | ### Problem: 37 | 38 | Service.start causes, "The service did not respond to the start or control request in a timely fashion." 39 | 40 | ### Troubleshooting: 41 | 42 | The best way to debug your services is to wrap your entire Daemon subclass in a begin/end block and send error messages to a file. That should give a good clue as to the nature of the problem. The most probable culprits are: 43 | 44 | - You forgot to require 'win32/daemon' in your Daemon code. 45 | 46 | - You've tried to require a library that's not in your $LOAD_PATH. Make sure that your require statements are inside the begin/rescue block so that you can easily find those mistakes. 47 | 48 | - Your have a bad binary path name. Be sure to use an absolute path name for the binary path name, including the full path to the Ruby interpreter, e.g. 'c:\ruby\bin\ruby' instead of just 'ruby'. 49 | 50 | - You've got a syntax error in your code somewhere. 51 | 52 | ## See Also 53 | 54 | ruby-wmi 55 | 56 | ## Future Plans 57 | 58 | Add service_session_change hook 59 | 60 | ## Copyright 61 | 62 | (C) 2003-2018, Daniel J. Berger, All Rights Reserved 63 | 64 | ## License 65 | 66 | Artistic 2.0 67 | 68 | ## Warranty 69 | 70 | This package is provided "as is" and without any express or implied warranties, including, without limitation, the implied warranties of merchantability and fitness for a particular purpose. 71 | 72 | ## Authors 73 | 74 | - Daniel J. Berger 75 | - Park Heesob 76 | -------------------------------------------------------------------------------- /Rakefile: -------------------------------------------------------------------------------- 1 | require "bundler/gem_tasks" 2 | require "rake" 3 | require "rake/clean" 4 | require "rake/testtask" 5 | require "rbconfig" 6 | require_relative "tasks/rspec" 7 | include RbConfig 8 | 9 | CLEAN.include( 10 | "**/*.gem", # Gem files 11 | "**/*.rbc" # Rubinius 12 | ) 13 | 14 | namespace :example do 15 | desc "Run the services example program." 16 | task :services do 17 | sh "ruby -Ilib examples/demo_services.rb" 18 | end 19 | end 20 | 21 | namespace "test" do 22 | desc "Run all tests for the win32-service library" 23 | Rake::TestTask.new("all") do |t| 24 | t.verbose = true 25 | t.warning = true 26 | end 27 | 28 | desc "Run the tests for the Win32::Daemon class" 29 | Rake::TestTask.new("daemon") do |t| 30 | task :daemon 31 | t.verbose = true 32 | t.warning = true 33 | t.test_files = FileList["test/test_win32_daemon.rb"] 34 | end 35 | 36 | namespace "service" do 37 | desc "Run the tests for the Win32::Service class" 38 | Rake::TestTask.new("all") do |t| 39 | t.verbose = true 40 | t.warning = true 41 | t.test_files = FileList["test/test_win32_service*.rb"] 42 | end 43 | 44 | Rake::TestTask.new("configure") do |t| 45 | t.verbose = true 46 | t.warning = true 47 | t.test_files = FileList["test/test_win32_service_configure.rb"] 48 | end 49 | 50 | Rake::TestTask.new("control") do |t| 51 | t.verbose = true 52 | t.warning = true 53 | t.test_files = FileList["test/test_win32_service.rb"] 54 | end 55 | 56 | Rake::TestTask.new("create") do |t| 57 | t.verbose = true 58 | t.warning = true 59 | t.test_files = FileList["test/test_win32_service_create.rb"] 60 | end 61 | 62 | Rake::TestTask.new("info") do |t| 63 | t.verbose = true 64 | t.warning = true 65 | t.test_files = FileList["test/test_win32_service_info.rb"] 66 | end 67 | 68 | Rake::TestTask.new("status") do |t| 69 | t.verbose = true 70 | t.warning = true 71 | t.test_files = FileList["test/test_win32_service_status.rb"] 72 | end 73 | 74 | Rake::TestTask.new("close_service_handle") do |t| 75 | t.verbose = true 76 | t.warning = true 77 | t.test_files = FileList["test/test_win32_service_close_service_handle.rb"] 78 | end 79 | end 80 | 81 | task :all do 82 | Rake.application[:clean].execute 83 | end 84 | 85 | task :daemon do 86 | Rake.application[:clean].execute 87 | end 88 | end 89 | 90 | task :console do 91 | require "irb" 92 | require "irb/completion" 93 | ARGV.clear 94 | IRB.start 95 | end 96 | 97 | task default: "test:all" 98 | -------------------------------------------------------------------------------- /VERSION: -------------------------------------------------------------------------------- 1 | 2.3.2 -------------------------------------------------------------------------------- /doc/daemon.txt: -------------------------------------------------------------------------------- 1 | = Description 2 | The Daemon class is a wrapper class that allows you to run your code as a 3 | Windows service. 4 | 5 | = Synopsis 6 | class Daemon 7 | def service_main 8 | while running? 9 | sleep 3 10 | File.open("c:\\test.log", "a"){ |f| f.puts "service is running" } 11 | end 12 | end 13 | end 14 | 15 | Daemon.mainloop 16 | 17 | = Singleton Methods 18 | Daemon.mainloop 19 | This is the method that actually puts your code into a loop and allows it 20 | to run as a service. The code that is actually run while in the mainloop 21 | is what you defined in the Daemon#service_main method. 22 | 23 | = Instance Methods 24 | Daemon#running? 25 | Returns whether or not the daemon is running. This is just a shortcut 26 | for checking if the state is RUNNING, PAUSED or IDLE. 27 | 28 | This is typically used within your service_main method. See the 29 | demo_daemon.rb file in the 'examples' directory for an example of how it's 30 | used in practice. 31 | 32 | Daemon#service_init 33 | Any code defined defined within this method occurs before service_main is 34 | reached. Any initialization code that takes more than two seconds to 35 | execute should be placed here. Otherwise, your service may timeout when 36 | you try to start it. 37 | 38 | Daemon#service_main(*args) 39 | You are expected to define your own service_main() method. The code 40 | defined in this method is the code that will run while running as a 41 | service. 42 | 43 | Any +args+ passed to Service.start are passed to this method. 44 | 45 | Daemon#state 46 | Returns the current state of the Daemon. For a list of valid states, see 47 | the Constants section below. 48 | 49 | = Signal Event Hooks 50 | These methods are called if defined within your Daemon class, and the 51 | appropriate signal is received by your service. 52 | 53 | Daemon#service_stop 54 | Called if the service receives a SERVICE_CONTROL_STOP signal. This is 55 | what the Service.stop() method sends. 56 | 57 | Daemon#service_pause 58 | Called if the service receives a SERVICE_CONTROL_PAUSE signal. This is 59 | what the Service.pause() method sends. 60 | 61 | Daemon#service_resume 62 | Called if the service receives a SERVICE_CONTROL_CONTINUE signal. This 63 | is what the Service.resume() method sends. 64 | 65 | Daemon#service_interrogate 66 | Called if the service receives a SERVICE_CONTROL_INTERROGATE signal. This 67 | notifies a service that it should report its current status information to 68 | the service control manager. 69 | 70 | Daemon#service_shutdown 71 | Called if the service receives a SERVICE_CONTROL_SHUTDOWN signal. 72 | 73 | Daemon#service_netbindadd 74 | Called if the service receives a SERVICE_CONTROL_NETBINDADD signal. This 75 | notifies a network service that there is a new component for binding. 76 | 77 | Daemon#service_netbinddisable 78 | Called if the service receives a SERVICE_CONTROL_NETBINDDISABLE signal. 79 | This notifies a network service that one of its bindings has been 80 | disabled. 81 | 82 | Daemon#service_netbindenable 83 | Called if the service receives a SERVICE_CONTROL_NETBINDENABLE signal. 84 | This Notifies a network service that a disabled binding has been enabled. 85 | 86 | Daemon#service_netbindremove 87 | Called if the service receives a SERVICE_CONTROL_NETBINDREMOVE signal. 88 | This notifies a network service that that a component for binding has 89 | been removed. 90 | 91 | Daemon#service_paramchange 92 | Called if the service receives a SERVICE_CONTROL_PARAMCHANGE signal. 93 | This notifies a service that its startup parameters have changed. 94 | 95 | Daemon#service_user_defined_control(code) 96 | Called if the service receives a user-defined control code (128 to 255). 97 | 98 | = Constants 99 | 100 | === Service state constants 101 | Daemon::CONTINUE_PENDING 102 | The service continue is pending. 103 | 104 | Daemon::PAUSE_PENDING 105 | The service pause is pending. 106 | 107 | Daemon::PAUSED 108 | The service is paused (but not STOPPED). 109 | 110 | Daemon::RUNNING 111 | The service is running. 112 | 113 | Daemon::START_PENDING 114 | The service is starting (but is not yet in a RUNNING state). 115 | 116 | Daemon::STOP_PENDING 117 | The service is stopping (but is not yet in a STOPPED state). 118 | 119 | Daemon::STOPPED 120 | The service is not running. 121 | 122 | Daemon::IDLE 123 | The service is running, in an idle state. This is a custom state that 124 | we added that gets around a thread blocking issue. 125 | 126 | = Notes 127 | You must create a service before you can actually run it. Look in the 128 | examples directory for the files 'demo_daemon.rb' and 'demodaemon_ctl.rb'. 129 | They're small and straightforward examples of how to control, install and 130 | setup your own Daemon. 131 | 132 | = Known Bugs 133 | None known. Please report any bugs you find on the issue tracker at 134 | https//github.com/djberg96/win32-service 135 | 136 | = Future Plans 137 | None at this time. 138 | 139 | Suggestions welcome. Please post them on the github project page at 140 | https//github.com/djberg96/win32-service 141 | 142 | = Acknowledgements 143 | Many thanks go to Patrick Hurley for providing the fix for the thread 144 | blocking issue for the original C code. Thanks also go to Kevin Burge for 145 | his patch that solved service responsiveness issues. 146 | 147 | = Copyright 148 | (C) 2003-2016 Daniel J. Berger, All Rights Reserved 149 | 150 | = License 151 | Artistic 2.0 152 | 153 | = Warranty 154 | This package is provided "as is" and without any express or 155 | implied warranties, including, without limitation, the implied 156 | warranties of merchantability and fitness for a particular purpose. 157 | 158 | = Author(s) 159 | * Daniel J. Berger 160 | * Park Heesob 161 | -------------------------------------------------------------------------------- /doc/service.txt: -------------------------------------------------------------------------------- 1 | = Description 2 | An interface for MS Windows Services. 3 | 4 | = Prerequisites 5 | ffi 1.0 or later 6 | 7 | This library is only supported for the Windows NT family of operating 8 | systems, e.g. 2000, XP, 2003, etc. It is NOT supported (and won't 9 | work) for any version of DOS or Windows 95/98/ME. It is also not 10 | supported on NT 4, as that platform is defunct. 11 | 12 | It should work on Windows XP Home, but is not officially supported for 13 | that platform. 14 | 15 | = Synopsis 16 | require "win32/service" 17 | include Win32 18 | 19 | # Create a new service 20 | Service.create( 21 | :service_name => 'some_service', 22 | :service_type => Service::WIN32_OWN_PROCESS, 23 | :description => 'A custom service I wrote just for fun' 24 | :start_type => Service::AUTO_START, 25 | :error_control => Service::ERROR_NORMAL, 26 | :binary_path_name => 'C:\path\to\some_service.exe', 27 | :load_order_group => 'Network', 28 | :dependencies => ['W32Time','Schedule'] 29 | :service_start_name => 'SomeDomain\\User', 30 | :password => 'XXXXXXX', 31 | :display_name => 'This is some service' 32 | ) 33 | 34 | # Configure a service that already exists 35 | Service.configure(:display_name => "My Bar Service") 36 | 37 | Service.start("foo") 38 | Service.pause("foo") 39 | Service.resume("foo") 40 | Service.stop("foo") 41 | 42 | Service.delete("foo") 43 | 44 | Service.get_display_name("Schedule") # "Task Scheduler" 45 | Service.get_service_name("ClipBook") # "ClipSrv" 46 | 47 | Service.status('W32Time') => 48 | 49 | # Enumerate over all services, inspecting each struct 50 | Service.services{ |s| 51 | puts s.inspect 52 | } 53 | 54 | = Class Methods 55 | Service.new(options={}) 56 | Creates a new service. The +options+ parameter is a hash that can 57 | contain any of the following parameters, and their default values: 58 | 59 | KEY DEFAULT 60 | * service_name => nil (mandatory) 61 | * host => nil 62 | * display_name => service_name 63 | * desired_access => Service::ALL_ACCESS 64 | * service_type => Service::WIN32_OWN_PROCESS|Service::INTERACTIVE_PROCESS 65 | * start_type => Service::DEMAND_START 66 | * error_control => Service::ERROR_NORMAL 67 | * binary_path_name => nil 68 | * load_order_group => nil 69 | * dependencies => nil 70 | * service_start_name => nil 71 | * password => nil 72 | * description => nil 73 | 74 | Service.configure(options={}) 75 | Configures an existing service. The +options+ parameter is a hash that can 76 | contain any of the following parameters: 77 | 78 | * service_name (mandatory) 79 | * host 80 | * service_type 81 | * start_type 82 | * error_control 83 | * binary_path_name 84 | * load_order_group 85 | * dependencies 86 | * service_start_name 87 | * password (used with service_start_name) 88 | * display_name 89 | * description 90 | 91 | Service.config_info(service, host=nil) 92 | Returns a ServiceConfigInfo struct containing the configuration information 93 | about +service+ on +host+, or the local host if no host is specified. 94 | 95 | Service.create 96 | Alias for Service.new 97 | 98 | Service.delete(service, host=nil) 99 | Deletes the specified +service+ on +host+. If no host is given, 100 | then it deletes it on the local machine. 101 | 102 | Service.exists?(service) 103 | Returns true if the specified service exists, false otherwise. 104 | 105 | Service.pause(service, host=nil) 106 | Pauses the specified +service+ on +host+, or the local machine if 107 | no host is provided. 108 | 109 | Service.resume(service, host=nil) 110 | Resumes the specified +service+ on +host+, or the local machine if 111 | no host is specified. 112 | 113 | Service.services(host=nil, group=nil){ |struct| ... } 114 | Enumerates over a list of service types on host, or the local 115 | machine if no host is specified, yielding a Win32Service struct for each 116 | service. 117 | 118 | If a 'group' is specified, then only those services that belong to 119 | that group are enumerated. If an empty string is provided, then only 120 | services that do not belong to any group are enumerated. If this parameter 121 | is nil, group membership is ignored and all services are enumerated. 122 | 123 | The 'group' option is only available on Windows 2000 or later, and only 124 | if compiled with VC++ 7.0 or later, or the .NET SDK. The Win32Service 125 | struct contains the following members: 126 | 127 | * service_name 128 | * display_name 129 | * service_type 130 | * current_state 131 | * controls_accepted 132 | * win32_exit_code 133 | * service_specific_exit_code 134 | * check_point 135 | * wait_hint 136 | * binary_path_name 137 | * start_type 138 | * error_control 139 | * load_order_group 140 | * tag_id 141 | * start_name 142 | * dependencies 143 | * description 144 | * interactive? 145 | * pid (Win2k or later) 146 | * service_flags (Win2k or later) 147 | 148 | Note that the 'pid' and 'service_flags' members are only available on 149 | Windows 2000 or later, and only if built with VC++ 7.0 or later (or the 150 | .NET SDK). 151 | 152 | Service.start(service, host=nil, *args) 153 | Starts the specified +service+ on +host+, or the local machine if no 154 | host is specified. Any +args+ passed here are passed as start parameters 155 | to the service. 156 | 157 | Service.status(service) 158 | Returns a Win32ServiceStatus struct for the specified service (or 159 | raises a Win32::ServiceError if not found). The Win32ServiceStatus 160 | struct contains the following members. 161 | 162 | * service_type 163 | * current_state 164 | * controls_accepted 165 | * win32_exit_code 166 | * service_specific_exit_code 167 | * check_point 168 | * wait_hint 169 | * interactive? 170 | 171 | Service.stop(service, host=nil) 172 | Stops the specified +service+ on +host+, or the local machine if no 173 | host is specified. 174 | 175 | = Create and configure options 176 | binary_path_name 177 | The binary to be used for the service. The path must be the fully 178 | qualified path name. A path that contains a space must be quoted so that 179 | it is correctly interpreted. The path may also include arguments to the 180 | service entry point (typically the 'main' function). 181 | 182 | dependencies 183 | Any dependencies the service has in order to run. This can be a string 184 | or an array of strings. 185 | 186 | description 187 | A text string describing the service. 188 | 189 | display_name 190 | The display name to be used by user interface programs to identify the 191 | service. The string has a maximum length of 256 characters. Case 192 | sensitivity is preserved. 193 | 194 | The default is to set the display name to the same string as the 195 | service name. 196 | 197 | error_control 198 | The error control for the service. The default is Service::ERROR_NORMAL. 199 | 200 | See the "Error Control Contants" section for available options and their 201 | meanings. 202 | 203 | load_order_group 204 | The load order group, a string that names the load ordering group of 205 | which this service is a member. The default is nil. 206 | 207 | password 208 | Sets the passsword to the account name specified in the Service#start_name 209 | method. By default, this value is set to nil, which is appropriate if 210 | the account has no password or if the service runs in the 211 | 'LocalService', 'NetworkService', or 'LocalSystem' account. 212 | 213 | Note that passwords are ignored for driver services. 214 | 215 | service_name 216 | The service name for the service. This value must be set in order 217 | to create a service. The string has a maximum length of 256 characters. 218 | 219 | service_type 220 | The service type for the service. The default is 221 | Service::WIN32_OWN_PROCESS | Service::INTERACTIVE_PROCESS. 222 | 223 | See the "Service Type Contants" section for available options and their 224 | meanings. 225 | 226 | start_name 227 | Sets the name of the account under which the service should run. 228 | By default the 'LocalSystem' account is used. 229 | 230 | start_type 231 | The start type for the service. The default is Service::DEMAND_START. 232 | 233 | See the "Start Type Contants" section for available options and their 234 | meanings. 235 | 236 | = Constants 237 | 238 | === Standard Constants 239 | VERSION 240 | The current version number of this package, returned as a string. 241 | 242 | === Desired Access Constants 243 | Service::MANAGER_ALL_ACCESS 244 | Includes STANDARD_RIGHTS_REQUIRED, in addition to all access rights 245 | in the table. 246 | 247 | Service::MANAGER_CREATE_SERVICE 248 | Required to call the CreateService function to create a service object 249 | and add it to the database. 250 | 251 | Service::MANAGER_CONNECT 252 | Required to connect to the service control manager. 253 | 254 | Service::MANAGER_ENUMERATE_SERVICE 255 | Required to call the EnumServicesStatus function to list the services 256 | that are in the database. 257 | 258 | Service::MANAGER_LOCK 259 | Required to call the LockServiceDatabase function to acquire a lock on the 260 | database. 261 | 262 | Service::MANAGER_BOOT_CONFIG 263 | Required to call the NotifyBootConfigStatus() (internal) function. Not 264 | defined with all compilers. 265 | 266 | Service::MANAGER_QUERY_LOCK_STATUS 267 | Required to call the QueryServiceLockStatus() (internal) function to 268 | retrieve the lock status information for the database. 269 | 270 | === Service Type Constants 271 | Service::FILE_SYSTEM_DRIVER 272 | File system driver service. 273 | 274 | Service::KERNEL_DRIVER 275 | Driver service. 276 | 277 | Service::WIN32_OWN_PROCESS 278 | Service that runs in its own process. 279 | 280 | Service::WIN32_SHARE_PROCESS 281 | Service that shares a process with one or more other services. 282 | 283 | Service::INTERACTIVE_PROCESS 284 | The service can interact with the desktop. This can only be used if 285 | either SERVICE_WIN32_OWN_PROCESS or SERVICE_WIN32_SHARE_PROCESS is 286 | specified as well, and the service is running in the context of the 287 | LocalSystem account (which is the default for this module, btw). 288 | 289 | === Start Type Constants 290 | Service::AUTO_START 291 | A service started automatically by the service control manager during 292 | system startup. 293 | 294 | Service::BOOT_START 295 | A device driver started by the system loader. This value is valid only 296 | for driver services. 297 | 298 | Service::DEMAND_START 299 | A service started by the service control manager when a process calls 300 | the StartService() function. 301 | 302 | Service::DISABLED 303 | A service that cannot be started. Attempts to start the service result 304 | in an error. 305 | 306 | Service::SYSTEM_START 307 | A device driver started by the IoInitSystem() function. This value is 308 | valid only for driver services. 309 | 310 | === Error Control Constants 311 | Service::ERROR_IGNORE 312 | The startup program logs the error but continues the startup operation. 313 | 314 | Service::ERROR_NORMAL 315 | The startup program logs the error and puts up a message box pop-up but 316 | continues the startup operation. 317 | 318 | Service::ERROR_SEVERE 319 | The startup program logs the error. If the last-known-good configuration 320 | is being started, the startup operation continues. Otherwise, the system 321 | is restarted with the last-known-good configuration. 322 | 323 | Service::ERROR_CRITICAL 324 | The startup program logs the error, if possible. If the last-known-good 325 | configuration is being started the startup operation fails. Otherwise, 326 | the system is restarted with the last-known-good configuration. 327 | 328 | = Notes 329 | See the MSDN API with regards to CreateService(), etc at http://www.msdn.com. 330 | 331 | Some API ideas taken (or not) from both Python's win32serviceutil.py and 332 | Perl's Win32::Service module. 333 | 334 | I don't truly understand how to allow a tag_id in the create_service() 335 | method, so for now it's set to NULL automatically. Suggestions welcome. 336 | 337 | = Known Bugs 338 | There may be a failure in the test suite if the W32Time dependency is 339 | not started. 340 | 341 | If you find any bugs please log them on the github project page at 342 | https://github.com/djberg96/win32-service 343 | 344 | = Acknowledgements 345 | Many thanks go to Patrick Hurley for providing the fix for the thread 346 | blocking issue in the original C code. Thanks also go to Kevin Burge for 347 | his patch that solved service responsiveness issues. 348 | 349 | = Future Plans 350 | Add Tag_ID support. 351 | Add ability to create or modify service failure actions. 352 | 353 | = Copyright 354 | (C) 2003-2016, Daniel J. Berger, All Rights Reserved 355 | 356 | = Warranty 357 | This package is provided "as is" and without any express or 358 | implied warranties, including, without limitation, the implied 359 | warranties of merchantability and fitness for a particular purpose. 360 | 361 | == Authors 362 | * Daniel J. Berger 363 | * Park Heesob 364 | -------------------------------------------------------------------------------- /examples/demo_daemon.rb: -------------------------------------------------------------------------------- 1 | LOG_FILE = 'C:\\Tmp\\win32_daemon_test.log' 2 | 3 | begin 4 | require "rubygems" 5 | require "win32/daemon" 6 | include Win32 7 | 8 | class DemoDaemon < Daemon 9 | # This method fires off before the +service_main+ mainloop is entered. 10 | # Any pre-setup code you need to run before your service's mainloop 11 | # starts should be put here. Otherwise the service might fail with a 12 | # timeout error when you try to start it. 13 | # 14 | def service_init 15 | Dir.mkdir("C:/Tmp") unless File.exist?("C:/Tmp") 16 | 10.times { |i| 17 | File.open(LOG_FILE , "a") { |f| f.puts("#{i}") } 18 | sleep 1 19 | } 20 | end 21 | 22 | # This is the daemon's mainloop. In other words, whatever runs here 23 | # is the code that runs while your service is running. Note that the 24 | # loop is not implicit. 25 | # 26 | # You must setup a loop as I've done here with the 'while running?' 27 | # code, or setup your own loop. Otherwise your service will exit and 28 | # won't be especially useful. 29 | # 30 | # In this particular case, I've setup a loop to append a short message 31 | # and timestamp to a file on your C: drive every 20 seconds. Be sure 32 | # to stop the service when you're done! 33 | # 34 | def service_main(*args) 35 | msg = "service_main entered at: " + Time.now.to_s 36 | 37 | File.open(LOG_FILE, "a") { |f| 38 | f.puts msg 39 | f.puts "Args: " + args.join(",") 40 | } 41 | 42 | # While we're in here the daemon is running. 43 | while running? 44 | if state == RUNNING 45 | sleep 20 46 | msg = "Service is running as of: " + Time.now.to_s 47 | File.open(LOG_FILE, "a") { |f| f.puts msg } 48 | else # PAUSED or IDLE 49 | sleep 0.5 50 | end 51 | end 52 | 53 | # We've left the loop, the daemon is about to exit. 54 | 55 | File.open(LOG_FILE, "a") { |f| f.puts "STATE: #{state}" } 56 | 57 | msg = "service_main left at: " + Time.now.to_s 58 | 59 | File.open(LOG_FILE, "a") { |f| f.puts msg } 60 | end 61 | 62 | # This event triggers when the service receives a signal to stop. 63 | # 64 | # NOTE: Older versions of this code used an explicit exit! call 65 | # to force the Ruby interpreter to exit. Don't do that. It is no 66 | # longer required and, in fact, may cause issues. 67 | # 68 | def service_stop 69 | msg = "Received stop signal at: " + Time.now.to_s 70 | File.open(LOG_FILE, "a") { |f| f.puts msg } 71 | end 72 | 73 | # This event triggers when the service receives a signal to pause. 74 | # 75 | def service_pause 76 | msg = "Received pause signal at: " + Time.now.to_s 77 | File.open(LOG_FILE, "a") { |f| f.puts msg } 78 | end 79 | 80 | # This event triggers when the service receives a signal to resume 81 | # from a paused state. 82 | # 83 | def service_resume 84 | msg = "Received resume signal at: " + Time.now.to_s 85 | File.open(LOG_FILE, "a") { |f| f.puts msg } 86 | end 87 | end 88 | 89 | # Create an instance of the Daemon and put it into a loop. I borrowed the 90 | # method name 'mainloop' from Tk, btw. 91 | # 92 | DemoDaemon.mainloop 93 | rescue Exception => err 94 | File.open(LOG_FILE, "a") { |fh| fh.puts "Daemon failure: #{err}" } 95 | raise 96 | end 97 | -------------------------------------------------------------------------------- /examples/demo_daemon_ctl.rb: -------------------------------------------------------------------------------- 1 | ############################################################################ 2 | # demo_daemon_ctl.rb 3 | # 4 | # This is a command line script for installing and/or running a small 5 | # Ruby program as a service. The service will simply write a small bit 6 | # of text to a file every 20 seconds. It will also write some text to the 7 | # file during the initialization (service_init) step. 8 | # 9 | # It should take about 10 seconds to start, which is intentional - it's a test 10 | # of the service_init hook, so don't be surprised if you see "one moment, 11 | # start pending" about 10 times on the command line. 12 | # 13 | # The file in question is C:\Tmp\win32_daemon_test.log. Feel free to delete 14 | # it when you're finished. 15 | # 16 | # To run the service, you must install it first. 17 | # 18 | # Usage: ruby demo_daemon_ctl.rb