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.
@@ -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
+ }