win32-eventlog 0.5.3 → 0.6.0
Sign up to get free protection for your applications and to get access to all the features.
- 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"
|