winevt_c 0.9.1 → 0.10.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,650 +1,649 @@
1
- #include <winevt_c.h>
2
-
3
- /* clang-format off */
4
- /*
5
- * Document-class: Winevt::EventLog::Query
6
- *
7
- * Query Windows EventLog channel.
8
- *
9
- * @example
10
- * require 'winevt'
11
- *
12
- * @query = Winevt::EventLog::Query.new("Application", "*[System[(Level <= 3) and TimeCreated[timediff(@SystemTime) <= 86400000]]]")
13
- *
14
- * @query.each do |eventlog, message, string_inserts|
15
- * puts ({eventlog: eventlog, data: message})
16
- * end
17
- */
18
- /* clang-format on */
19
-
20
- VALUE rb_cFlag;
21
-
22
- static void query_free(void* ptr);
23
-
24
- static const rb_data_type_t rb_winevt_query_type = { "winevt/query",
25
- {
26
- 0,
27
- query_free,
28
- 0,
29
- },
30
- NULL,
31
- NULL,
32
- RUBY_TYPED_FREE_IMMEDIATELY };
33
-
34
- static void
35
- close_handles(struct WinevtQuery* winevtQuery)
36
- {
37
- if (winevtQuery->query) {
38
- EvtClose(winevtQuery->query);
39
- winevtQuery->query = NULL;
40
- }
41
-
42
- for (int i = 0; i < winevtQuery->count; i++) {
43
- if (winevtQuery->hEvents[i]) {
44
- EvtClose(winevtQuery->hEvents[i]);
45
- winevtQuery->hEvents[i] = NULL;
46
- }
47
- }
48
-
49
- if (winevtQuery->remoteHandle) {
50
- EvtClose(winevtQuery->remoteHandle);
51
- winevtQuery->remoteHandle = NULL;
52
- }
53
- }
54
-
55
- static void
56
- query_free(void* ptr)
57
- {
58
- struct WinevtQuery* winevtQuery = (struct WinevtQuery*)ptr;
59
- close_handles(winevtQuery);
60
-
61
- xfree(ptr);
62
- }
63
-
64
- static VALUE
65
- rb_winevt_query_alloc(VALUE klass)
66
- {
67
- VALUE obj;
68
- struct WinevtQuery* winevtQuery;
69
- obj =
70
- TypedData_Make_Struct(klass, struct WinevtQuery, &rb_winevt_query_type, winevtQuery);
71
- return obj;
72
- }
73
-
74
- /*
75
- * Initalize Query class.
76
- *
77
- * @overload initialize(channel, xpath, session=nil)
78
- * @param channel [String] Querying EventLog channel.
79
- * @param xpath [String] Querying XPath.
80
- * @param session [Session] Session information for remoting access.
81
- * @return [Query]
82
- *
83
- */
84
- static VALUE
85
- rb_winevt_query_initialize(VALUE argc, VALUE *argv, VALUE self)
86
- {
87
- PWSTR evtChannel, evtXPath;
88
- VALUE channel, xpath, session;
89
- struct WinevtQuery* winevtQuery;
90
- struct WinevtSession* winevtSession;
91
- EVT_HANDLE hRemoteHandle = NULL;
92
- DWORD len;
93
- VALUE wchannelBuf, wpathBuf;
94
- DWORD err;
95
-
96
- rb_scan_args(argc, argv, "21", &channel, &xpath, &session);
97
- Check_Type(channel, T_STRING);
98
- Check_Type(xpath, T_STRING);
99
-
100
- if (rb_obj_is_kind_of(session, rb_cSession)) {
101
- winevtSession = EventSession(session);
102
-
103
- hRemoteHandle = connect_to_remote(winevtSession->server,
104
- winevtSession->domain,
105
- winevtSession->username,
106
- winevtSession->password,
107
- winevtSession->flags);
108
-
109
- err = GetLastError();
110
- if (err != ERROR_SUCCESS) {
111
- raise_system_error(rb_eRuntimeError, err);
112
- }
113
- }
114
-
115
- // channel : To wide char
116
- len =
117
- MultiByteToWideChar(CP_UTF8, 0, RSTRING_PTR(channel), RSTRING_LEN(channel), NULL, 0);
118
- evtChannel = ALLOCV_N(WCHAR, wchannelBuf, len + 1);
119
- MultiByteToWideChar(
120
- CP_UTF8, 0, RSTRING_PTR(channel), RSTRING_LEN(channel), evtChannel, len);
121
- evtChannel[len] = L'\0';
122
-
123
- // xpath : To wide char
124
- len = MultiByteToWideChar(CP_UTF8, 0, RSTRING_PTR(xpath), RSTRING_LEN(xpath), NULL, 0);
125
- evtXPath = ALLOCV_N(WCHAR, wpathBuf, len + 1);
126
- MultiByteToWideChar(CP_UTF8, 0, RSTRING_PTR(xpath), RSTRING_LEN(xpath), evtXPath, len);
127
- evtXPath[len] = L'\0';
128
-
129
- TypedData_Get_Struct(self, struct WinevtQuery, &rb_winevt_query_type, winevtQuery);
130
-
131
- winevtQuery->query = EvtQuery(
132
- hRemoteHandle, evtChannel, evtXPath, EvtQueryChannelPath | EvtQueryTolerateQueryErrors);
133
- err = GetLastError();
134
- if (err != ERROR_SUCCESS) {
135
- raise_system_error(rb_eRuntimeError, err);
136
- }
137
- winevtQuery->offset = 0L;
138
- winevtQuery->timeout = 0L;
139
- winevtQuery->renderAsXML = TRUE;
140
- winevtQuery->preserveQualifiers = FALSE;
141
- winevtQuery->localeInfo = &default_locale;
142
- winevtQuery->remoteHandle = hRemoteHandle;
143
-
144
- ALLOCV_END(wchannelBuf);
145
- ALLOCV_END(wpathBuf);
146
-
147
- return Qnil;
148
- }
149
-
150
- /*
151
- * This method returns querying event offset.
152
- *
153
- * @return [Integer]
154
- */
155
- static VALUE
156
- rb_winevt_query_get_offset(VALUE self)
157
- {
158
- struct WinevtQuery* winevtQuery;
159
-
160
- TypedData_Get_Struct(self, struct WinevtQuery, &rb_winevt_query_type, winevtQuery);
161
-
162
- return LONG2NUM(winevtQuery->offset);
163
- }
164
-
165
- /*
166
- * This method specifies querying event offset.
167
- *
168
- * @param offset [Integer] offset value
169
- */
170
- static VALUE
171
- rb_winevt_query_set_offset(VALUE self, VALUE offset)
172
- {
173
- struct WinevtQuery* winevtQuery;
174
-
175
- TypedData_Get_Struct(self, struct WinevtQuery, &rb_winevt_query_type, winevtQuery);
176
-
177
- winevtQuery->offset = NUM2LONG(offset);
178
-
179
- return Qnil;
180
- }
181
-
182
- /*
183
- * This method returns timeout value.
184
- *
185
- * @return [Integer]
186
- */
187
- static VALUE
188
- rb_winevt_query_get_timeout(VALUE self)
189
- {
190
- struct WinevtQuery* winevtQuery;
191
-
192
- TypedData_Get_Struct(self, struct WinevtQuery, &rb_winevt_query_type, winevtQuery);
193
-
194
- return LONG2NUM(winevtQuery->timeout);
195
- }
196
-
197
- /*
198
- * This method specifies timeout value.
199
- *
200
- * @param timeout [Integer] timeout value
201
- */
202
- static VALUE
203
- rb_winevt_query_set_timeout(VALUE self, VALUE timeout)
204
- {
205
- struct WinevtQuery* winevtQuery;
206
-
207
- TypedData_Get_Struct(self, struct WinevtQuery, &rb_winevt_query_type, winevtQuery);
208
-
209
- winevtQuery->timeout = NUM2LONG(timeout);
210
-
211
- return Qnil;
212
- }
213
-
214
- /*
215
- * Handle the next values. Since v0.6.0, this method is used for
216
- * testing only. Please use #each instead.
217
- *
218
- * @return [Boolean]
219
- *
220
- * @see each
221
- */
222
- static VALUE
223
- rb_winevt_query_next(VALUE self)
224
- {
225
- EVT_HANDLE hEvents[QUERY_ARRAY_SIZE];
226
- ULONG count;
227
- DWORD status = ERROR_SUCCESS;
228
- struct WinevtQuery* winevtQuery;
229
-
230
- TypedData_Get_Struct(self, struct WinevtQuery, &rb_winevt_query_type, winevtQuery);
231
-
232
- if (!EvtNext(winevtQuery->query, QUERY_ARRAY_SIZE, hEvents, INFINITE, 0, &count)) {
233
- status = GetLastError();
234
- if (ERROR_CANCELLED == status) {
235
- return Qfalse;
236
- }
237
- if (ERROR_NO_MORE_ITEMS != status) {
238
- return Qfalse;
239
- }
240
- }
241
-
242
- if (status == ERROR_SUCCESS) {
243
- winevtQuery->count = count;
244
- for (int i = 0; i < count; i++) {
245
- winevtQuery->hEvents[i] = hEvents[i];
246
- }
247
-
248
- return Qtrue;
249
- }
250
-
251
- return Qfalse;
252
- }
253
-
254
- static VALUE
255
- rb_winevt_query_render(VALUE self, EVT_HANDLE event)
256
- {
257
- struct WinevtQuery* winevtQuery;
258
-
259
- TypedData_Get_Struct(self, struct WinevtQuery, &rb_winevt_query_type, winevtQuery);
260
-
261
- if (winevtQuery->renderAsXML) {
262
- return render_to_rb_str(event, EvtRenderEventXml);
263
- } else {
264
- return render_system_event(event, winevtQuery->preserveQualifiers);
265
- }
266
- }
267
-
268
- static VALUE
269
- rb_winevt_query_message(EVT_HANDLE event, LocaleInfo* localeInfo, EVT_HANDLE hRemote)
270
- {
271
- WCHAR* wResult;
272
- VALUE utf8str;
273
-
274
- wResult = get_description(event, localeInfo->langID, hRemote);
275
- utf8str = wstr_to_rb_str(CP_UTF8, wResult, -1);
276
- free(wResult);
277
-
278
- return utf8str;
279
- }
280
-
281
- static VALUE
282
- rb_winevt_query_string_inserts(EVT_HANDLE event)
283
- {
284
- return get_values(event);
285
- }
286
-
287
- static DWORD
288
- get_evt_seek_flag_from_cstr(char* flag_str)
289
- {
290
- if (strcmp(flag_str, "first") == 0)
291
- return EvtSeekRelativeToFirst;
292
- else if (strcmp(flag_str, "last") == 0)
293
- return EvtSeekRelativeToLast;
294
- else if (strcmp(flag_str, "current") == 0)
295
- return EvtSeekRelativeToCurrent;
296
- else if (strcmp(flag_str, "bookmark") == 0)
297
- return EvtSeekRelativeToBookmark;
298
- else if (strcmp(flag_str, "originmask") == 0)
299
- return EvtSeekOriginMask;
300
- else if (strcmp(flag_str, "strict") == 0)
301
- return EvtSeekStrict;
302
- else
303
- rb_raise(rb_eArgError, "Unknown seek flag: %s", flag_str);
304
-
305
- return 0;
306
- }
307
-
308
- /*
309
- * This method specifies seek strategy.
310
- *
311
- * @param bookmark_or_flag [Bookmark|Query::Flag]
312
- * @return [Boolean]
313
- */
314
- static VALUE
315
- rb_winevt_query_seek(VALUE self, VALUE bookmark_or_flag)
316
- {
317
- struct WinevtQuery* winevtQuery;
318
- struct WinevtBookmark* winevtBookmark = NULL;
319
- DWORD flag = 0;
320
-
321
- switch (TYPE(bookmark_or_flag)) {
322
- case T_SYMBOL:
323
- flag = get_evt_seek_flag_from_cstr(RSTRING_PTR(rb_sym2str(bookmark_or_flag)));
324
- break;
325
- case T_STRING:
326
- flag = get_evt_seek_flag_from_cstr(StringValueCStr(bookmark_or_flag));
327
- break;
328
- case T_FIXNUM:
329
- flag = NUM2LONG(bookmark_or_flag);
330
- break;
331
- default:
332
- if (!rb_obj_is_kind_of(bookmark_or_flag, rb_cBookmark))
333
- rb_raise(rb_eArgError, "Expected a String or a Symbol or a Bookmark instance");
334
-
335
- winevtBookmark = EventBookMark(bookmark_or_flag);
336
- }
337
-
338
- if (winevtBookmark) {
339
- TypedData_Get_Struct(self, struct WinevtQuery, &rb_winevt_query_type, winevtQuery);
340
- if (EvtSeek(winevtQuery->query,
341
- winevtQuery->offset,
342
- winevtBookmark->bookmark,
343
- winevtQuery->timeout,
344
- EvtSeekRelativeToBookmark))
345
- return Qtrue;
346
- } else {
347
- TypedData_Get_Struct(self, struct WinevtQuery, &rb_winevt_query_type, winevtQuery);
348
- if (EvtSeek(
349
- winevtQuery->query, winevtQuery->offset, NULL, winevtQuery->timeout, flag)) {
350
- return Qtrue;
351
- }
352
- }
353
-
354
- return Qfalse;
355
- }
356
-
357
- static VALUE
358
- rb_winevt_query_close_handle(VALUE self)
359
- {
360
- struct WinevtQuery* winevtQuery;
361
-
362
- TypedData_Get_Struct(self, struct WinevtQuery, &rb_winevt_query_type, winevtQuery);
363
-
364
- for (int i = 0; i < winevtQuery->count; i++) {
365
- if (winevtQuery->hEvents[i] != NULL) {
366
- EvtClose(winevtQuery->hEvents[i]);
367
- winevtQuery->hEvents[i] = NULL;
368
- }
369
- }
370
-
371
- return Qnil;
372
- }
373
-
374
- static VALUE
375
- rb_winevt_query_each_yield(VALUE self)
376
- {
377
- RETURN_ENUMERATOR(self, 0, 0);
378
-
379
- struct WinevtQuery* winevtQuery;
380
-
381
- TypedData_Get_Struct(self, struct WinevtQuery, &rb_winevt_query_type, winevtQuery);
382
-
383
- for (int i = 0; i < winevtQuery->count; i++) {
384
- rb_yield_values(3,
385
- rb_winevt_query_render(self, winevtQuery->hEvents[i]),
386
- rb_winevt_query_message(winevtQuery->hEvents[i], winevtQuery->localeInfo,
387
- winevtQuery->remoteHandle),
388
- rb_winevt_query_string_inserts(winevtQuery->hEvents[i]));
389
- }
390
- return Qnil;
391
- }
392
-
393
- /*
394
- * Enumerate to obtain Windows EventLog contents.
395
- *
396
- * This method yields the following:
397
- * (Stringified EventLog, Stringified detail message, Stringified
398
- * insert values)
399
- *
400
- * @yield (String,String,String)
401
- *
402
- */
403
- static VALUE
404
- rb_winevt_query_each(VALUE self)
405
- {
406
- RETURN_ENUMERATOR(self, 0, 0);
407
-
408
- while (rb_winevt_query_next(self)) {
409
- rb_ensure(rb_winevt_query_each_yield, self, rb_winevt_query_close_handle, self);
410
- }
411
-
412
- return Qnil;
413
- }
414
-
415
- /*
416
- * This method returns whether render as xml or not.
417
- *
418
- * @return [Boolean]
419
- */
420
- static VALUE
421
- rb_winevt_query_render_as_xml_p(VALUE self)
422
- {
423
- struct WinevtQuery* winevtQuery;
424
-
425
- TypedData_Get_Struct(self, struct WinevtQuery, &rb_winevt_query_type, winevtQuery);
426
-
427
- return winevtQuery->renderAsXML ? Qtrue : Qfalse;
428
- }
429
-
430
- /*
431
- * This method specifies whether render as xml or not.
432
- *
433
- * @param rb_render_as_xml [Boolean]
434
- */
435
- static VALUE
436
- rb_winevt_query_set_render_as_xml(VALUE self, VALUE rb_render_as_xml)
437
- {
438
- struct WinevtQuery* winevtQuery;
439
-
440
- TypedData_Get_Struct(self, struct WinevtQuery, &rb_winevt_query_type, winevtQuery);
441
-
442
- winevtQuery->renderAsXML = RTEST(rb_render_as_xml);
443
-
444
- return Qnil;
445
- }
446
-
447
- /*
448
- * This method specifies whether preserving qualifiers key or not.
449
- *
450
- * @since 0.7.3
451
- * @param rb_preserve_qualifiers [Boolean]
452
- */
453
- static VALUE
454
- rb_winevt_query_set_preserve_qualifiers(VALUE self, VALUE rb_preserve_qualifiers)
455
- {
456
- struct WinevtQuery* winevtQuery;
457
-
458
- TypedData_Get_Struct(
459
- self, struct WinevtQuery, &rb_winevt_query_type, winevtQuery);
460
-
461
- winevtQuery->preserveQualifiers = RTEST(rb_preserve_qualifiers);
462
-
463
- return Qnil;
464
- }
465
-
466
- /*
467
- * This method returns whether preserving qualifiers or not.
468
- *
469
- * @since 0.7.3
470
- * @return [Integer]
471
- */
472
- static VALUE
473
- rb_winevt_query_get_preserve_qualifiers_p(VALUE self)
474
- {
475
- struct WinevtQuery* winevtQuery;
476
-
477
- TypedData_Get_Struct(
478
- self, struct WinevtQuery, &rb_winevt_query_type, winevtQuery);
479
-
480
- return winevtQuery->preserveQualifiers ? Qtrue : Qfalse;
481
- }
482
-
483
- /*
484
- * This method specifies locale with [String].
485
- *
486
- * @since 0.8.0
487
- * @param rb_locale_str [String]
488
- */
489
- static VALUE
490
- rb_winevt_query_set_locale(VALUE self, VALUE rb_locale_str)
491
- {
492
- struct WinevtQuery* winevtQuery;
493
- LocaleInfo* locale_info = &default_locale;
494
-
495
- TypedData_Get_Struct(
496
- self, struct WinevtQuery, &rb_winevt_query_type, winevtQuery);
497
-
498
- locale_info = get_locale_info_from_rb_str(rb_locale_str);
499
-
500
- winevtQuery->localeInfo = locale_info;
501
-
502
- return Qnil;
503
- }
504
-
505
- /*
506
- * This method obtains specified locale with [String].
507
- *
508
- * @since 0.8.0
509
- */
510
- static VALUE
511
- rb_winevt_query_get_locale(VALUE self)
512
- {
513
- struct WinevtQuery* winevtQuery;
514
-
515
- TypedData_Get_Struct(
516
- self, struct WinevtQuery, &rb_winevt_query_type, winevtQuery);
517
-
518
- if (winevtQuery->localeInfo->langCode) {
519
- return rb_str_new2(winevtQuery->localeInfo->langCode);
520
- } else {
521
- return rb_str_new2(default_locale.langCode);
522
- }
523
- }
524
-
525
- /*
526
- * This method cancels channel query.
527
- *
528
- * @return [Boolean]
529
- * @since 0.9.1
530
- */
531
- static VALUE
532
- rb_winevt_query_cancel(VALUE self)
533
- {
534
- struct WinevtQuery* winevtQuery;
535
- BOOL result = FALSE;
536
-
537
- TypedData_Get_Struct(
538
- self, struct WinevtQuery, &rb_winevt_query_type, winevtQuery);
539
-
540
- if (winevtQuery->query) {
541
- result = EvtCancel(winevtQuery->query);
542
- }
543
-
544
- if (result) {
545
- return Qtrue;
546
- } else {
547
- return Qfalse;
548
- }
549
- }
550
-
551
- /*
552
- * This method closes channel handles forcibly.
553
- *
554
- * @since 0.9.1
555
- */
556
- static VALUE
557
- rb_winevt_query_close(VALUE self)
558
- {
559
- struct WinevtQuery* winevtQuery;
560
-
561
- TypedData_Get_Struct(
562
- self, struct WinevtQuery, &rb_winevt_query_type, winevtQuery);
563
-
564
- close_handles(winevtQuery);
565
-
566
- return Qnil;
567
- }
568
-
569
- void
570
- Init_winevt_query(VALUE rb_cEventLog)
571
- {
572
- rb_cQuery = rb_define_class_under(rb_cEventLog, "Query", rb_cObject);
573
- rb_define_alloc_func(rb_cQuery, rb_winevt_query_alloc);
574
-
575
- rb_cFlag = rb_define_module_under(rb_cQuery, "Flag");
576
-
577
- /* clang-format off */
578
- /*
579
- * EVT_SEEK_FLAGS enumeration: EvtSeekRelativeToFirst
580
- * @since 0.6.0
581
- * @see https://msdn.microsoft.com/en-us/windows/desktop/aa385575#EvtSeekRelativeToFirst
582
- */
583
- rb_define_const(rb_cFlag, "RelativeToFirst", LONG2NUM(EvtSeekRelativeToFirst));
584
- /*
585
- * EVT_SEEK_FLAGS enumeration: EvtSeekRelativeToLast
586
- * @since 0.6.0
587
- * @see https://msdn.microsoft.com/en-us/windows/desktop/aa385575#EvtSeekRelativeToLast
588
- */
589
- rb_define_const(rb_cFlag, "RelativeToLast", LONG2NUM(EvtSeekRelativeToLast));
590
- /*
591
- * EVT_SEEK_FLAGS enumeration: EvtSeekRelativeToCurrent
592
- * @since 0.6.0
593
- * @see https://msdn.microsoft.com/en-us/windows/desktop/aa385575#EvtSeekRelativeToCurrent
594
- */
595
- rb_define_const(rb_cFlag, "RelativeToCurrent", LONG2NUM(EvtSeekRelativeToCurrent));
596
- /*
597
- * EVT_SEEK_FLAGS enumeration: EvtSeekRelativeToBookmark
598
- * @since 0.6.0
599
- * @see https://msdn.microsoft.com/en-us/windows/desktop/aa385575#EvtSeekRelativeToBookmark
600
- */
601
- rb_define_const(rb_cFlag, "RelativeToBookmark", LONG2NUM(EvtSeekRelativeToBookmark));
602
- /*
603
- * EVT_SEEK_FLAGS enumeration: EvtSeekOriginMask
604
- * @since 0.6.0
605
- * @see https://msdn.microsoft.com/en-us/windows/desktop/aa385575#EvtSeekOriginMask
606
- */
607
- rb_define_const(rb_cFlag, "OriginMask", LONG2NUM(EvtSeekOriginMask));
608
- /*
609
- * EVT_SEEK_FLAGS enumeration: EvtSeekStrict
610
- * @since 0.6.0
611
- * @see https://msdn.microsoft.com/en-us/windows/desktop/aa385575#EvtSeekStrict
612
- */
613
- rb_define_const(rb_cFlag, "Strict", LONG2NUM(EvtSeekStrict));
614
- /* clang-format on */
615
-
616
- rb_define_method(rb_cQuery, "initialize", rb_winevt_query_initialize, -1);
617
- rb_define_method(rb_cQuery, "next", rb_winevt_query_next, 0);
618
- rb_define_method(rb_cQuery, "seek", rb_winevt_query_seek, 1);
619
- rb_define_method(rb_cQuery, "offset", rb_winevt_query_get_offset, 0);
620
- rb_define_method(rb_cQuery, "offset=", rb_winevt_query_set_offset, 1);
621
- rb_define_method(rb_cQuery, "timeout", rb_winevt_query_get_timeout, 0);
622
- rb_define_method(rb_cQuery, "timeout=", rb_winevt_query_set_timeout, 1);
623
- rb_define_method(rb_cQuery, "each", rb_winevt_query_each, 0);
624
- rb_define_method(rb_cQuery, "render_as_xml?", rb_winevt_query_render_as_xml_p, 0);
625
- rb_define_method(rb_cQuery, "render_as_xml=", rb_winevt_query_set_render_as_xml, 1);
626
- /*
627
- * @since 0.7.3
628
- */
629
- rb_define_method(rb_cQuery, "preserve_qualifiers?", rb_winevt_query_get_preserve_qualifiers_p, 0);
630
- /*
631
- * @since 0.7.3
632
- */
633
- rb_define_method(rb_cQuery, "preserve_qualifiers=", rb_winevt_query_set_preserve_qualifiers, 1);
634
- /*
635
- * @since 0.8.0
636
- */
637
- rb_define_method(rb_cQuery, "locale", rb_winevt_query_get_locale, 0);
638
- /*
639
- * @since 0.8.0
640
- */
641
- rb_define_method(rb_cQuery, "locale=", rb_winevt_query_set_locale, 1);
642
- /*
643
- * @since 0.9.1
644
- */
645
- rb_define_method(rb_cQuery, "cancel", rb_winevt_query_cancel, 0);
646
- /*
647
- * @since 0.9.1
648
- */
649
- rb_define_method(rb_cQuery, "close", rb_winevt_query_close, 0);
650
- }
1
+ #include <winevt_c.h>
2
+
3
+ /* clang-format off */
4
+ /*
5
+ * Document-class: Winevt::EventLog::Query
6
+ *
7
+ * Query Windows EventLog channel.
8
+ *
9
+ * @example
10
+ * require 'winevt'
11
+ *
12
+ * @query = Winevt::EventLog::Query.new("Application", "*[System[(Level <= 3) and TimeCreated[timediff(@SystemTime) <= 86400000]]]")
13
+ *
14
+ * @query.each do |eventlog, message, string_inserts|
15
+ * puts ({eventlog: eventlog, data: message})
16
+ * end
17
+ */
18
+ /* clang-format on */
19
+
20
+ VALUE rb_cFlag;
21
+
22
+ static void query_free(void* ptr);
23
+
24
+ static const rb_data_type_t rb_winevt_query_type = { "winevt/query",
25
+ {
26
+ 0,
27
+ query_free,
28
+ 0,
29
+ },
30
+ NULL,
31
+ NULL,
32
+ RUBY_TYPED_FREE_IMMEDIATELY };
33
+
34
+ static void
35
+ close_handles(struct WinevtQuery* winevtQuery)
36
+ {
37
+ if (winevtQuery->query) {
38
+ EvtClose(winevtQuery->query);
39
+ winevtQuery->query = NULL;
40
+ }
41
+
42
+ for (int i = 0; i < winevtQuery->count; i++) {
43
+ if (winevtQuery->hEvents[i]) {
44
+ EvtClose(winevtQuery->hEvents[i]);
45
+ winevtQuery->hEvents[i] = NULL;
46
+ }
47
+ }
48
+
49
+ if (winevtQuery->remoteHandle) {
50
+ EvtClose(winevtQuery->remoteHandle);
51
+ winevtQuery->remoteHandle = NULL;
52
+ }
53
+ }
54
+
55
+ static void
56
+ query_free(void* ptr)
57
+ {
58
+ struct WinevtQuery* winevtQuery = (struct WinevtQuery*)ptr;
59
+ close_handles(winevtQuery);
60
+
61
+ xfree(ptr);
62
+ }
63
+
64
+ static VALUE
65
+ rb_winevt_query_alloc(VALUE klass)
66
+ {
67
+ VALUE obj;
68
+ struct WinevtQuery* winevtQuery;
69
+ obj =
70
+ TypedData_Make_Struct(klass, struct WinevtQuery, &rb_winevt_query_type, winevtQuery);
71
+ return obj;
72
+ }
73
+
74
+ /*
75
+ * Initalize Query class.
76
+ *
77
+ * @overload initialize(channel, xpath, session=nil)
78
+ * @param channel [String] Querying EventLog channel.
79
+ * @param xpath [String] Querying XPath.
80
+ * @param session [Session] Session information for remoting access.
81
+ * @return [Query]
82
+ *
83
+ */
84
+ static VALUE
85
+ rb_winevt_query_initialize(VALUE argc, VALUE *argv, VALUE self)
86
+ {
87
+ PWSTR evtChannel, evtXPath;
88
+ VALUE channel, xpath, session;
89
+ struct WinevtQuery* winevtQuery;
90
+ struct WinevtSession* winevtSession;
91
+ EVT_HANDLE hRemoteHandle = NULL;
92
+ DWORD len;
93
+ VALUE wchannelBuf, wpathBuf;
94
+ DWORD err = ERROR_SUCCESS;
95
+
96
+ rb_scan_args(argc, argv, "21", &channel, &xpath, &session);
97
+ Check_Type(channel, T_STRING);
98
+ Check_Type(xpath, T_STRING);
99
+
100
+ if (rb_obj_is_kind_of(session, rb_cSession)) {
101
+ winevtSession = EventSession(session);
102
+
103
+ hRemoteHandle = connect_to_remote(winevtSession->server,
104
+ winevtSession->domain,
105
+ winevtSession->username,
106
+ winevtSession->password,
107
+ winevtSession->flags,
108
+ &err);
109
+ if (err != ERROR_SUCCESS) {
110
+ raise_system_error(rb_eRuntimeError, err);
111
+ }
112
+ }
113
+
114
+ // channel : To wide char
115
+ len =
116
+ MultiByteToWideChar(CP_UTF8, 0, RSTRING_PTR(channel), RSTRING_LEN(channel), NULL, 0);
117
+ evtChannel = ALLOCV_N(WCHAR, wchannelBuf, len + 1);
118
+ MultiByteToWideChar(
119
+ CP_UTF8, 0, RSTRING_PTR(channel), RSTRING_LEN(channel), evtChannel, len);
120
+ evtChannel[len] = L'\0';
121
+
122
+ // xpath : To wide char
123
+ len = MultiByteToWideChar(CP_UTF8, 0, RSTRING_PTR(xpath), RSTRING_LEN(xpath), NULL, 0);
124
+ evtXPath = ALLOCV_N(WCHAR, wpathBuf, len + 1);
125
+ MultiByteToWideChar(CP_UTF8, 0, RSTRING_PTR(xpath), RSTRING_LEN(xpath), evtXPath, len);
126
+ evtXPath[len] = L'\0';
127
+
128
+ TypedData_Get_Struct(self, struct WinevtQuery, &rb_winevt_query_type, winevtQuery);
129
+
130
+ winevtQuery->query = EvtQuery(
131
+ hRemoteHandle, evtChannel, evtXPath, EvtQueryChannelPath | EvtQueryTolerateQueryErrors);
132
+ err = GetLastError();
133
+ if (err != ERROR_SUCCESS) {
134
+ raise_system_error(rb_eRuntimeError, err);
135
+ }
136
+ winevtQuery->offset = 0L;
137
+ winevtQuery->timeout = 0L;
138
+ winevtQuery->renderAsXML = TRUE;
139
+ winevtQuery->preserveQualifiers = FALSE;
140
+ winevtQuery->localeInfo = &default_locale;
141
+ winevtQuery->remoteHandle = hRemoteHandle;
142
+
143
+ ALLOCV_END(wchannelBuf);
144
+ ALLOCV_END(wpathBuf);
145
+
146
+ return Qnil;
147
+ }
148
+
149
+ /*
150
+ * This method returns querying event offset.
151
+ *
152
+ * @return [Integer]
153
+ */
154
+ static VALUE
155
+ rb_winevt_query_get_offset(VALUE self)
156
+ {
157
+ struct WinevtQuery* winevtQuery;
158
+
159
+ TypedData_Get_Struct(self, struct WinevtQuery, &rb_winevt_query_type, winevtQuery);
160
+
161
+ return LONG2NUM(winevtQuery->offset);
162
+ }
163
+
164
+ /*
165
+ * This method specifies querying event offset.
166
+ *
167
+ * @param offset [Integer] offset value
168
+ */
169
+ static VALUE
170
+ rb_winevt_query_set_offset(VALUE self, VALUE offset)
171
+ {
172
+ struct WinevtQuery* winevtQuery;
173
+
174
+ TypedData_Get_Struct(self, struct WinevtQuery, &rb_winevt_query_type, winevtQuery);
175
+
176
+ winevtQuery->offset = NUM2LONG(offset);
177
+
178
+ return Qnil;
179
+ }
180
+
181
+ /*
182
+ * This method returns timeout value.
183
+ *
184
+ * @return [Integer]
185
+ */
186
+ static VALUE
187
+ rb_winevt_query_get_timeout(VALUE self)
188
+ {
189
+ struct WinevtQuery* winevtQuery;
190
+
191
+ TypedData_Get_Struct(self, struct WinevtQuery, &rb_winevt_query_type, winevtQuery);
192
+
193
+ return LONG2NUM(winevtQuery->timeout);
194
+ }
195
+
196
+ /*
197
+ * This method specifies timeout value.
198
+ *
199
+ * @param timeout [Integer] timeout value
200
+ */
201
+ static VALUE
202
+ rb_winevt_query_set_timeout(VALUE self, VALUE timeout)
203
+ {
204
+ struct WinevtQuery* winevtQuery;
205
+
206
+ TypedData_Get_Struct(self, struct WinevtQuery, &rb_winevt_query_type, winevtQuery);
207
+
208
+ winevtQuery->timeout = NUM2LONG(timeout);
209
+
210
+ return Qnil;
211
+ }
212
+
213
+ /*
214
+ * Handle the next values. Since v0.6.0, this method is used for
215
+ * testing only. Please use #each instead.
216
+ *
217
+ * @return [Boolean]
218
+ *
219
+ * @see each
220
+ */
221
+ static VALUE
222
+ rb_winevt_query_next(VALUE self)
223
+ {
224
+ EVT_HANDLE hEvents[QUERY_ARRAY_SIZE];
225
+ ULONG count;
226
+ DWORD status = ERROR_SUCCESS;
227
+ struct WinevtQuery* winevtQuery;
228
+
229
+ TypedData_Get_Struct(self, struct WinevtQuery, &rb_winevt_query_type, winevtQuery);
230
+
231
+ if (!EvtNext(winevtQuery->query, QUERY_ARRAY_SIZE, hEvents, INFINITE, 0, &count)) {
232
+ status = GetLastError();
233
+ if (ERROR_CANCELLED == status) {
234
+ return Qfalse;
235
+ }
236
+ if (ERROR_NO_MORE_ITEMS != status) {
237
+ return Qfalse;
238
+ }
239
+ }
240
+
241
+ if (status == ERROR_SUCCESS) {
242
+ winevtQuery->count = count;
243
+ for (int i = 0; i < count; i++) {
244
+ winevtQuery->hEvents[i] = hEvents[i];
245
+ }
246
+
247
+ return Qtrue;
248
+ }
249
+
250
+ return Qfalse;
251
+ }
252
+
253
+ static VALUE
254
+ rb_winevt_query_render(VALUE self, EVT_HANDLE event)
255
+ {
256
+ struct WinevtQuery* winevtQuery;
257
+
258
+ TypedData_Get_Struct(self, struct WinevtQuery, &rb_winevt_query_type, winevtQuery);
259
+
260
+ if (winevtQuery->renderAsXML) {
261
+ return render_to_rb_str(event, EvtRenderEventXml);
262
+ } else {
263
+ return render_system_event(event, winevtQuery->preserveQualifiers);
264
+ }
265
+ }
266
+
267
+ static VALUE
268
+ rb_winevt_query_message(EVT_HANDLE event, LocaleInfo* localeInfo, EVT_HANDLE hRemote)
269
+ {
270
+ WCHAR* wResult;
271
+ VALUE utf8str;
272
+
273
+ wResult = get_description(event, localeInfo->langID, hRemote);
274
+ utf8str = wstr_to_rb_str(CP_UTF8, wResult, -1);
275
+ free(wResult);
276
+
277
+ return utf8str;
278
+ }
279
+
280
+ static VALUE
281
+ rb_winevt_query_string_inserts(EVT_HANDLE event)
282
+ {
283
+ return get_values(event);
284
+ }
285
+
286
+ static DWORD
287
+ get_evt_seek_flag_from_cstr(char* flag_str)
288
+ {
289
+ if (strcmp(flag_str, "first") == 0)
290
+ return EvtSeekRelativeToFirst;
291
+ else if (strcmp(flag_str, "last") == 0)
292
+ return EvtSeekRelativeToLast;
293
+ else if (strcmp(flag_str, "current") == 0)
294
+ return EvtSeekRelativeToCurrent;
295
+ else if (strcmp(flag_str, "bookmark") == 0)
296
+ return EvtSeekRelativeToBookmark;
297
+ else if (strcmp(flag_str, "originmask") == 0)
298
+ return EvtSeekOriginMask;
299
+ else if (strcmp(flag_str, "strict") == 0)
300
+ return EvtSeekStrict;
301
+ else
302
+ rb_raise(rb_eArgError, "Unknown seek flag: %s", flag_str);
303
+
304
+ return 0;
305
+ }
306
+
307
+ /*
308
+ * This method specifies seek strategy.
309
+ *
310
+ * @param bookmark_or_flag [Bookmark|Query::Flag]
311
+ * @return [Boolean]
312
+ */
313
+ static VALUE
314
+ rb_winevt_query_seek(VALUE self, VALUE bookmark_or_flag)
315
+ {
316
+ struct WinevtQuery* winevtQuery;
317
+ struct WinevtBookmark* winevtBookmark = NULL;
318
+ DWORD flag = 0;
319
+
320
+ switch (TYPE(bookmark_or_flag)) {
321
+ case T_SYMBOL:
322
+ flag = get_evt_seek_flag_from_cstr(RSTRING_PTR(rb_sym2str(bookmark_or_flag)));
323
+ break;
324
+ case T_STRING:
325
+ flag = get_evt_seek_flag_from_cstr(StringValueCStr(bookmark_or_flag));
326
+ break;
327
+ case T_FIXNUM:
328
+ flag = NUM2LONG(bookmark_or_flag);
329
+ break;
330
+ default:
331
+ if (!rb_obj_is_kind_of(bookmark_or_flag, rb_cBookmark))
332
+ rb_raise(rb_eArgError, "Expected a String or a Symbol or a Bookmark instance");
333
+
334
+ winevtBookmark = EventBookMark(bookmark_or_flag);
335
+ }
336
+
337
+ if (winevtBookmark) {
338
+ TypedData_Get_Struct(self, struct WinevtQuery, &rb_winevt_query_type, winevtQuery);
339
+ if (EvtSeek(winevtQuery->query,
340
+ winevtQuery->offset,
341
+ winevtBookmark->bookmark,
342
+ winevtQuery->timeout,
343
+ EvtSeekRelativeToBookmark))
344
+ return Qtrue;
345
+ } else {
346
+ TypedData_Get_Struct(self, struct WinevtQuery, &rb_winevt_query_type, winevtQuery);
347
+ if (EvtSeek(
348
+ winevtQuery->query, winevtQuery->offset, NULL, winevtQuery->timeout, flag)) {
349
+ return Qtrue;
350
+ }
351
+ }
352
+
353
+ return Qfalse;
354
+ }
355
+
356
+ static VALUE
357
+ rb_winevt_query_close_handle(VALUE self)
358
+ {
359
+ struct WinevtQuery* winevtQuery;
360
+
361
+ TypedData_Get_Struct(self, struct WinevtQuery, &rb_winevt_query_type, winevtQuery);
362
+
363
+ for (int i = 0; i < winevtQuery->count; i++) {
364
+ if (winevtQuery->hEvents[i] != NULL) {
365
+ EvtClose(winevtQuery->hEvents[i]);
366
+ winevtQuery->hEvents[i] = NULL;
367
+ }
368
+ }
369
+
370
+ return Qnil;
371
+ }
372
+
373
+ static VALUE
374
+ rb_winevt_query_each_yield(VALUE self)
375
+ {
376
+ RETURN_ENUMERATOR(self, 0, 0);
377
+
378
+ struct WinevtQuery* winevtQuery;
379
+
380
+ TypedData_Get_Struct(self, struct WinevtQuery, &rb_winevt_query_type, winevtQuery);
381
+
382
+ for (int i = 0; i < winevtQuery->count; i++) {
383
+ rb_yield_values(3,
384
+ rb_winevt_query_render(self, winevtQuery->hEvents[i]),
385
+ rb_winevt_query_message(winevtQuery->hEvents[i], winevtQuery->localeInfo,
386
+ winevtQuery->remoteHandle),
387
+ rb_winevt_query_string_inserts(winevtQuery->hEvents[i]));
388
+ }
389
+ return Qnil;
390
+ }
391
+
392
+ /*
393
+ * Enumerate to obtain Windows EventLog contents.
394
+ *
395
+ * This method yields the following:
396
+ * (Stringified EventLog, Stringified detail message, Stringified
397
+ * insert values)
398
+ *
399
+ * @yield (String,String,String)
400
+ *
401
+ */
402
+ static VALUE
403
+ rb_winevt_query_each(VALUE self)
404
+ {
405
+ RETURN_ENUMERATOR(self, 0, 0);
406
+
407
+ while (rb_winevt_query_next(self)) {
408
+ rb_ensure(rb_winevt_query_each_yield, self, rb_winevt_query_close_handle, self);
409
+ }
410
+
411
+ return Qnil;
412
+ }
413
+
414
+ /*
415
+ * This method returns whether render as xml or not.
416
+ *
417
+ * @return [Boolean]
418
+ */
419
+ static VALUE
420
+ rb_winevt_query_render_as_xml_p(VALUE self)
421
+ {
422
+ struct WinevtQuery* winevtQuery;
423
+
424
+ TypedData_Get_Struct(self, struct WinevtQuery, &rb_winevt_query_type, winevtQuery);
425
+
426
+ return winevtQuery->renderAsXML ? Qtrue : Qfalse;
427
+ }
428
+
429
+ /*
430
+ * This method specifies whether render as xml or not.
431
+ *
432
+ * @param rb_render_as_xml [Boolean]
433
+ */
434
+ static VALUE
435
+ rb_winevt_query_set_render_as_xml(VALUE self, VALUE rb_render_as_xml)
436
+ {
437
+ struct WinevtQuery* winevtQuery;
438
+
439
+ TypedData_Get_Struct(self, struct WinevtQuery, &rb_winevt_query_type, winevtQuery);
440
+
441
+ winevtQuery->renderAsXML = RTEST(rb_render_as_xml);
442
+
443
+ return Qnil;
444
+ }
445
+
446
+ /*
447
+ * This method specifies whether preserving qualifiers key or not.
448
+ *
449
+ * @since 0.7.3
450
+ * @param rb_preserve_qualifiers [Boolean]
451
+ */
452
+ static VALUE
453
+ rb_winevt_query_set_preserve_qualifiers(VALUE self, VALUE rb_preserve_qualifiers)
454
+ {
455
+ struct WinevtQuery* winevtQuery;
456
+
457
+ TypedData_Get_Struct(
458
+ self, struct WinevtQuery, &rb_winevt_query_type, winevtQuery);
459
+
460
+ winevtQuery->preserveQualifiers = RTEST(rb_preserve_qualifiers);
461
+
462
+ return Qnil;
463
+ }
464
+
465
+ /*
466
+ * This method returns whether preserving qualifiers or not.
467
+ *
468
+ * @since 0.7.3
469
+ * @return [Integer]
470
+ */
471
+ static VALUE
472
+ rb_winevt_query_get_preserve_qualifiers_p(VALUE self)
473
+ {
474
+ struct WinevtQuery* winevtQuery;
475
+
476
+ TypedData_Get_Struct(
477
+ self, struct WinevtQuery, &rb_winevt_query_type, winevtQuery);
478
+
479
+ return winevtQuery->preserveQualifiers ? Qtrue : Qfalse;
480
+ }
481
+
482
+ /*
483
+ * This method specifies locale with [String].
484
+ *
485
+ * @since 0.8.0
486
+ * @param rb_locale_str [String]
487
+ */
488
+ static VALUE
489
+ rb_winevt_query_set_locale(VALUE self, VALUE rb_locale_str)
490
+ {
491
+ struct WinevtQuery* winevtQuery;
492
+ LocaleInfo* locale_info = &default_locale;
493
+
494
+ TypedData_Get_Struct(
495
+ self, struct WinevtQuery, &rb_winevt_query_type, winevtQuery);
496
+
497
+ locale_info = get_locale_info_from_rb_str(rb_locale_str);
498
+
499
+ winevtQuery->localeInfo = locale_info;
500
+
501
+ return Qnil;
502
+ }
503
+
504
+ /*
505
+ * This method obtains specified locale with [String].
506
+ *
507
+ * @since 0.8.0
508
+ */
509
+ static VALUE
510
+ rb_winevt_query_get_locale(VALUE self)
511
+ {
512
+ struct WinevtQuery* winevtQuery;
513
+
514
+ TypedData_Get_Struct(
515
+ self, struct WinevtQuery, &rb_winevt_query_type, winevtQuery);
516
+
517
+ if (winevtQuery->localeInfo->langCode) {
518
+ return rb_str_new2(winevtQuery->localeInfo->langCode);
519
+ } else {
520
+ return rb_str_new2(default_locale.langCode);
521
+ }
522
+ }
523
+
524
+ /*
525
+ * This method cancels channel query.
526
+ *
527
+ * @return [Boolean]
528
+ * @since 0.9.1
529
+ */
530
+ static VALUE
531
+ rb_winevt_query_cancel(VALUE self)
532
+ {
533
+ struct WinevtQuery* winevtQuery;
534
+ BOOL result = FALSE;
535
+
536
+ TypedData_Get_Struct(
537
+ self, struct WinevtQuery, &rb_winevt_query_type, winevtQuery);
538
+
539
+ if (winevtQuery->query) {
540
+ result = EvtCancel(winevtQuery->query);
541
+ }
542
+
543
+ if (result) {
544
+ return Qtrue;
545
+ } else {
546
+ return Qfalse;
547
+ }
548
+ }
549
+
550
+ /*
551
+ * This method closes channel handles forcibly.
552
+ *
553
+ * @since 0.9.1
554
+ */
555
+ static VALUE
556
+ rb_winevt_query_close(VALUE self)
557
+ {
558
+ struct WinevtQuery* winevtQuery;
559
+
560
+ TypedData_Get_Struct(
561
+ self, struct WinevtQuery, &rb_winevt_query_type, winevtQuery);
562
+
563
+ close_handles(winevtQuery);
564
+
565
+ return Qnil;
566
+ }
567
+
568
+ void
569
+ Init_winevt_query(VALUE rb_cEventLog)
570
+ {
571
+ rb_cQuery = rb_define_class_under(rb_cEventLog, "Query", rb_cObject);
572
+ rb_define_alloc_func(rb_cQuery, rb_winevt_query_alloc);
573
+
574
+ rb_cFlag = rb_define_module_under(rb_cQuery, "Flag");
575
+
576
+ /* clang-format off */
577
+ /*
578
+ * EVT_SEEK_FLAGS enumeration: EvtSeekRelativeToFirst
579
+ * @since 0.6.0
580
+ * @see https://msdn.microsoft.com/en-us/windows/desktop/aa385575#EvtSeekRelativeToFirst
581
+ */
582
+ rb_define_const(rb_cFlag, "RelativeToFirst", LONG2NUM(EvtSeekRelativeToFirst));
583
+ /*
584
+ * EVT_SEEK_FLAGS enumeration: EvtSeekRelativeToLast
585
+ * @since 0.6.0
586
+ * @see https://msdn.microsoft.com/en-us/windows/desktop/aa385575#EvtSeekRelativeToLast
587
+ */
588
+ rb_define_const(rb_cFlag, "RelativeToLast", LONG2NUM(EvtSeekRelativeToLast));
589
+ /*
590
+ * EVT_SEEK_FLAGS enumeration: EvtSeekRelativeToCurrent
591
+ * @since 0.6.0
592
+ * @see https://msdn.microsoft.com/en-us/windows/desktop/aa385575#EvtSeekRelativeToCurrent
593
+ */
594
+ rb_define_const(rb_cFlag, "RelativeToCurrent", LONG2NUM(EvtSeekRelativeToCurrent));
595
+ /*
596
+ * EVT_SEEK_FLAGS enumeration: EvtSeekRelativeToBookmark
597
+ * @since 0.6.0
598
+ * @see https://msdn.microsoft.com/en-us/windows/desktop/aa385575#EvtSeekRelativeToBookmark
599
+ */
600
+ rb_define_const(rb_cFlag, "RelativeToBookmark", LONG2NUM(EvtSeekRelativeToBookmark));
601
+ /*
602
+ * EVT_SEEK_FLAGS enumeration: EvtSeekOriginMask
603
+ * @since 0.6.0
604
+ * @see https://msdn.microsoft.com/en-us/windows/desktop/aa385575#EvtSeekOriginMask
605
+ */
606
+ rb_define_const(rb_cFlag, "OriginMask", LONG2NUM(EvtSeekOriginMask));
607
+ /*
608
+ * EVT_SEEK_FLAGS enumeration: EvtSeekStrict
609
+ * @since 0.6.0
610
+ * @see https://msdn.microsoft.com/en-us/windows/desktop/aa385575#EvtSeekStrict
611
+ */
612
+ rb_define_const(rb_cFlag, "Strict", LONG2NUM(EvtSeekStrict));
613
+ /* clang-format on */
614
+
615
+ rb_define_method(rb_cQuery, "initialize", rb_winevt_query_initialize, -1);
616
+ rb_define_method(rb_cQuery, "next", rb_winevt_query_next, 0);
617
+ rb_define_method(rb_cQuery, "seek", rb_winevt_query_seek, 1);
618
+ rb_define_method(rb_cQuery, "offset", rb_winevt_query_get_offset, 0);
619
+ rb_define_method(rb_cQuery, "offset=", rb_winevt_query_set_offset, 1);
620
+ rb_define_method(rb_cQuery, "timeout", rb_winevt_query_get_timeout, 0);
621
+ rb_define_method(rb_cQuery, "timeout=", rb_winevt_query_set_timeout, 1);
622
+ rb_define_method(rb_cQuery, "each", rb_winevt_query_each, 0);
623
+ rb_define_method(rb_cQuery, "render_as_xml?", rb_winevt_query_render_as_xml_p, 0);
624
+ rb_define_method(rb_cQuery, "render_as_xml=", rb_winevt_query_set_render_as_xml, 1);
625
+ /*
626
+ * @since 0.7.3
627
+ */
628
+ rb_define_method(rb_cQuery, "preserve_qualifiers?", rb_winevt_query_get_preserve_qualifiers_p, 0);
629
+ /*
630
+ * @since 0.7.3
631
+ */
632
+ rb_define_method(rb_cQuery, "preserve_qualifiers=", rb_winevt_query_set_preserve_qualifiers, 1);
633
+ /*
634
+ * @since 0.8.0
635
+ */
636
+ rb_define_method(rb_cQuery, "locale", rb_winevt_query_get_locale, 0);
637
+ /*
638
+ * @since 0.8.0
639
+ */
640
+ rb_define_method(rb_cQuery, "locale=", rb_winevt_query_set_locale, 1);
641
+ /*
642
+ * @since 0.9.1
643
+ */
644
+ rb_define_method(rb_cQuery, "cancel", rb_winevt_query_cancel, 0);
645
+ /*
646
+ * @since 0.9.1
647
+ */
648
+ rb_define_method(rb_cQuery, "close", rb_winevt_query_close, 0);
649
+ }