#!perl -w use strict; use warnings; # # Application to display control information, demosntrating AxWindow # usage for Webbrowser, as well as providing useful information for # anyone wanting to use other controls # # If you're randomly browsing controls, don't be surprised to find some # that crash perl. # # Select an AxtiveX Object from the dropdown ... # # Author: Robert May # use Win32::GUI qw(WS_CLIPCHILDREN WS_EX_CLIENTEDGE); use Win32::GUI::AxWindow(); use Win32::OLE(); use Win32::TieRegistry(); # Info about the currently inspected control my %INFO; # main Window my $mw = new Win32::GUI::Window ( -name => "MW", -title => "Win32::GUI::AxWindow Control Navigator", -size => [600,400], -addstyle => WS_CLIPCHILDREN, -onResize => \&mwResize, ) or die "new Window"; $mw->Center(); $mw->AddLabel( -name => "PROGID_Prompt", -pos => [10,13], -height => 20, -text => "Select PROGID :", ) or die "new Label"; $mw->AddCombobox( -name => "PROGID", -top => 10, -left => $mw->PROGID_Prompt->Left()+$mw->PROGID_Prompt->Width()+10, -size => [300,200], -vscroll => 1, -onChange => \&loadInfo, -dropdownlist => 1, ) or die "new Combobox"; $mw->AddTreeView( -name => 'TV', -top => $mw->PROGID_Prompt->Height()+20, -width => 180, -height => $mw->ScaleHeight()-$mw->PROGID_Prompt->Height()-20, -rootlines => 1, -lines => 1, -buttons => 1, -onNodeClick => \&dispInfo, ) or die "new TreeView"; Win32::GUI::AxWindow->new( -parent => $mw, -control => "Shell.Explorer", -name => 'BW', -left => $mw->TV->Left() + $mw->TV->Width()+5, -top => $mw->PROGID_Prompt->Height()+20, -width => $mw->ScaleWidth()-$mw->TV->Width()-5, -height => $mw->ScaleHeight()-$mw->PROGID_Prompt->Height()-20, -addexstyle => WS_EX_CLIENTEDGE, ) or die "new AxWindow"; # Load a blank page $mw->BW->CallMethod("Navigate", "about:blank"); $mw->Show(); $mw->Disable(); # Ref to list of controls my $controls = getInstalledControls(); exit(0) if not defined $controls; # Abort #Populate combo selection $mw->PROGID->Add(sort {lc $a cmp lc $b} @{$controls}); $mw->Enable(); $mw->BringWindowToTop(); Win32::GUI::Dialog(); $mw->Hide(); undef $mw; exit(0); sub mwResize { my $win = shift; my ($width, $height) = ($win->GetClientRect())[2..3]; $win->TV->Height($height-$win->TV->Top()); $win->BW->Width($width-$win->BW->Left()); $win->BW->Height($height-$win->BW->Top()); return 1; } sub loadInfo { Update_Treeview($mw->TV); return 1; } sub Update_Treeview { my $tv = shift; # reset information %INFO = (); $tv->DeleteAllItems(); Display(""); $INFO{progid} = $mw->PROGID->Text(); $INFO{progid} =~ s/\s.*$//; # Determine if we can create the object: # This is pretty heavy handed, but I can't think of a better # way to prevent us falling back on Shell.Explorer if we can't # load the requested ActiveX object { my $oleobj; { local $SIG{__WARN__} = sub {}; $oleobj = Win32::OLE->new($INFO{progid}); } if (not defined $oleobj) { Display("
ERROR creating $INFO{progid} (OLE)
"); return 0; } } # Create invisible AxWindow control my $C = new Win32::GUI::AxWindow( -parent => $mw, -name => "Control", -control => $INFO{progid}, ); if (not defined $C) { Display("ERROR creating $INFO{progid} (Control)
"); return 0; } # Get Property info foreach my $id ($C->EnumPropertyID()) { my %property = $C->GetPropertyInfo($id); $INFO{Properties}->{$property{-Name}} = \%property; } # Get Method info foreach my $id ($C->EnumMethodID()) { my %method = $C->GetMethodInfo($id); $INFO{Methods}->{$method{-Name}} = \%method; } # Get Event info foreach my $id ($C->EnumEventID()) { my %event = $C->GetEventInfo ($id); $INFO{Events}->{$event{-Name}} = \%event; } # Update the tree view # Insert the nodes for my $pnode_text qw(Properties Methods Events) { next if not defined $INFO{$pnode_text}; my $pnode = $tv->InsertItem(-text => $pnode_text); for my $prop_name (sort keys %{$INFO{$pnode_text}}) { $tv-> InsertItem( -parent => $pnode, -text => $prop_name, ); } } return 1; } sub dispInfo { my ($tv, $node) = @_; my $pnode = $tv->GetParent($node); # Don't do anything for the top level nodes return 1 if $pnode == 0; my %pitem_info = $tv->GetItem($pnode); my $type = $pitem_info{-text}; my %item_info = $tv->GetItem($node); my $name = $item_info{-text}; my $info = $INFO{$type}->{$name}; my $html; if ($type eq "Properties") { $html = property_html($info); } elsif ($type eq "Methods") { $html = method_html($info); } elsif ($type eq "Events") { $html = event_html($info); } else { $html = "Unknown type: $type (you shouldn't see this)
"; } Display($html); return 1; } sub Display{ my $html = shift; # Clear the document window and send the new contents # Ask Microsoft why they don't support the # document.clear method $mw->BW->GetOLE()->{Document}->open("about:bank", "_self"); $mw->BW->GetOLE()->{Document}->write($html); $mw->BW->GetOLE()->{Document}->close(); } sub property_html { my $prop = shift; my $html = "$prop->{-Description}
"; $html .= "Name: | $prop->{-Name} |
Prototype: | $prop->{-Prototype} |
VarType: | $prop->{-VarType} |
Readonly: | ".($prop->{-ReadOnly}?"Yes":"No")." |
ID: | $prop->{-ID} |
$name | $value |
$prop->{-Description}
"; $html .= "Name: | $prop->{-Name} |
Prototype: | $prop->{-Prototype} |
ID: | $prop->{-ID} |
$prop->{-Description}
"; $html .= "Name: | $prop->{-Name} |
Prototype: | $prop->{-Prototype} |
ID: | $prop->{-ID} |