package Win32::WQL;
use strict;
use Win32::OLE; #  qw(EVENTS);
# Events support will follow later
use parent 'Class::Accessor';

=head1 NAME

Win32::WQL - DBI-like wrapper for the WMI


  use Win32::WQL;
  my $wmi = Win32::WQL->new( machine => 'remote_computer' );
  my $sth = $wmi->prepare(<<'WQL');

    ASSOCIATORS OF {Win32_Directory.Name='C:\\WINNT'}
    WHERE ResultClass = CIM_DataFile


  my $remote_files = $sth->execute;
  while (my $file = $remote_files->fetch()) {
      print $file->{Name},"\n";


This module implements a bare bones DBI clone
which is similar yet different. You will most likely
want to use the real thing, L<DBD::WMI>, which
is a compatibility layer over this module.


our $VERSION = '0.11';

Win32::OLE->Option(Warn => 3);

__PACKAGE__->mk_accessors(qw(statement_class event_iterator_class collection_iterator_class wmi));

=head1 METHODS

=head2 C<< new %ARGS >>

Initializes the thin wrapper over the L<Win32::OLE>
WMI instance. All parameters are optional.


The parameter is the machine name to connect to. It defaults
to the local machine.


A preinitialized WMI object to use. Defaults to creating
a fresh instance.


The class into which the results of C<prepare>
are blessed. Defaults to C<Win32::WQL::Statement>.


The class into which the results of C<fetchrow>
are blessed for event queries. Defaults to


The class into which the results of C<fetchrow>
are blessed for static queries. Defaults to


sub new {
    my ($package, %args) = @_;
    my $machine = delete $args{machine} || '.';
    my $self = {
        wmi             => Win32::OLE->GetObject("winmgmts:\\\\$machine\\root\\cimV2"),
        statement_class => 'Win32::WQL::Statement',
        event_iterator_class  => 'Win32::WQL::Iterator::Event',
        collection_iterator_class  => 'Win32::WQL::Iterator::Collection',

=head2 C<< $wmi->prepare QUERY >>

Returns a prepared query by calling

    return $self->statement_class->new({
        query => $query,
        wmi => $self,
        iterator_class => $class,
        wmi_method => $method,


sub prepare {
    my ($self,$query) = @_;

    my ($class,$method,$fetch);
    if ($self->event_query($query)) {
        $class = $self->event_iterator_class;
        $method = 'ExecNotificationQuery';
    } else {
        $class = $self->collection_iterator_class;
        $method = 'ExecQuery';

    return $self->statement_class->new({
        query => $query,
        wmi => $self,
        iterator_class => $class,
        wmi_method => $method,

=head2 C<< $wmi->event_query QUERY >>

Determines whether a query is an event query
or a static query.

Event queries return a row whenever a new event
arrives and block if there is no event available.

Static queries are static and return all rows in
one go.

A query is considered an event query if it

     $query =~ /\b__instance(?:\w+)event\b/i
  or $query =~ /\wEvent\b/i


sub event_query {
    my ($package, $query) = @_;
    (   $query =~ /\b__instance(?:\w+)event\b/i
     or $query =~ /\wEvent\b/i

package Win32::WQL::Statement;
use strict;
use Win32::OLE;
use base 'Class::Accessor';

__PACKAGE__->mk_accessors(qw(iterator_class wmi query wmi_method));

sub execute {
    my ($self) = @_;
    my $m = $self->wmi_method;
    my $i = $self->wmi->wmi->$m( $self->query );
    return $self->iterator_class->new({
        wql_iterator => $i

package Win32::WQL::Iterator::Collection;
use strict;
use base 'Class::Accessor';
__PACKAGE__->mk_accessors(qw(wql_iterator items));

use Win32::OLE qw(in);
use Data::Dumper;

# Finite, prefetched list

sub new {
    my ($package,$args) = @_;
    my @items = in delete $args->{wql_iterator};
    $args->{items} = \@items;

sub fetchrow {
    my ($self) = @_;
    if (@{ $self->items }) {
        shift @{ $self->items };
    } else {
        return ()

package Win32::WQL::Iterator::Event;
use strict;
use base 'Class::Accessor';

# potentially infinite list

sub fetchrow {
    my ($self) = @_;
    return $self->wql_iterator->NextEvent();


=head1 SEE ALSO

L<DBD::WMI> for more examples

=head1 TODO

=over 4

=item * Implement parameters for and credentials

=item * Implement a multiplexer by using multiple, waiting threads so you can C<SELECT>
events from more than one WMI namespace



The public repository of this module is

=head1 SUPPORT

The public support forum of this module is


Please report bugs in this module via the RT CPAN bug queue at
or via mail to L<>.

=head1 AUTHOR

Max Maischein C<>

=head1 COPYRIGHT (c)

Copyright 2009-2018 by Max Maischein C<>.

=head1 LICENSE

This module is released under the same terms as Perl itself.