win32-eventlog 0.5.3 → 0.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/CHANGES +234 -226
- data/MANIFEST +19 -16
- data/README +78 -68
- data/Rakefile +6 -1
- data/doc/tutorial.txt +136 -136
- data/examples/example_notify.rb +23 -23
- data/examples/example_read.rb +83 -83
- data/examples/example_write.rb +64 -64
- data/lib/win32/eventlog.rb +1146 -1157
- data/lib/win32/mc.rb +120 -118
- data/lib/win32/windows/constants.rb +56 -0
- data/lib/win32/windows/functions.rb +51 -0
- data/lib/win32/windows/helper.rb +13 -0
- data/lib/win32/windows/structs.rb +30 -0
- data/misc/install_msg.rb +46 -46
- data/misc/rubymsg.mc +35 -35
- data/test/foo.mc +24 -24
- data/test/test_eventlog.rb +310 -319
- data/test/test_mc.rb +64 -67
- data/win32-eventlog.gemspec +30 -29
- metadata +90 -90
data/lib/win32/mc.rb
CHANGED
@@ -1,118 +1,120 @@
|
|
1
|
-
# The Win32 module serves as a namespace only.
|
2
|
-
module Win32
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
end
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
1
|
+
# The Win32 module serves as a namespace only.
|
2
|
+
module Win32
|
3
|
+
|
4
|
+
# The MC class encapsulates the mc (eventlog message compiler) commands.
|
5
|
+
class MC
|
6
|
+
|
7
|
+
# Raised if any of the MC methods fail.
|
8
|
+
class Error < StandardError; end;
|
9
|
+
|
10
|
+
# The version of the win32-mc library.
|
11
|
+
VERSION = '0.1.6'
|
12
|
+
|
13
|
+
# The name of the message category file initially processed.
|
14
|
+
attr_accessor :mc_file
|
15
|
+
|
16
|
+
# The name of the resource file generated by the mc command.
|
17
|
+
attr_accessor :res_file
|
18
|
+
|
19
|
+
# The name of the dll file generated by the link command.
|
20
|
+
attr_accessor :dll_file
|
21
|
+
|
22
|
+
# Accepts three file names as arguments and returns an MC object. The
|
23
|
+
# +mc_file+ is the name of the .mc file to be used to ultimately
|
24
|
+
# generate the .dll file.
|
25
|
+
#
|
26
|
+
# If +res_file+ or +dll_file+ are not specified, then the basename
|
27
|
+
# of +mc_file+ is used to generate their names, with .res and .dll
|
28
|
+
# extensions, respectively.
|
29
|
+
#
|
30
|
+
def initialize(mc_file, res_file=nil, dll_file=nil)
|
31
|
+
@mc_file = mc_file
|
32
|
+
|
33
|
+
if res_file
|
34
|
+
@res_file = res_file
|
35
|
+
else
|
36
|
+
@res_file = File.basename(mc_file, '.mc') + '.res'
|
37
|
+
end
|
38
|
+
|
39
|
+
if dll_file
|
40
|
+
@dll_file = dll_file
|
41
|
+
else
|
42
|
+
@dll_file = File.basename(mc_file, '.mc') + '.dll'
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
# Uses the message compiler (mc) program to generate the .h and .rc
|
47
|
+
# files based on the .mc (message category) file. This method must
|
48
|
+
# be called before MC#create_res_file or MC#create_dll_file.
|
49
|
+
#
|
50
|
+
def create_header
|
51
|
+
system("mc #{@mc_file}")
|
52
|
+
end
|
53
|
+
|
54
|
+
# Creates the .res (resource) file from the .rc file generated by the
|
55
|
+
# MC#create_header method. Raises an MC::Error if the .rc file is not
|
56
|
+
# found.
|
57
|
+
#
|
58
|
+
def create_res_file
|
59
|
+
rc_file = File.basename(@mc_file, '.mc') + '.rc'
|
60
|
+
unless File.exists?(rc_file)
|
61
|
+
raise MC::Error, "No .rc file found: #{@rc_file}"
|
62
|
+
end
|
63
|
+
system("rc -r -fo #{@res_file} #{rc_file}")
|
64
|
+
end
|
65
|
+
|
66
|
+
# Creates the .dll file from the .res file generated by the
|
67
|
+
# MC#create_res_file method. Raises an MC::Error if the .res file is not
|
68
|
+
# found.
|
69
|
+
#
|
70
|
+
def create_dll_file
|
71
|
+
unless File.exists?(@res_file)
|
72
|
+
raise MC::Error, "No .res file found: #{@res_file}"
|
73
|
+
end
|
74
|
+
system("link -dll -noentry -out:#{@dll_file} #{@res_file}")
|
75
|
+
end
|
76
|
+
|
77
|
+
# A shortcut for MC#create_header + MC#create_res_file +
|
78
|
+
# MC#create_dll_file.
|
79
|
+
#
|
80
|
+
def create_all
|
81
|
+
create_header
|
82
|
+
create_res_file
|
83
|
+
create_dll_file
|
84
|
+
end
|
85
|
+
|
86
|
+
# Delete .h, .rc and .res files created from the corresponding
|
87
|
+
# .mc file (but *not* the .dll file). This also deletes all MSG*.bin
|
88
|
+
# files in the current directory.
|
89
|
+
#
|
90
|
+
def clean
|
91
|
+
base = File.basename(@mc_file, '.mc')
|
92
|
+
|
93
|
+
%w[.h .rc .res].each do |ext|
|
94
|
+
file = base + ext
|
95
|
+
File.delete(file) if File.exists?(file)
|
96
|
+
end
|
97
|
+
|
98
|
+
Dir["MSG*.bin"].each do |binfile|
|
99
|
+
File.delete(binfile)
|
100
|
+
end
|
101
|
+
end
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
if $PROGRAM_NAME == __FILE__
|
106
|
+
mc_file = ARGV[0]
|
107
|
+
|
108
|
+
if mc_file
|
109
|
+
mc_file.chomp!
|
110
|
+
else
|
111
|
+
msg = "Usage: ruby mc.rb 'filename.mc'"
|
112
|
+
raise Win32::MC::Error, msg
|
113
|
+
end
|
114
|
+
|
115
|
+
m = Win32::MC.new(mc_file)
|
116
|
+
m.create_header
|
117
|
+
m.create_res_file
|
118
|
+
m.create_dll_file
|
119
|
+
puts "MC finished"
|
120
|
+
end
|
@@ -0,0 +1,56 @@
|
|
1
|
+
module Windows
|
2
|
+
module Constants
|
3
|
+
private
|
4
|
+
|
5
|
+
EVENTLOG_SEQUENTIAL_READ = 0x0001
|
6
|
+
EVENTLOG_SEEK_READ = 0x0002
|
7
|
+
EVENTLOG_FORWARDS_READ = 0x0004
|
8
|
+
EVENTLOG_BACKWARDS_READ = 0x0008
|
9
|
+
|
10
|
+
EVENTLOG_SUCCESS = 0x0000
|
11
|
+
EVENTLOG_ERROR_TYPE = 0x0001
|
12
|
+
EVENTLOG_WARNING_TYPE = 0x0002
|
13
|
+
EVENTLOG_INFORMATION_TYPE = 0x0004
|
14
|
+
EVENTLOG_AUDIT_SUCCESS = 0x0008
|
15
|
+
EVENTLOG_AUDIT_FAILURE = 0x0010
|
16
|
+
|
17
|
+
EVENTLOG_FULL_INFO = 0
|
18
|
+
|
19
|
+
HKEY_LOCAL_MACHINE = 0x80000002
|
20
|
+
|
21
|
+
REG_OPTION_NON_VOLATILE = 0
|
22
|
+
REG_DWORD = 4
|
23
|
+
REG_EXPAND_SZ = 2
|
24
|
+
|
25
|
+
ERROR_SUCCESS = 0
|
26
|
+
ERROR_INSUFFICIENT_BUFFER = 122
|
27
|
+
|
28
|
+
BUFFER_SIZE = 1024 * 64
|
29
|
+
MAX_SIZE = 512
|
30
|
+
MAX_STRINGS = 16
|
31
|
+
INFINITE = 0xFFFFFFFF
|
32
|
+
WAIT_FAILED = 0xFFFFFFFF
|
33
|
+
|
34
|
+
BASE_KEY = "SYSTEM\\CurrentControlSet\\Services\\EventLog\\"
|
35
|
+
|
36
|
+
STANDARD_RIGHTS_READ = 0x20000
|
37
|
+
STANDARD_RIGHTS_WRITE = 0x20000
|
38
|
+
SYNCHRONIZE = 0x100000
|
39
|
+
|
40
|
+
KEY_QUERY_VALUE = 0x0001
|
41
|
+
KEY_SET_VALUE = 0x0002
|
42
|
+
KEY_CREATE_SUB_KEY = 0x0004
|
43
|
+
KEY_ENUMERATE_SUB_KEYS = 0x0008
|
44
|
+
KEY_NOTIFY = 0x0010
|
45
|
+
|
46
|
+
KEY_WRITE = (STANDARD_RIGHTS_WRITE|KEY_SET_VALUE|KEY_CREATE_SUB_KEY) & (~SYNCHRONIZE)
|
47
|
+
KEY_READ = (STANDARD_RIGHTS_READ|KEY_QUERY_VALUE|KEY_ENUMERATE_SUB_KEYS| KEY_NOTIFY) & (~SYNCHRONIZE)
|
48
|
+
|
49
|
+
DONT_RESOLVE_DLL_REFERENCES = 0x00000001
|
50
|
+
LOAD_LIBRARY_AS_DATAFILE = 0x00000002
|
51
|
+
|
52
|
+
FORMAT_MESSAGE_IGNORE_INSERTS = 0x00000200
|
53
|
+
FORMAT_MESSAGE_FROM_HMODULE = 0x00000800
|
54
|
+
FORMAT_MESSAGE_ARGUMENT_ARRAY = 0x00002000
|
55
|
+
end
|
56
|
+
end
|
@@ -0,0 +1,51 @@
|
|
1
|
+
require 'ffi'
|
2
|
+
|
3
|
+
module Windows
|
4
|
+
module Functions
|
5
|
+
extend FFI::Library
|
6
|
+
ffi_lib :advapi32
|
7
|
+
|
8
|
+
typedef :uintptr_t, :handle
|
9
|
+
typedef :uintptr_t, :hkey
|
10
|
+
typedef :ulong, :dword
|
11
|
+
typedef :ushort, :word
|
12
|
+
|
13
|
+
attach_function :BackupEventLog, :BackupEventLogA, [:handle, :string], :bool
|
14
|
+
attach_function :ClearEventLog, :ClearEventLogA, [:handle, :string], :bool
|
15
|
+
attach_function :CloseEventLog, [:handle], :bool
|
16
|
+
attach_function :GetOldestEventLogRecord, [:handle, :pointer], :bool
|
17
|
+
attach_function :GetEventLogInformation, [:handle, :dword, :pointer, :dword, :pointer], :bool
|
18
|
+
attach_function :GetNumberOfEventLogRecords, [:handle, :pointer], :bool
|
19
|
+
attach_function :LookupAccountSid, :LookupAccountSidA, [:string, :pointer, :pointer, :pointer, :pointer, :pointer, :pointer], :bool
|
20
|
+
attach_function :OpenEventLog, :OpenEventLogA, [:string, :string], :handle
|
21
|
+
attach_function :OpenBackupEventLog, :OpenBackupEventLogA, [:string, :string], :handle
|
22
|
+
attach_function :NotifyChangeEventLog, [:handle, :handle], :bool
|
23
|
+
attach_function :ReadEventLog, :ReadEventLogA, [:handle, :dword, :dword, :buffer_out, :dword, :pointer, :pointer], :bool
|
24
|
+
attach_function :RegCloseKey, [:hkey], :long
|
25
|
+
attach_function :RegConnectRegistry, :RegConnectRegistryA, [:string, :hkey, :pointer], :long
|
26
|
+
attach_function :RegCreateKeyEx, :RegCreateKeyExA, [:hkey, :string, :dword, :string, :dword, :dword, :pointer, :pointer, :pointer], :long
|
27
|
+
attach_function :RegisterEventSource, :RegisterEventSourceA, [:string, :string], :handle
|
28
|
+
attach_function :RegOpenKeyEx, :RegOpenKeyExA, [:hkey, :string, :dword, :ulong, :pointer], :long
|
29
|
+
attach_function :RegQueryValueEx, :RegQueryValueExA, [:hkey, :string, :pointer, :pointer, :pointer, :pointer], :long
|
30
|
+
attach_function :RegSetValueEx, :RegSetValueExA, [:hkey, :string, :dword, :dword, :pointer, :dword], :long
|
31
|
+
attach_function :ReportEvent, :ReportEventA, [:handle, :word, :word, :dword, :pointer, :word, :dword, :pointer, :pointer], :bool
|
32
|
+
|
33
|
+
ffi_lib :kernel32
|
34
|
+
|
35
|
+
attach_function :CloseHandle, [:handle], :bool
|
36
|
+
attach_function :CreateEvent, :CreateEventA, [:pointer, :bool, :bool, :string], :handle
|
37
|
+
attach_function :ExpandEnvironmentStrings, :ExpandEnvironmentStringsA, [:string, :pointer, :dword], :dword
|
38
|
+
attach_function :FormatMessage, :FormatMessageA, [:dword, :uintptr_t, :dword, :dword, :pointer, :dword, :pointer], :dword
|
39
|
+
attach_function :FreeLibrary, [:handle], :bool
|
40
|
+
attach_function :LoadLibraryEx, :LoadLibraryExA, [:string, :handle, :dword], :handle
|
41
|
+
attach_function :WaitForSingleObject, [:handle, :dword], :dword
|
42
|
+
attach_function :Wow64DisableWow64FsRedirection, [:pointer], :bool
|
43
|
+
attach_function :Wow64RevertWow64FsRedirection, [:ulong], :bool
|
44
|
+
|
45
|
+
ffi_lib :wevtapi
|
46
|
+
|
47
|
+
attach_function :EvtClose, [:handle], :bool
|
48
|
+
attach_function :EvtOpenPublisherMetadata, [:handle, :buffer_in, :buffer_in, :dword, :dword], :handle
|
49
|
+
attach_function :EvtGetPublisherMetadataProperty, [:handle, :int, :dword, :dword, :pointer, :pointer], :bool
|
50
|
+
end
|
51
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
class String
|
2
|
+
# Convenience method for converting strings to UTF-16LE for wide character
|
3
|
+
# functions that require it.
|
4
|
+
def wincode
|
5
|
+
(self.tr(File::SEPARATOR, File::ALT_SEPARATOR) + 0.chr).encode('UTF-16LE')
|
6
|
+
end
|
7
|
+
|
8
|
+
# Read a wide character string up until the first double null, and delete
|
9
|
+
# any remaining null characters.
|
10
|
+
def read_wide
|
11
|
+
self[/^.*?(?=\x00{2})/].delete(0.chr)
|
12
|
+
end
|
13
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
require 'ffi'
|
2
|
+
|
3
|
+
module Windows
|
4
|
+
module Structs
|
5
|
+
extend FFI::Library
|
6
|
+
typedef :ulong, :dword
|
7
|
+
typedef :ushort, :word
|
8
|
+
|
9
|
+
class EVENTLOGRECORD < FFI::Struct
|
10
|
+
layout(
|
11
|
+
:Length, :dword,
|
12
|
+
:Reserved, :dword,
|
13
|
+
:RecordNumber, :dword,
|
14
|
+
:TimeGenerated, :dword,
|
15
|
+
:TimeWritten, :dword,
|
16
|
+
:EventID, :dword,
|
17
|
+
:EventType, :word,
|
18
|
+
:NumStrings, :word,
|
19
|
+
:EventCategory, :word,
|
20
|
+
:ReservedFlags, :word,
|
21
|
+
:ClosingRecordNumber, :dword,
|
22
|
+
:StringOffset, :dword,
|
23
|
+
:UserSidLength, :dword,
|
24
|
+
:UserSidOffset, :dword,
|
25
|
+
:DataLength, :dword,
|
26
|
+
:DataOffset, :dword
|
27
|
+
)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
data/misc/install_msg.rb
CHANGED
@@ -1,46 +1,46 @@
|
|
1
|
-
###############################################################################
|
2
|
-
# install_msg.rb
|
3
|
-
#
|
4
|
-
# This script will create a 'RubyMsg' event source in your registry.
|
5
|
-
# the relevant files will be copied to the 'rubymsg' directory under C:\ruby,
|
6
|
-
# or wherever your toplevel Ruby installation directory is located.
|
7
|
-
#
|
8
|
-
#
|
9
|
-
#
|
10
|
-
#
|
11
|
-
# DO NOT MOVE THE DLL FILE ONCE IT IS INSTALLED.
|
12
|
-
# to delete the registry entry and reinstall the event source pointing to the
|
13
|
-
# proper directory.
|
14
|
-
#
|
15
|
-
# You should only run this script *after* you have installed win32-eventlog.
|
16
|
-
###############################################################################
|
17
|
-
require 'rbconfig'
|
18
|
-
require 'fileutils'
|
19
|
-
require 'win32/eventlog'
|
20
|
-
require 'win32/mc'
|
21
|
-
include Win32
|
22
|
-
|
23
|
-
msg_dir = File.join(
|
24
|
-
msg_file = 'rubymsg.mc'
|
25
|
-
|
26
|
-
Dir.mkdir(msg_dir) unless File.exists?(msg_dir)
|
27
|
-
FileUtils.cp('misc/rubymsg.mc', msg_dir)
|
28
|
-
Dir.chdir(msg_dir)
|
29
|
-
|
30
|
-
mc = Win32::MC.new(msg_file)
|
31
|
-
mc.create_all
|
32
|
-
|
33
|
-
puts ".dll created"
|
34
|
-
|
35
|
-
dll_file = File.expand_path(
|
36
|
-
|
37
|
-
# Change 'Application' to whatever you feel is appropriate
|
38
|
-
Win32::EventLog.add_event_source(
|
39
|
-
:source => "Application",
|
40
|
-
:key_name => "RubyMsg",
|
41
|
-
:category_count => 3,
|
42
|
-
:event_message_file => dll_file,
|
43
|
-
:category_message_file => dll_file
|
44
|
-
)
|
45
|
-
|
46
|
-
puts "Event source 'RubyMsg' added to registry"
|
1
|
+
###############################################################################
|
2
|
+
# install_msg.rb
|
3
|
+
#
|
4
|
+
# This script will create a 'RubyMsg' event source in your registry. All of
|
5
|
+
# the relevant files will be copied to the 'rubymsg' directory under C:\ruby,
|
6
|
+
# or wherever your toplevel Ruby installation directory is located. By default
|
7
|
+
# this will be installed in the 'Application' log. If you wish to change that
|
8
|
+
# then change the word 'Application' to either 'Security' or 'System' (or your
|
9
|
+
# own custom log).
|
10
|
+
#
|
11
|
+
# DO NOT MOVE THE DLL FILE ONCE IT IS INSTALLED. If you do, you will have
|
12
|
+
# to delete the registry entry and reinstall the event source pointing to the
|
13
|
+
# proper directory.
|
14
|
+
#
|
15
|
+
# You should only run this script *after* you have installed win32-eventlog.
|
16
|
+
###############################################################################
|
17
|
+
require 'rbconfig'
|
18
|
+
require 'fileutils'
|
19
|
+
require 'win32/eventlog'
|
20
|
+
require 'win32/mc'
|
21
|
+
include Win32
|
22
|
+
|
23
|
+
msg_dir = File.join(RbConfig::CONFIG['prefix'], 'rubymsg')
|
24
|
+
msg_file = 'rubymsg.mc'
|
25
|
+
|
26
|
+
Dir.mkdir(msg_dir) unless File.exists?(msg_dir)
|
27
|
+
FileUtils.cp('misc/rubymsg.mc', msg_dir)
|
28
|
+
Dir.chdir(msg_dir)
|
29
|
+
|
30
|
+
mc = Win32::MC.new(msg_file)
|
31
|
+
mc.create_all
|
32
|
+
|
33
|
+
puts ".dll created"
|
34
|
+
|
35
|
+
dll_file = File.expand_path(mc.dll_file)
|
36
|
+
|
37
|
+
# Change 'Application' to whatever you feel is appropriate
|
38
|
+
Win32::EventLog.add_event_source(
|
39
|
+
:source => "Application",
|
40
|
+
:key_name => "RubyMsg",
|
41
|
+
:category_count => 3,
|
42
|
+
:event_message_file => dll_file,
|
43
|
+
:category_message_file => dll_file
|
44
|
+
)
|
45
|
+
|
46
|
+
puts "Event source 'RubyMsg' added to registry"
|