winevt_c 0.9.1 → 0.10.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 +4 -4
- data/.clang-format +4 -4
- data/.github/workflows/linux.yml +26 -0
- data/Gemfile +6 -6
- data/LICENSE.txt +202 -202
- data/README.md +97 -97
- data/Rakefile +37 -37
- data/appveyor.yml +48 -26
- data/example/bookmark.rb +9 -9
- data/example/enumerate_channels.rb +13 -13
- data/example/eventlog.rb +13 -13
- data/example/locale.rb +13 -13
- data/example/rate_limit.rb +14 -14
- data/example/tailing.rb +21 -21
- data/ext/winevt/extconf.rb +24 -24
- data/ext/winevt/winevt.c +30 -30
- data/ext/winevt/winevt_bookmark.c +149 -149
- data/ext/winevt/winevt_c.h +133 -132
- data/ext/winevt/winevt_channel.c +327 -327
- data/ext/winevt/winevt_locale.c +92 -92
- data/ext/winevt/winevt_locale_info.c +68 -68
- data/ext/winevt/winevt_query.c +649 -650
- data/ext/winevt/winevt_session.c +425 -425
- data/ext/winevt/winevt_subscribe.c +756 -757
- data/ext/winevt/winevt_utils.cpp +790 -718
- data/lib/winevt/bookmark.rb +6 -6
- data/lib/winevt/query.rb +6 -6
- data/lib/winevt/session.rb +15 -15
- data/lib/winevt/subscribe.rb +18 -18
- data/lib/winevt/version.rb +3 -3
- data/lib/winevt.rb +14 -14
- data/winevt_c.gemspec +34 -34
- metadata +8 -9
- data/.travis.yml +0 -15
@@ -1,757 +1,756 @@
|
|
1
|
-
#include <winevt_c.h>
|
2
|
-
|
3
|
-
/* clang-format off */
|
4
|
-
/*
|
5
|
-
* Document-class: Winevt::EventLog::Subscribe
|
6
|
-
*
|
7
|
-
* Subscribe Windows EventLog channel.
|
8
|
-
*
|
9
|
-
* @example
|
10
|
-
* require 'winevt'
|
11
|
-
*
|
12
|
-
* @subscribe = Winevt::EventLog::Subscribe.new
|
13
|
-
* @subscribe.tail = true
|
14
|
-
* @subscribe.rate_limit = 80
|
15
|
-
* @subscribe.subscribe(
|
16
|
-
* "Application", "*[System[(Level <= 4) and TimeCreated[timediff(@SystemTime) <= 86400000]]]"
|
17
|
-
* )
|
18
|
-
* while true do
|
19
|
-
* @subscribe.each do |eventlog, message, string_inserts|
|
20
|
-
* puts ({eventlog: eventlog, data: message})
|
21
|
-
* end
|
22
|
-
* sleep(0.1)
|
23
|
-
* end
|
24
|
-
*
|
25
|
-
* @see https://docs.microsoft.com/en-us/windows/win32/api/winevt/nf-winevt-evtsubscribe
|
26
|
-
*/
|
27
|
-
/* clang-format on */
|
28
|
-
|
29
|
-
static void subscribe_free(void* ptr);
|
30
|
-
|
31
|
-
static const rb_data_type_t rb_winevt_subscribe_type = { "winevt/subscribe",
|
32
|
-
{
|
33
|
-
0,
|
34
|
-
subscribe_free,
|
35
|
-
0,
|
36
|
-
},
|
37
|
-
NULL,
|
38
|
-
NULL,
|
39
|
-
RUBY_TYPED_FREE_IMMEDIATELY };
|
40
|
-
|
41
|
-
static void
|
42
|
-
close_handles(struct WinevtSubscribe* winevtSubscribe)
|
43
|
-
{
|
44
|
-
if (winevtSubscribe->signalEvent) {
|
45
|
-
CloseHandle(winevtSubscribe->signalEvent);
|
46
|
-
winevtSubscribe->signalEvent = NULL;
|
47
|
-
}
|
48
|
-
|
49
|
-
if (winevtSubscribe->subscription) {
|
50
|
-
EvtClose(winevtSubscribe->subscription);
|
51
|
-
winevtSubscribe->subscription = NULL;
|
52
|
-
}
|
53
|
-
|
54
|
-
if (winevtSubscribe->bookmark) {
|
55
|
-
EvtClose(winevtSubscribe->bookmark);
|
56
|
-
winevtSubscribe->bookmark = NULL;
|
57
|
-
}
|
58
|
-
|
59
|
-
for (int i = 0; i < winevtSubscribe->count; i++) {
|
60
|
-
if (winevtSubscribe->hEvents[i]) {
|
61
|
-
EvtClose(winevtSubscribe->hEvents[i]);
|
62
|
-
winevtSubscribe->hEvents[i] = NULL;
|
63
|
-
}
|
64
|
-
}
|
65
|
-
winevtSubscribe->count = 0;
|
66
|
-
|
67
|
-
if (winevtSubscribe->remoteHandle) {
|
68
|
-
EvtClose(winevtSubscribe->remoteHandle);
|
69
|
-
winevtSubscribe->remoteHandle = NULL;
|
70
|
-
}
|
71
|
-
}
|
72
|
-
|
73
|
-
static void
|
74
|
-
subscribe_free(void* ptr)
|
75
|
-
{
|
76
|
-
struct WinevtSubscribe* winevtSubscribe = (struct WinevtSubscribe*)ptr;
|
77
|
-
close_handles(winevtSubscribe);
|
78
|
-
|
79
|
-
xfree(ptr);
|
80
|
-
}
|
81
|
-
|
82
|
-
static VALUE
|
83
|
-
rb_winevt_subscribe_alloc(VALUE klass)
|
84
|
-
{
|
85
|
-
VALUE obj;
|
86
|
-
struct WinevtSubscribe* winevtSubscribe;
|
87
|
-
obj = TypedData_Make_Struct(
|
88
|
-
klass, struct WinevtSubscribe, &rb_winevt_subscribe_type, winevtSubscribe);
|
89
|
-
return obj;
|
90
|
-
}
|
91
|
-
|
92
|
-
/*
|
93
|
-
* Initalize Subscribe class.
|
94
|
-
*
|
95
|
-
* @return [Subscribe]
|
96
|
-
*
|
97
|
-
*/
|
98
|
-
static VALUE
|
99
|
-
rb_winevt_subscribe_initialize(VALUE self)
|
100
|
-
{
|
101
|
-
struct WinevtSubscribe* winevtSubscribe;
|
102
|
-
|
103
|
-
TypedData_Get_Struct(
|
104
|
-
self, struct WinevtSubscribe, &rb_winevt_subscribe_type, winevtSubscribe);
|
105
|
-
|
106
|
-
winevtSubscribe->rateLimit = SUBSCRIBE_RATE_INFINITE;
|
107
|
-
winevtSubscribe->lastTime = 0;
|
108
|
-
winevtSubscribe->currentRate = 0;
|
109
|
-
winevtSubscribe->renderAsXML = TRUE;
|
110
|
-
winevtSubscribe->readExistingEvents = TRUE;
|
111
|
-
winevtSubscribe->preserveQualifiers = FALSE;
|
112
|
-
winevtSubscribe->localeInfo = &default_locale;
|
113
|
-
|
114
|
-
return Qnil;
|
115
|
-
}
|
116
|
-
|
117
|
-
/*
|
118
|
-
* This method specifies whether read existing events or not.
|
119
|
-
*
|
120
|
-
* @param rb_read_existing_events_p [Boolean]
|
121
|
-
*/
|
122
|
-
static VALUE
|
123
|
-
rb_winevt_subscribe_set_read_existing_events(VALUE self, VALUE rb_read_existing_events_p)
|
124
|
-
{
|
125
|
-
struct WinevtSubscribe* winevtSubscribe;
|
126
|
-
|
127
|
-
TypedData_Get_Struct(
|
128
|
-
self, struct WinevtSubscribe, &rb_winevt_subscribe_type, winevtSubscribe);
|
129
|
-
|
130
|
-
winevtSubscribe->readExistingEvents = RTEST(rb_read_existing_events_p);
|
131
|
-
|
132
|
-
return Qnil;
|
133
|
-
}
|
134
|
-
|
135
|
-
/*
|
136
|
-
* This method returns whether read existing events or not.
|
137
|
-
*
|
138
|
-
* @return [Boolean]
|
139
|
-
*/
|
140
|
-
static VALUE
|
141
|
-
rb_winevt_subscribe_read_existing_events_p(VALUE self)
|
142
|
-
{
|
143
|
-
struct WinevtSubscribe* winevtSubscribe;
|
144
|
-
|
145
|
-
TypedData_Get_Struct(
|
146
|
-
self, struct WinevtSubscribe, &rb_winevt_subscribe_type, winevtSubscribe);
|
147
|
-
|
148
|
-
return winevtSubscribe->readExistingEvents ? Qtrue : Qfalse;
|
149
|
-
}
|
150
|
-
|
151
|
-
/*
|
152
|
-
* Subscribe into a Windows EventLog channel.
|
153
|
-
*
|
154
|
-
* @overload subscribe(path, query, bookmark=nil, session=nil)
|
155
|
-
* @param path [String] Subscribe Channel
|
156
|
-
* @param query [String] Query string for channel
|
157
|
-
* @param bookmark [Bookmark] bookmark Bookmark class instance.
|
158
|
-
* @param session [Session] Session information for remoting access.
|
159
|
-
* @return [Boolean]
|
160
|
-
*
|
161
|
-
*/
|
162
|
-
static VALUE
|
163
|
-
rb_winevt_subscribe_subscribe(int argc, VALUE* argv, VALUE self)
|
164
|
-
{
|
165
|
-
VALUE rb_path, rb_query, rb_bookmark, rb_session;
|
166
|
-
EVT_HANDLE hSubscription = NULL, hBookmark = NULL;
|
167
|
-
HANDLE hSignalEvent;
|
168
|
-
EVT_HANDLE hRemoteHandle = NULL;
|
169
|
-
DWORD len, flags = 0L;
|
170
|
-
DWORD err = ERROR_SUCCESS;
|
171
|
-
VALUE wpathBuf, wqueryBuf, wBookmarkBuf;
|
172
|
-
PWSTR path, query, bookmarkXml;
|
173
|
-
DWORD status = ERROR_SUCCESS;
|
174
|
-
struct WinevtSession* winevtSession;
|
175
|
-
struct WinevtSubscribe* winevtSubscribe;
|
176
|
-
|
177
|
-
hSignalEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
|
178
|
-
|
179
|
-
TypedData_Get_Struct(
|
180
|
-
self, struct WinevtSubscribe, &rb_winevt_subscribe_type, winevtSubscribe);
|
181
|
-
|
182
|
-
rb_scan_args(argc, argv, "22", &rb_path, &rb_query, &rb_bookmark, &rb_session);
|
183
|
-
Check_Type(rb_path, T_STRING);
|
184
|
-
Check_Type(rb_query, T_STRING);
|
185
|
-
|
186
|
-
if (rb_obj_is_kind_of(rb_bookmark, rb_cString)) {
|
187
|
-
// bookmarkXml : To wide char
|
188
|
-
len = MultiByteToWideChar(
|
189
|
-
CP_UTF8, 0, RSTRING_PTR(rb_bookmark), RSTRING_LEN(rb_bookmark), NULL, 0);
|
190
|
-
bookmarkXml = ALLOCV_N(WCHAR, wBookmarkBuf, len + 1);
|
191
|
-
MultiByteToWideChar(CP_UTF8,
|
192
|
-
0,
|
193
|
-
RSTRING_PTR(rb_bookmark),
|
194
|
-
RSTRING_LEN(rb_bookmark),
|
195
|
-
bookmarkXml,
|
196
|
-
len);
|
197
|
-
bookmarkXml[len] = L'\0';
|
198
|
-
hBookmark = EvtCreateBookmark(bookmarkXml);
|
199
|
-
ALLOCV_END(wBookmarkBuf);
|
200
|
-
if (hBookmark == NULL) {
|
201
|
-
status = GetLastError();
|
202
|
-
raise_system_error(rb_eWinevtQueryError, status);
|
203
|
-
}
|
204
|
-
}
|
205
|
-
if (rb_obj_is_kind_of(rb_session, rb_cSession)) {
|
206
|
-
winevtSession = EventSession(rb_session);
|
207
|
-
hRemoteHandle = connect_to_remote(winevtSession->server,
|
208
|
-
winevtSession->domain,
|
209
|
-
winevtSession->username,
|
210
|
-
winevtSession->password,
|
211
|
-
winevtSession->flags
|
212
|
-
|
213
|
-
err
|
214
|
-
|
215
|
-
|
216
|
-
|
217
|
-
|
218
|
-
|
219
|
-
|
220
|
-
|
221
|
-
|
222
|
-
|
223
|
-
|
224
|
-
|
225
|
-
|
226
|
-
|
227
|
-
|
228
|
-
|
229
|
-
|
230
|
-
|
231
|
-
|
232
|
-
|
233
|
-
|
234
|
-
|
235
|
-
|
236
|
-
|
237
|
-
|
238
|
-
|
239
|
-
|
240
|
-
|
241
|
-
|
242
|
-
|
243
|
-
|
244
|
-
|
245
|
-
if (hBookmark != NULL) {
|
246
|
-
EvtClose(hBookmark);
|
247
|
-
}
|
248
|
-
if (hSignalEvent != NULL) {
|
249
|
-
CloseHandle(hSignalEvent);
|
250
|
-
}
|
251
|
-
|
252
|
-
|
253
|
-
|
254
|
-
|
255
|
-
|
256
|
-
|
257
|
-
|
258
|
-
|
259
|
-
|
260
|
-
|
261
|
-
|
262
|
-
|
263
|
-
|
264
|
-
ALLOCV_END(
|
265
|
-
|
266
|
-
|
267
|
-
winevtSubscribe->
|
268
|
-
winevtSubscribe->
|
269
|
-
|
270
|
-
|
271
|
-
|
272
|
-
|
273
|
-
winevtSubscribe->bookmark
|
274
|
-
|
275
|
-
if (hSubscription != NULL) {
|
276
|
-
EvtClose(hSubscription);
|
277
|
-
}
|
278
|
-
if (hSignalEvent != NULL) {
|
279
|
-
CloseHandle(hSignalEvent);
|
280
|
-
}
|
281
|
-
status
|
282
|
-
|
283
|
-
|
284
|
-
|
285
|
-
|
286
|
-
|
287
|
-
|
288
|
-
|
289
|
-
|
290
|
-
|
291
|
-
|
292
|
-
|
293
|
-
|
294
|
-
|
295
|
-
|
296
|
-
|
297
|
-
|
298
|
-
|
299
|
-
|
300
|
-
|
301
|
-
|
302
|
-
|
303
|
-
|
304
|
-
|
305
|
-
|
306
|
-
|
307
|
-
|
308
|
-
|
309
|
-
|
310
|
-
|
311
|
-
|
312
|
-
|
313
|
-
|
314
|
-
|
315
|
-
|
316
|
-
|
317
|
-
|
318
|
-
|
319
|
-
winevtSubscribe->
|
320
|
-
|
321
|
-
|
322
|
-
|
323
|
-
|
324
|
-
*
|
325
|
-
*
|
326
|
-
*
|
327
|
-
*
|
328
|
-
*
|
329
|
-
|
330
|
-
|
331
|
-
|
332
|
-
|
333
|
-
|
334
|
-
|
335
|
-
|
336
|
-
|
337
|
-
|
338
|
-
|
339
|
-
|
340
|
-
|
341
|
-
|
342
|
-
|
343
|
-
|
344
|
-
|
345
|
-
|
346
|
-
|
347
|
-
|
348
|
-
|
349
|
-
|
350
|
-
|
351
|
-
|
352
|
-
|
353
|
-
|
354
|
-
|
355
|
-
|
356
|
-
|
357
|
-
|
358
|
-
|
359
|
-
|
360
|
-
|
361
|
-
|
362
|
-
|
363
|
-
|
364
|
-
|
365
|
-
|
366
|
-
|
367
|
-
|
368
|
-
|
369
|
-
|
370
|
-
winevtSubscribe->
|
371
|
-
|
372
|
-
|
373
|
-
|
374
|
-
|
375
|
-
|
376
|
-
|
377
|
-
|
378
|
-
|
379
|
-
|
380
|
-
|
381
|
-
|
382
|
-
|
383
|
-
|
384
|
-
|
385
|
-
|
386
|
-
|
387
|
-
|
388
|
-
|
389
|
-
|
390
|
-
|
391
|
-
|
392
|
-
|
393
|
-
|
394
|
-
|
395
|
-
|
396
|
-
|
397
|
-
|
398
|
-
|
399
|
-
|
400
|
-
|
401
|
-
|
402
|
-
|
403
|
-
|
404
|
-
|
405
|
-
|
406
|
-
|
407
|
-
|
408
|
-
|
409
|
-
|
410
|
-
|
411
|
-
|
412
|
-
|
413
|
-
|
414
|
-
|
415
|
-
|
416
|
-
|
417
|
-
|
418
|
-
|
419
|
-
|
420
|
-
|
421
|
-
|
422
|
-
|
423
|
-
|
424
|
-
|
425
|
-
|
426
|
-
|
427
|
-
|
428
|
-
|
429
|
-
|
430
|
-
|
431
|
-
|
432
|
-
|
433
|
-
|
434
|
-
|
435
|
-
|
436
|
-
|
437
|
-
|
438
|
-
|
439
|
-
|
440
|
-
|
441
|
-
|
442
|
-
|
443
|
-
|
444
|
-
|
445
|
-
|
446
|
-
|
447
|
-
|
448
|
-
|
449
|
-
|
450
|
-
|
451
|
-
|
452
|
-
|
453
|
-
|
454
|
-
|
455
|
-
*
|
456
|
-
*
|
457
|
-
*
|
458
|
-
*
|
459
|
-
*
|
460
|
-
*
|
461
|
-
*
|
462
|
-
|
463
|
-
|
464
|
-
|
465
|
-
|
466
|
-
|
467
|
-
|
468
|
-
|
469
|
-
|
470
|
-
|
471
|
-
|
472
|
-
|
473
|
-
|
474
|
-
|
475
|
-
|
476
|
-
|
477
|
-
|
478
|
-
*
|
479
|
-
*
|
480
|
-
|
481
|
-
|
482
|
-
|
483
|
-
|
484
|
-
|
485
|
-
|
486
|
-
|
487
|
-
|
488
|
-
|
489
|
-
|
490
|
-
|
491
|
-
|
492
|
-
|
493
|
-
|
494
|
-
*
|
495
|
-
*
|
496
|
-
* @
|
497
|
-
|
498
|
-
|
499
|
-
|
500
|
-
|
501
|
-
|
502
|
-
|
503
|
-
|
504
|
-
|
505
|
-
|
506
|
-
|
507
|
-
|
508
|
-
|
509
|
-
|
510
|
-
|
511
|
-
*
|
512
|
-
*
|
513
|
-
* @
|
514
|
-
|
515
|
-
|
516
|
-
|
517
|
-
|
518
|
-
|
519
|
-
|
520
|
-
|
521
|
-
|
522
|
-
|
523
|
-
|
524
|
-
|
525
|
-
|
526
|
-
|
527
|
-
|
528
|
-
|
529
|
-
|
530
|
-
|
531
|
-
|
532
|
-
|
533
|
-
|
534
|
-
|
535
|
-
|
536
|
-
|
537
|
-
*
|
538
|
-
*
|
539
|
-
* @
|
540
|
-
|
541
|
-
|
542
|
-
|
543
|
-
|
544
|
-
|
545
|
-
|
546
|
-
|
547
|
-
|
548
|
-
|
549
|
-
|
550
|
-
|
551
|
-
|
552
|
-
|
553
|
-
|
554
|
-
*
|
555
|
-
*
|
556
|
-
* @
|
557
|
-
|
558
|
-
|
559
|
-
|
560
|
-
|
561
|
-
|
562
|
-
|
563
|
-
|
564
|
-
|
565
|
-
|
566
|
-
|
567
|
-
|
568
|
-
|
569
|
-
|
570
|
-
|
571
|
-
|
572
|
-
|
573
|
-
*
|
574
|
-
*
|
575
|
-
* @
|
576
|
-
|
577
|
-
|
578
|
-
|
579
|
-
|
580
|
-
|
581
|
-
|
582
|
-
|
583
|
-
|
584
|
-
|
585
|
-
|
586
|
-
|
587
|
-
|
588
|
-
|
589
|
-
|
590
|
-
|
591
|
-
|
592
|
-
*
|
593
|
-
*
|
594
|
-
* @
|
595
|
-
|
596
|
-
|
597
|
-
|
598
|
-
|
599
|
-
|
600
|
-
|
601
|
-
|
602
|
-
|
603
|
-
|
604
|
-
|
605
|
-
|
606
|
-
|
607
|
-
|
608
|
-
|
609
|
-
*
|
610
|
-
*
|
611
|
-
* @
|
612
|
-
|
613
|
-
|
614
|
-
|
615
|
-
|
616
|
-
|
617
|
-
|
618
|
-
|
619
|
-
|
620
|
-
|
621
|
-
|
622
|
-
|
623
|
-
|
624
|
-
|
625
|
-
|
626
|
-
|
627
|
-
|
628
|
-
|
629
|
-
|
630
|
-
|
631
|
-
*
|
632
|
-
*
|
633
|
-
|
634
|
-
|
635
|
-
|
636
|
-
|
637
|
-
|
638
|
-
|
639
|
-
|
640
|
-
|
641
|
-
|
642
|
-
|
643
|
-
|
644
|
-
|
645
|
-
|
646
|
-
|
647
|
-
|
648
|
-
|
649
|
-
|
650
|
-
|
651
|
-
*
|
652
|
-
*
|
653
|
-
* @
|
654
|
-
|
655
|
-
|
656
|
-
|
657
|
-
|
658
|
-
|
659
|
-
|
660
|
-
|
661
|
-
|
662
|
-
|
663
|
-
|
664
|
-
|
665
|
-
|
666
|
-
|
667
|
-
|
668
|
-
|
669
|
-
|
670
|
-
|
671
|
-
|
672
|
-
|
673
|
-
|
674
|
-
|
675
|
-
|
676
|
-
|
677
|
-
*
|
678
|
-
*
|
679
|
-
|
680
|
-
|
681
|
-
|
682
|
-
|
683
|
-
|
684
|
-
|
685
|
-
|
686
|
-
|
687
|
-
|
688
|
-
|
689
|
-
|
690
|
-
|
691
|
-
|
692
|
-
|
693
|
-
|
694
|
-
|
695
|
-
|
696
|
-
|
697
|
-
|
698
|
-
|
699
|
-
|
700
|
-
|
701
|
-
|
702
|
-
|
703
|
-
*
|
704
|
-
|
705
|
-
|
706
|
-
|
707
|
-
|
708
|
-
rb_define_method(rb_cSubscribe, "
|
709
|
-
rb_define_method(rb_cSubscribe, "
|
710
|
-
rb_define_method(rb_cSubscribe, "
|
711
|
-
rb_define_method(rb_cSubscribe, "
|
712
|
-
|
713
|
-
|
714
|
-
|
715
|
-
|
716
|
-
|
717
|
-
|
718
|
-
|
719
|
-
|
720
|
-
rb_define_method(rb_cSubscribe, "
|
721
|
-
rb_define_method(rb_cSubscribe, "rate_limit",
|
722
|
-
rb_define_method(
|
723
|
-
|
724
|
-
|
725
|
-
|
726
|
-
|
727
|
-
|
728
|
-
|
729
|
-
|
730
|
-
|
731
|
-
|
732
|
-
|
733
|
-
|
734
|
-
|
735
|
-
|
736
|
-
|
737
|
-
|
738
|
-
|
739
|
-
|
740
|
-
|
741
|
-
|
742
|
-
|
743
|
-
|
744
|
-
|
745
|
-
|
746
|
-
|
747
|
-
|
748
|
-
|
749
|
-
|
750
|
-
|
751
|
-
|
752
|
-
|
753
|
-
|
754
|
-
|
755
|
-
|
756
|
-
|
757
|
-
}
|
1
|
+
#include <winevt_c.h>
|
2
|
+
|
3
|
+
/* clang-format off */
|
4
|
+
/*
|
5
|
+
* Document-class: Winevt::EventLog::Subscribe
|
6
|
+
*
|
7
|
+
* Subscribe Windows EventLog channel.
|
8
|
+
*
|
9
|
+
* @example
|
10
|
+
* require 'winevt'
|
11
|
+
*
|
12
|
+
* @subscribe = Winevt::EventLog::Subscribe.new
|
13
|
+
* @subscribe.tail = true
|
14
|
+
* @subscribe.rate_limit = 80
|
15
|
+
* @subscribe.subscribe(
|
16
|
+
* "Application", "*[System[(Level <= 4) and TimeCreated[timediff(@SystemTime) <= 86400000]]]"
|
17
|
+
* )
|
18
|
+
* while true do
|
19
|
+
* @subscribe.each do |eventlog, message, string_inserts|
|
20
|
+
* puts ({eventlog: eventlog, data: message})
|
21
|
+
* end
|
22
|
+
* sleep(0.1)
|
23
|
+
* end
|
24
|
+
*
|
25
|
+
* @see https://docs.microsoft.com/en-us/windows/win32/api/winevt/nf-winevt-evtsubscribe
|
26
|
+
*/
|
27
|
+
/* clang-format on */
|
28
|
+
|
29
|
+
static void subscribe_free(void* ptr);
|
30
|
+
|
31
|
+
static const rb_data_type_t rb_winevt_subscribe_type = { "winevt/subscribe",
|
32
|
+
{
|
33
|
+
0,
|
34
|
+
subscribe_free,
|
35
|
+
0,
|
36
|
+
},
|
37
|
+
NULL,
|
38
|
+
NULL,
|
39
|
+
RUBY_TYPED_FREE_IMMEDIATELY };
|
40
|
+
|
41
|
+
static void
|
42
|
+
close_handles(struct WinevtSubscribe* winevtSubscribe)
|
43
|
+
{
|
44
|
+
if (winevtSubscribe->signalEvent) {
|
45
|
+
CloseHandle(winevtSubscribe->signalEvent);
|
46
|
+
winevtSubscribe->signalEvent = NULL;
|
47
|
+
}
|
48
|
+
|
49
|
+
if (winevtSubscribe->subscription) {
|
50
|
+
EvtClose(winevtSubscribe->subscription);
|
51
|
+
winevtSubscribe->subscription = NULL;
|
52
|
+
}
|
53
|
+
|
54
|
+
if (winevtSubscribe->bookmark) {
|
55
|
+
EvtClose(winevtSubscribe->bookmark);
|
56
|
+
winevtSubscribe->bookmark = NULL;
|
57
|
+
}
|
58
|
+
|
59
|
+
for (int i = 0; i < winevtSubscribe->count; i++) {
|
60
|
+
if (winevtSubscribe->hEvents[i]) {
|
61
|
+
EvtClose(winevtSubscribe->hEvents[i]);
|
62
|
+
winevtSubscribe->hEvents[i] = NULL;
|
63
|
+
}
|
64
|
+
}
|
65
|
+
winevtSubscribe->count = 0;
|
66
|
+
|
67
|
+
if (winevtSubscribe->remoteHandle) {
|
68
|
+
EvtClose(winevtSubscribe->remoteHandle);
|
69
|
+
winevtSubscribe->remoteHandle = NULL;
|
70
|
+
}
|
71
|
+
}
|
72
|
+
|
73
|
+
static void
|
74
|
+
subscribe_free(void* ptr)
|
75
|
+
{
|
76
|
+
struct WinevtSubscribe* winevtSubscribe = (struct WinevtSubscribe*)ptr;
|
77
|
+
close_handles(winevtSubscribe);
|
78
|
+
|
79
|
+
xfree(ptr);
|
80
|
+
}
|
81
|
+
|
82
|
+
static VALUE
|
83
|
+
rb_winevt_subscribe_alloc(VALUE klass)
|
84
|
+
{
|
85
|
+
VALUE obj;
|
86
|
+
struct WinevtSubscribe* winevtSubscribe;
|
87
|
+
obj = TypedData_Make_Struct(
|
88
|
+
klass, struct WinevtSubscribe, &rb_winevt_subscribe_type, winevtSubscribe);
|
89
|
+
return obj;
|
90
|
+
}
|
91
|
+
|
92
|
+
/*
|
93
|
+
* Initalize Subscribe class.
|
94
|
+
*
|
95
|
+
* @return [Subscribe]
|
96
|
+
*
|
97
|
+
*/
|
98
|
+
static VALUE
|
99
|
+
rb_winevt_subscribe_initialize(VALUE self)
|
100
|
+
{
|
101
|
+
struct WinevtSubscribe* winevtSubscribe;
|
102
|
+
|
103
|
+
TypedData_Get_Struct(
|
104
|
+
self, struct WinevtSubscribe, &rb_winevt_subscribe_type, winevtSubscribe);
|
105
|
+
|
106
|
+
winevtSubscribe->rateLimit = SUBSCRIBE_RATE_INFINITE;
|
107
|
+
winevtSubscribe->lastTime = 0;
|
108
|
+
winevtSubscribe->currentRate = 0;
|
109
|
+
winevtSubscribe->renderAsXML = TRUE;
|
110
|
+
winevtSubscribe->readExistingEvents = TRUE;
|
111
|
+
winevtSubscribe->preserveQualifiers = FALSE;
|
112
|
+
winevtSubscribe->localeInfo = &default_locale;
|
113
|
+
|
114
|
+
return Qnil;
|
115
|
+
}
|
116
|
+
|
117
|
+
/*
|
118
|
+
* This method specifies whether read existing events or not.
|
119
|
+
*
|
120
|
+
* @param rb_read_existing_events_p [Boolean]
|
121
|
+
*/
|
122
|
+
static VALUE
|
123
|
+
rb_winevt_subscribe_set_read_existing_events(VALUE self, VALUE rb_read_existing_events_p)
|
124
|
+
{
|
125
|
+
struct WinevtSubscribe* winevtSubscribe;
|
126
|
+
|
127
|
+
TypedData_Get_Struct(
|
128
|
+
self, struct WinevtSubscribe, &rb_winevt_subscribe_type, winevtSubscribe);
|
129
|
+
|
130
|
+
winevtSubscribe->readExistingEvents = RTEST(rb_read_existing_events_p);
|
131
|
+
|
132
|
+
return Qnil;
|
133
|
+
}
|
134
|
+
|
135
|
+
/*
|
136
|
+
* This method returns whether read existing events or not.
|
137
|
+
*
|
138
|
+
* @return [Boolean]
|
139
|
+
*/
|
140
|
+
static VALUE
|
141
|
+
rb_winevt_subscribe_read_existing_events_p(VALUE self)
|
142
|
+
{
|
143
|
+
struct WinevtSubscribe* winevtSubscribe;
|
144
|
+
|
145
|
+
TypedData_Get_Struct(
|
146
|
+
self, struct WinevtSubscribe, &rb_winevt_subscribe_type, winevtSubscribe);
|
147
|
+
|
148
|
+
return winevtSubscribe->readExistingEvents ? Qtrue : Qfalse;
|
149
|
+
}
|
150
|
+
|
151
|
+
/*
|
152
|
+
* Subscribe into a Windows EventLog channel.
|
153
|
+
*
|
154
|
+
* @overload subscribe(path, query, bookmark=nil, session=nil)
|
155
|
+
* @param path [String] Subscribe Channel
|
156
|
+
* @param query [String] Query string for channel
|
157
|
+
* @param bookmark [Bookmark] bookmark Bookmark class instance.
|
158
|
+
* @param session [Session] Session information for remoting access.
|
159
|
+
* @return [Boolean]
|
160
|
+
*
|
161
|
+
*/
|
162
|
+
static VALUE
|
163
|
+
rb_winevt_subscribe_subscribe(int argc, VALUE* argv, VALUE self)
|
164
|
+
{
|
165
|
+
VALUE rb_path, rb_query, rb_bookmark, rb_session;
|
166
|
+
EVT_HANDLE hSubscription = NULL, hBookmark = NULL;
|
167
|
+
HANDLE hSignalEvent;
|
168
|
+
EVT_HANDLE hRemoteHandle = NULL;
|
169
|
+
DWORD len, flags = 0L;
|
170
|
+
DWORD err = ERROR_SUCCESS;
|
171
|
+
VALUE wpathBuf, wqueryBuf, wBookmarkBuf;
|
172
|
+
PWSTR path, query, bookmarkXml;
|
173
|
+
DWORD status = ERROR_SUCCESS;
|
174
|
+
struct WinevtSession* winevtSession;
|
175
|
+
struct WinevtSubscribe* winevtSubscribe;
|
176
|
+
|
177
|
+
hSignalEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
|
178
|
+
|
179
|
+
TypedData_Get_Struct(
|
180
|
+
self, struct WinevtSubscribe, &rb_winevt_subscribe_type, winevtSubscribe);
|
181
|
+
|
182
|
+
rb_scan_args(argc, argv, "22", &rb_path, &rb_query, &rb_bookmark, &rb_session);
|
183
|
+
Check_Type(rb_path, T_STRING);
|
184
|
+
Check_Type(rb_query, T_STRING);
|
185
|
+
|
186
|
+
if (rb_obj_is_kind_of(rb_bookmark, rb_cString)) {
|
187
|
+
// bookmarkXml : To wide char
|
188
|
+
len = MultiByteToWideChar(
|
189
|
+
CP_UTF8, 0, RSTRING_PTR(rb_bookmark), RSTRING_LEN(rb_bookmark), NULL, 0);
|
190
|
+
bookmarkXml = ALLOCV_N(WCHAR, wBookmarkBuf, len + 1);
|
191
|
+
MultiByteToWideChar(CP_UTF8,
|
192
|
+
0,
|
193
|
+
RSTRING_PTR(rb_bookmark),
|
194
|
+
RSTRING_LEN(rb_bookmark),
|
195
|
+
bookmarkXml,
|
196
|
+
len);
|
197
|
+
bookmarkXml[len] = L'\0';
|
198
|
+
hBookmark = EvtCreateBookmark(bookmarkXml);
|
199
|
+
ALLOCV_END(wBookmarkBuf);
|
200
|
+
if (hBookmark == NULL) {
|
201
|
+
status = GetLastError();
|
202
|
+
raise_system_error(rb_eWinevtQueryError, status);
|
203
|
+
}
|
204
|
+
}
|
205
|
+
if (rb_obj_is_kind_of(rb_session, rb_cSession)) {
|
206
|
+
winevtSession = EventSession(rb_session);
|
207
|
+
hRemoteHandle = connect_to_remote(winevtSession->server,
|
208
|
+
winevtSession->domain,
|
209
|
+
winevtSession->username,
|
210
|
+
winevtSession->password,
|
211
|
+
winevtSession->flags,
|
212
|
+
&err);
|
213
|
+
if (err != ERROR_SUCCESS) {
|
214
|
+
raise_system_error(rb_eRuntimeError, err);
|
215
|
+
}
|
216
|
+
}
|
217
|
+
|
218
|
+
// path : To wide char
|
219
|
+
len =
|
220
|
+
MultiByteToWideChar(CP_UTF8, 0, RSTRING_PTR(rb_path), RSTRING_LEN(rb_path), NULL, 0);
|
221
|
+
path = ALLOCV_N(WCHAR, wpathBuf, len + 1);
|
222
|
+
MultiByteToWideChar(CP_UTF8, 0, RSTRING_PTR(rb_path), RSTRING_LEN(rb_path), path, len);
|
223
|
+
path[len] = L'\0';
|
224
|
+
|
225
|
+
// query : To wide char
|
226
|
+
len = MultiByteToWideChar(
|
227
|
+
CP_UTF8, 0, RSTRING_PTR(rb_query), RSTRING_LEN(rb_query), NULL, 0);
|
228
|
+
query = ALLOCV_N(WCHAR, wqueryBuf, len + 1);
|
229
|
+
MultiByteToWideChar(
|
230
|
+
CP_UTF8, 0, RSTRING_PTR(rb_query), RSTRING_LEN(rb_query), query, len);
|
231
|
+
query[len] = L'\0';
|
232
|
+
|
233
|
+
if (hBookmark) {
|
234
|
+
flags |= EvtSubscribeStartAfterBookmark;
|
235
|
+
} else if (winevtSubscribe->readExistingEvents) {
|
236
|
+
flags |= EvtSubscribeStartAtOldestRecord;
|
237
|
+
} else {
|
238
|
+
flags |= EvtSubscribeToFutureEvents;
|
239
|
+
}
|
240
|
+
|
241
|
+
hSubscription =
|
242
|
+
EvtSubscribe(hRemoteHandle, hSignalEvent, path, query, hBookmark, NULL, NULL, flags);
|
243
|
+
if (!hSubscription) {
|
244
|
+
status = GetLastError();
|
245
|
+
if (hBookmark != NULL) {
|
246
|
+
EvtClose(hBookmark);
|
247
|
+
}
|
248
|
+
if (hSignalEvent != NULL) {
|
249
|
+
CloseHandle(hSignalEvent);
|
250
|
+
}
|
251
|
+
if (rb_obj_is_kind_of(rb_session, rb_cSession)) {
|
252
|
+
rb_raise(rb_eRemoteHandlerError, "Remoting subscription is not working. errCode: %ld\n", status);
|
253
|
+
} else {
|
254
|
+
raise_system_error(rb_eWinevtQueryError, status);
|
255
|
+
}
|
256
|
+
}
|
257
|
+
|
258
|
+
if (winevtSubscribe->subscription != NULL) {
|
259
|
+
// should be disgarded the old event subscription handle.
|
260
|
+
EvtClose(winevtSubscribe->subscription);
|
261
|
+
}
|
262
|
+
|
263
|
+
ALLOCV_END(wpathBuf);
|
264
|
+
ALLOCV_END(wqueryBuf);
|
265
|
+
|
266
|
+
winevtSubscribe->signalEvent = hSignalEvent;
|
267
|
+
winevtSubscribe->subscription = hSubscription;
|
268
|
+
winevtSubscribe->remoteHandle = hRemoteHandle;
|
269
|
+
if (hBookmark) {
|
270
|
+
winevtSubscribe->bookmark = hBookmark;
|
271
|
+
} else {
|
272
|
+
winevtSubscribe->bookmark = EvtCreateBookmark(NULL);
|
273
|
+
if (winevtSubscribe->bookmark == NULL) {
|
274
|
+
status = GetLastError();
|
275
|
+
if (hSubscription != NULL) {
|
276
|
+
EvtClose(hSubscription);
|
277
|
+
}
|
278
|
+
if (hSignalEvent != NULL) {
|
279
|
+
CloseHandle(hSignalEvent);
|
280
|
+
}
|
281
|
+
raise_system_error(rb_eWinevtQueryError, status);
|
282
|
+
}
|
283
|
+
}
|
284
|
+
|
285
|
+
return Qtrue;
|
286
|
+
}
|
287
|
+
|
288
|
+
BOOL
|
289
|
+
is_rate_limit_exceeded(struct WinevtSubscribe* winevtSubscribe)
|
290
|
+
{
|
291
|
+
time_t now;
|
292
|
+
|
293
|
+
if (winevtSubscribe->rateLimit == SUBSCRIBE_RATE_INFINITE)
|
294
|
+
return FALSE;
|
295
|
+
|
296
|
+
time(&now);
|
297
|
+
|
298
|
+
if (now <= winevtSubscribe->lastTime) {
|
299
|
+
if (winevtSubscribe->currentRate >= winevtSubscribe->rateLimit) {
|
300
|
+
return TRUE;
|
301
|
+
}
|
302
|
+
} else {
|
303
|
+
winevtSubscribe->currentRate = 0;
|
304
|
+
}
|
305
|
+
|
306
|
+
return FALSE;
|
307
|
+
}
|
308
|
+
|
309
|
+
void
|
310
|
+
update_to_reflect_rate_limit_state(struct WinevtSubscribe* winevtSubscribe, ULONG count)
|
311
|
+
{
|
312
|
+
time_t lastTime = 0;
|
313
|
+
|
314
|
+
if (winevtSubscribe->rateLimit == SUBSCRIBE_RATE_INFINITE)
|
315
|
+
return;
|
316
|
+
|
317
|
+
time(&lastTime);
|
318
|
+
winevtSubscribe->lastTime = lastTime;
|
319
|
+
winevtSubscribe->currentRate += count;
|
320
|
+
}
|
321
|
+
|
322
|
+
/*
|
323
|
+
* Handle the next values. Since v0.6.0, this method is used for
|
324
|
+
* testing only. Please use #each instead.
|
325
|
+
*
|
326
|
+
* @return [Boolean]
|
327
|
+
*
|
328
|
+
* @see each
|
329
|
+
*/
|
330
|
+
|
331
|
+
static VALUE
|
332
|
+
rb_winevt_subscribe_next(VALUE self)
|
333
|
+
{
|
334
|
+
EVT_HANDLE hEvents[SUBSCRIBE_ARRAY_SIZE];
|
335
|
+
ULONG count = 0;
|
336
|
+
DWORD status = ERROR_SUCCESS;
|
337
|
+
struct WinevtSubscribe* winevtSubscribe;
|
338
|
+
|
339
|
+
TypedData_Get_Struct(
|
340
|
+
self, struct WinevtSubscribe, &rb_winevt_subscribe_type, winevtSubscribe);
|
341
|
+
|
342
|
+
if (is_rate_limit_exceeded(winevtSubscribe)) {
|
343
|
+
return Qfalse;
|
344
|
+
}
|
345
|
+
|
346
|
+
/* If subscription handle is NULL, it should return false. */
|
347
|
+
if (!winevtSubscribe->subscription) {
|
348
|
+
return Qfalse;
|
349
|
+
}
|
350
|
+
|
351
|
+
if (!EvtNext(winevtSubscribe->subscription,
|
352
|
+
SUBSCRIBE_ARRAY_SIZE,
|
353
|
+
hEvents,
|
354
|
+
INFINITE,
|
355
|
+
0,
|
356
|
+
&count)) {
|
357
|
+
status = GetLastError();
|
358
|
+
if (ERROR_CANCELLED == status) {
|
359
|
+
return Qfalse;
|
360
|
+
}
|
361
|
+
if (ERROR_NO_MORE_ITEMS != status) {
|
362
|
+
return Qfalse;
|
363
|
+
}
|
364
|
+
}
|
365
|
+
|
366
|
+
if (status == ERROR_SUCCESS) {
|
367
|
+
winevtSubscribe->count = count;
|
368
|
+
for (int i = 0; i < count; i++) {
|
369
|
+
winevtSubscribe->hEvents[i] = hEvents[i];
|
370
|
+
EvtUpdateBookmark(winevtSubscribe->bookmark, winevtSubscribe->hEvents[i]);
|
371
|
+
}
|
372
|
+
|
373
|
+
update_to_reflect_rate_limit_state(winevtSubscribe, count);
|
374
|
+
|
375
|
+
return Qtrue;
|
376
|
+
}
|
377
|
+
|
378
|
+
return Qfalse;
|
379
|
+
}
|
380
|
+
|
381
|
+
static VALUE
|
382
|
+
rb_winevt_subscribe_render(VALUE self, EVT_HANDLE event)
|
383
|
+
{
|
384
|
+
struct WinevtSubscribe* winevtSubscribe;
|
385
|
+
|
386
|
+
TypedData_Get_Struct(
|
387
|
+
self, struct WinevtSubscribe, &rb_winevt_subscribe_type, winevtSubscribe);
|
388
|
+
|
389
|
+
if (winevtSubscribe->renderAsXML) {
|
390
|
+
return render_to_rb_str(event, EvtRenderEventXml);
|
391
|
+
} else {
|
392
|
+
return render_system_event(event, winevtSubscribe->preserveQualifiers);
|
393
|
+
}
|
394
|
+
}
|
395
|
+
|
396
|
+
static VALUE
|
397
|
+
rb_winevt_subscribe_message(EVT_HANDLE event, LocaleInfo* localeInfo, EVT_HANDLE hRemote)
|
398
|
+
{
|
399
|
+
WCHAR* wResult;
|
400
|
+
VALUE utf8str;
|
401
|
+
|
402
|
+
wResult = get_description(event, localeInfo->langID, hRemote);
|
403
|
+
utf8str = wstr_to_rb_str(CP_UTF8, wResult, -1);
|
404
|
+
free(wResult);
|
405
|
+
|
406
|
+
return utf8str;
|
407
|
+
}
|
408
|
+
|
409
|
+
static VALUE
|
410
|
+
rb_winevt_subscribe_string_inserts(EVT_HANDLE event)
|
411
|
+
{
|
412
|
+
return get_values(event);
|
413
|
+
}
|
414
|
+
|
415
|
+
static VALUE
|
416
|
+
rb_winevt_subscribe_close_handle(VALUE self)
|
417
|
+
{
|
418
|
+
struct WinevtSubscribe* winevtSubscribe;
|
419
|
+
|
420
|
+
TypedData_Get_Struct(
|
421
|
+
self, struct WinevtSubscribe, &rb_winevt_subscribe_type, winevtSubscribe);
|
422
|
+
|
423
|
+
for (int i = 0; i < winevtSubscribe->count; i++) {
|
424
|
+
if (winevtSubscribe->hEvents[i] != NULL) {
|
425
|
+
EvtClose(winevtSubscribe->hEvents[i]);
|
426
|
+
winevtSubscribe->hEvents[i] = NULL;
|
427
|
+
}
|
428
|
+
}
|
429
|
+
|
430
|
+
return Qnil;
|
431
|
+
}
|
432
|
+
|
433
|
+
static VALUE
|
434
|
+
rb_winevt_subscribe_each_yield(VALUE self)
|
435
|
+
{
|
436
|
+
RETURN_ENUMERATOR(self, 0, 0);
|
437
|
+
struct WinevtSubscribe* winevtSubscribe;
|
438
|
+
|
439
|
+
TypedData_Get_Struct(
|
440
|
+
self, struct WinevtSubscribe, &rb_winevt_subscribe_type, winevtSubscribe);
|
441
|
+
|
442
|
+
for (int i = 0; i < winevtSubscribe->count; i++) {
|
443
|
+
rb_yield_values(3,
|
444
|
+
rb_winevt_subscribe_render(self, winevtSubscribe->hEvents[i]),
|
445
|
+
rb_winevt_subscribe_message(winevtSubscribe->hEvents[i], winevtSubscribe->localeInfo,
|
446
|
+
winevtSubscribe->remoteHandle),
|
447
|
+
rb_winevt_subscribe_string_inserts(winevtSubscribe->hEvents[i]));
|
448
|
+
}
|
449
|
+
|
450
|
+
return Qnil;
|
451
|
+
}
|
452
|
+
|
453
|
+
/*
|
454
|
+
* Enumerate to obtain Windows EventLog contents.
|
455
|
+
*
|
456
|
+
* This method yields the following:
|
457
|
+
* (Stringified EventLog, Stringified detail message, Stringified
|
458
|
+
* insert values)
|
459
|
+
*
|
460
|
+
* @yield (String,String,String)
|
461
|
+
*
|
462
|
+
*/
|
463
|
+
static VALUE
|
464
|
+
rb_winevt_subscribe_each(VALUE self)
|
465
|
+
{
|
466
|
+
RETURN_ENUMERATOR(self, 0, 0);
|
467
|
+
|
468
|
+
while (rb_winevt_subscribe_next(self)) {
|
469
|
+
rb_ensure(
|
470
|
+
rb_winevt_subscribe_each_yield, self, rb_winevt_subscribe_close_handle, self);
|
471
|
+
}
|
472
|
+
|
473
|
+
return Qnil;
|
474
|
+
}
|
475
|
+
|
476
|
+
/*
|
477
|
+
* This method renders bookmark content which is related to Subscribe class instance.
|
478
|
+
*
|
479
|
+
* @return [String]
|
480
|
+
*/
|
481
|
+
static VALUE
|
482
|
+
rb_winevt_subscribe_get_bookmark(VALUE self)
|
483
|
+
{
|
484
|
+
struct WinevtSubscribe* winevtSubscribe;
|
485
|
+
|
486
|
+
TypedData_Get_Struct(
|
487
|
+
self, struct WinevtSubscribe, &rb_winevt_subscribe_type, winevtSubscribe);
|
488
|
+
|
489
|
+
return render_to_rb_str(winevtSubscribe->bookmark, EvtRenderBookmark);
|
490
|
+
}
|
491
|
+
|
492
|
+
/*
|
493
|
+
* This method returns rate limit value.
|
494
|
+
*
|
495
|
+
* @since 0.6.0
|
496
|
+
* @return [Integer]
|
497
|
+
*/
|
498
|
+
static VALUE
|
499
|
+
rb_winevt_subscribe_get_rate_limit(VALUE self)
|
500
|
+
{
|
501
|
+
struct WinevtSubscribe* winevtSubscribe;
|
502
|
+
|
503
|
+
TypedData_Get_Struct(
|
504
|
+
self, struct WinevtSubscribe, &rb_winevt_subscribe_type, winevtSubscribe);
|
505
|
+
|
506
|
+
return INT2NUM(winevtSubscribe->rateLimit);
|
507
|
+
}
|
508
|
+
|
509
|
+
/*
|
510
|
+
* This method specifies rate limit value.
|
511
|
+
*
|
512
|
+
* @since 0.6.0
|
513
|
+
* @param rb_rate_limit [Integer] rate_limit value
|
514
|
+
*/
|
515
|
+
static VALUE
|
516
|
+
rb_winevt_subscribe_set_rate_limit(VALUE self, VALUE rb_rate_limit)
|
517
|
+
{
|
518
|
+
struct WinevtSubscribe* winevtSubscribe;
|
519
|
+
DWORD rateLimit;
|
520
|
+
|
521
|
+
TypedData_Get_Struct(
|
522
|
+
self, struct WinevtSubscribe, &rb_winevt_subscribe_type, winevtSubscribe);
|
523
|
+
|
524
|
+
rateLimit = NUM2LONG(rb_rate_limit);
|
525
|
+
|
526
|
+
if ((rateLimit != SUBSCRIBE_RATE_INFINITE) && (rateLimit < 10 || rateLimit % 10)) {
|
527
|
+
rb_raise(rb_eArgError, "Specify a multiples of 10 or RATE_INFINITE constant");
|
528
|
+
} else {
|
529
|
+
winevtSubscribe->rateLimit = rateLimit;
|
530
|
+
}
|
531
|
+
|
532
|
+
return Qnil;
|
533
|
+
}
|
534
|
+
|
535
|
+
/*
|
536
|
+
* This method returns whether render as xml or not.
|
537
|
+
*
|
538
|
+
* @since 0.6.0
|
539
|
+
* @return [Boolean]
|
540
|
+
*/
|
541
|
+
static VALUE
|
542
|
+
rb_winevt_subscribe_render_as_xml_p(VALUE self)
|
543
|
+
{
|
544
|
+
struct WinevtSubscribe* winevtSubscribe;
|
545
|
+
|
546
|
+
TypedData_Get_Struct(
|
547
|
+
self, struct WinevtSubscribe, &rb_winevt_subscribe_type, winevtSubscribe);
|
548
|
+
|
549
|
+
return winevtSubscribe->renderAsXML ? Qtrue : Qfalse;
|
550
|
+
}
|
551
|
+
|
552
|
+
/*
|
553
|
+
* This method specifies whether render as xml or not.
|
554
|
+
*
|
555
|
+
* @since 0.6.0
|
556
|
+
* @param rb_render_as_xml [Boolean]
|
557
|
+
*/
|
558
|
+
static VALUE
|
559
|
+
rb_winevt_subscribe_set_render_as_xml(VALUE self, VALUE rb_render_as_xml)
|
560
|
+
{
|
561
|
+
struct WinevtSubscribe* winevtSubscribe;
|
562
|
+
|
563
|
+
TypedData_Get_Struct(
|
564
|
+
self, struct WinevtSubscribe, &rb_winevt_subscribe_type, winevtSubscribe);
|
565
|
+
|
566
|
+
winevtSubscribe->renderAsXML = RTEST(rb_render_as_xml);
|
567
|
+
|
568
|
+
return Qnil;
|
569
|
+
}
|
570
|
+
|
571
|
+
/*
|
572
|
+
* This method specifies whether preserving qualifiers key or not.
|
573
|
+
*
|
574
|
+
* @since 0.7.3
|
575
|
+
* @param rb_preserve_qualifiers [Boolean]
|
576
|
+
*/
|
577
|
+
static VALUE
|
578
|
+
rb_winevt_subscribe_set_preserve_qualifiers(VALUE self, VALUE rb_preserve_qualifiers)
|
579
|
+
{
|
580
|
+
struct WinevtSubscribe* winevtSubscribe;
|
581
|
+
|
582
|
+
TypedData_Get_Struct(
|
583
|
+
self, struct WinevtSubscribe, &rb_winevt_subscribe_type, winevtSubscribe);
|
584
|
+
|
585
|
+
winevtSubscribe->preserveQualifiers = RTEST(rb_preserve_qualifiers);
|
586
|
+
|
587
|
+
return Qnil;
|
588
|
+
}
|
589
|
+
|
590
|
+
/*
|
591
|
+
* This method returns whether preserving qualifiers or not.
|
592
|
+
*
|
593
|
+
* @since 0.7.3
|
594
|
+
* @return [Integer]
|
595
|
+
*/
|
596
|
+
static VALUE
|
597
|
+
rb_winevt_subscribe_get_preserve_qualifiers_p(VALUE self)
|
598
|
+
{
|
599
|
+
struct WinevtSubscribe* winevtSubscribe;
|
600
|
+
|
601
|
+
TypedData_Get_Struct(
|
602
|
+
self, struct WinevtSubscribe, &rb_winevt_subscribe_type, winevtSubscribe);
|
603
|
+
|
604
|
+
return winevtSubscribe->preserveQualifiers ? Qtrue : Qfalse;
|
605
|
+
}
|
606
|
+
|
607
|
+
/*
|
608
|
+
* This method specifies locale with [String].
|
609
|
+
*
|
610
|
+
* @since 0.8.0
|
611
|
+
* @param rb_locale_str [String]
|
612
|
+
*/
|
613
|
+
static VALUE
|
614
|
+
rb_winevt_subscribe_set_locale(VALUE self, VALUE rb_locale_str)
|
615
|
+
{
|
616
|
+
struct WinevtSubscribe* winevtSubscribe;
|
617
|
+
LocaleInfo* locale_info = &default_locale;
|
618
|
+
|
619
|
+
TypedData_Get_Struct(
|
620
|
+
self, struct WinevtSubscribe, &rb_winevt_subscribe_type, winevtSubscribe);
|
621
|
+
|
622
|
+
locale_info = get_locale_info_from_rb_str(rb_locale_str);
|
623
|
+
|
624
|
+
winevtSubscribe->localeInfo = locale_info;
|
625
|
+
|
626
|
+
return Qnil;
|
627
|
+
}
|
628
|
+
|
629
|
+
/*
|
630
|
+
* This method obtains specified locale with [String].
|
631
|
+
*
|
632
|
+
* @since 0.8.0
|
633
|
+
*/
|
634
|
+
static VALUE
|
635
|
+
rb_winevt_subscribe_get_locale(VALUE self)
|
636
|
+
{
|
637
|
+
struct WinevtSubscribe* winevtSubscribe;
|
638
|
+
|
639
|
+
TypedData_Get_Struct(
|
640
|
+
self, struct WinevtSubscribe, &rb_winevt_subscribe_type, winevtSubscribe);
|
641
|
+
|
642
|
+
if (winevtSubscribe->localeInfo->langCode) {
|
643
|
+
return rb_str_new2(winevtSubscribe->localeInfo->langCode);
|
644
|
+
} else {
|
645
|
+
return rb_str_new2(default_locale.langCode);
|
646
|
+
}
|
647
|
+
}
|
648
|
+
|
649
|
+
/*
|
650
|
+
* This method cancels channel subscription.
|
651
|
+
*
|
652
|
+
* @return [Boolean]
|
653
|
+
* @since 0.9.1
|
654
|
+
*/
|
655
|
+
static VALUE
|
656
|
+
rb_winevt_subscribe_cancel(VALUE self)
|
657
|
+
{
|
658
|
+
struct WinevtSubscribe* winevtSubscribe;
|
659
|
+
BOOL result = FALSE;
|
660
|
+
|
661
|
+
TypedData_Get_Struct(
|
662
|
+
self, struct WinevtSubscribe, &rb_winevt_subscribe_type, winevtSubscribe);
|
663
|
+
|
664
|
+
if (winevtSubscribe->subscription) {
|
665
|
+
result = EvtCancel(winevtSubscribe->subscription);
|
666
|
+
}
|
667
|
+
|
668
|
+
if (result) {
|
669
|
+
return Qtrue;
|
670
|
+
} else {
|
671
|
+
return Qfalse;
|
672
|
+
}
|
673
|
+
}
|
674
|
+
|
675
|
+
/*
|
676
|
+
* This method closes channel handles forcibly.
|
677
|
+
*
|
678
|
+
* @since 0.9.1
|
679
|
+
*/
|
680
|
+
static VALUE
|
681
|
+
rb_winevt_subscribe_close(VALUE self)
|
682
|
+
{
|
683
|
+
struct WinevtSubscribe* winevtSubscribe;
|
684
|
+
|
685
|
+
TypedData_Get_Struct(
|
686
|
+
self, struct WinevtSubscribe, &rb_winevt_subscribe_type, winevtSubscribe);
|
687
|
+
|
688
|
+
close_handles(winevtSubscribe);
|
689
|
+
|
690
|
+
return Qnil;
|
691
|
+
}
|
692
|
+
|
693
|
+
|
694
|
+
void
|
695
|
+
Init_winevt_subscribe(VALUE rb_cEventLog)
|
696
|
+
{
|
697
|
+
rb_cSubscribe = rb_define_class_under(rb_cEventLog, "Subscribe", rb_cObject);
|
698
|
+
|
699
|
+
rb_define_alloc_func(rb_cSubscribe, rb_winevt_subscribe_alloc);
|
700
|
+
|
701
|
+
/*
|
702
|
+
* For Subscribe#rate_limit=. It represents unspecified rate limit.
|
703
|
+
* @since 0.6.0
|
704
|
+
*/
|
705
|
+
rb_define_const(rb_cSubscribe, "RATE_INFINITE", SUBSCRIBE_RATE_INFINITE);
|
706
|
+
|
707
|
+
rb_define_method(rb_cSubscribe, "initialize", rb_winevt_subscribe_initialize, 0);
|
708
|
+
rb_define_method(rb_cSubscribe, "subscribe", rb_winevt_subscribe_subscribe, -1);
|
709
|
+
rb_define_method(rb_cSubscribe, "next", rb_winevt_subscribe_next, 0);
|
710
|
+
rb_define_method(rb_cSubscribe, "each", rb_winevt_subscribe_each, 0);
|
711
|
+
rb_define_method(rb_cSubscribe, "bookmark", rb_winevt_subscribe_get_bookmark, 0);
|
712
|
+
/*
|
713
|
+
* @since 0.7.0
|
714
|
+
*/
|
715
|
+
rb_define_method(rb_cSubscribe, "read_existing_events?", rb_winevt_subscribe_read_existing_events_p, 0);
|
716
|
+
/*
|
717
|
+
* @since 0.7.0
|
718
|
+
*/
|
719
|
+
rb_define_method(rb_cSubscribe, "read_existing_events=", rb_winevt_subscribe_set_read_existing_events, 1);
|
720
|
+
rb_define_method(rb_cSubscribe, "rate_limit", rb_winevt_subscribe_get_rate_limit, 0);
|
721
|
+
rb_define_method(rb_cSubscribe, "rate_limit=", rb_winevt_subscribe_set_rate_limit, 1);
|
722
|
+
rb_define_method(
|
723
|
+
rb_cSubscribe, "render_as_xml?", rb_winevt_subscribe_render_as_xml_p, 0);
|
724
|
+
rb_define_method(
|
725
|
+
rb_cSubscribe, "render_as_xml=", rb_winevt_subscribe_set_render_as_xml, 1);
|
726
|
+
/*
|
727
|
+
* @since 0.7.3
|
728
|
+
*/
|
729
|
+
rb_define_method(
|
730
|
+
rb_cSubscribe, "preserve_qualifiers?", rb_winevt_subscribe_get_preserve_qualifiers_p, 0);
|
731
|
+
/*
|
732
|
+
* @since 0.7.3
|
733
|
+
*/
|
734
|
+
rb_define_method(
|
735
|
+
rb_cSubscribe, "preserve_qualifiers=", rb_winevt_subscribe_set_preserve_qualifiers, 1);
|
736
|
+
/*
|
737
|
+
* @since 0.8.0
|
738
|
+
*/
|
739
|
+
rb_define_method(
|
740
|
+
rb_cSubscribe, "locale", rb_winevt_subscribe_get_locale, 0);
|
741
|
+
/*
|
742
|
+
* @since 0.8.0
|
743
|
+
*/
|
744
|
+
rb_define_method(
|
745
|
+
rb_cSubscribe, "locale=", rb_winevt_subscribe_set_locale, 1);
|
746
|
+
/*
|
747
|
+
* @since 0.9.1
|
748
|
+
*/
|
749
|
+
rb_define_method(
|
750
|
+
rb_cSubscribe, "cancel", rb_winevt_subscribe_cancel, 0);
|
751
|
+
/*
|
752
|
+
* @since 0.9.1
|
753
|
+
*/
|
754
|
+
rb_define_method(
|
755
|
+
rb_cSubscribe, "close", rb_winevt_subscribe_close, 0);
|
756
|
+
}
|