1. kob58im

    No comment

    kob58im
Changes in body
Source | HTML | Preview
@@ -1,270 +1,270 @@
[COMオブジェクトのメンバー一覧を取得する (PowerShell)](https://qiita.com/kob58im/items/ea1ca69b9f898845a71f)
を応用してブラウザつくってみた。
ちなみにCOMオブジェクトでない普通の.Netのクラス(System.IO.Fileかと)であれば、
[C#リフレクションTIPS 55連発](https://qiita.com/gushwell/items/91436bd1871586f6e663)
が参考になります。
# つくってみた(キャプチャ)
![comobjbrowser.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/438183/74fe8480-6a6e-700c-51dc-5f7497a1dc04.png)
# ソースコード
```csharp
using System;
using System.Collections;
using System.Collections.ObjectModel;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Diagnostics;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.IO;
using System.Reflection;
using System.Runtime.InteropServices;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading;
using System.Windows.Forms;
using System.Management.Automation;
class MainForm:Form
{
Button btn;
Button btnGetMembers;
SplitContainer spl;
TextBox txtClassName;
ListView lsvObj;
ListView lsvMemb;
static Collection<PSObject> GetObjNames()
{
string[] source = new string[] {
@"$a = dir REGISTRY::HKEY_CLASSES_ROOT\CLSID -Include PROGID -Recurse",
"$a | foreach {$_.GetValue(\"\")} | sort"
};
using ( var invoker = new RunspaceInvoke() ) {
Collection<PSObject> tmp = invoker.Invoke(source[0]);
Collection<PSObject> result = invoker.Invoke(source[1]);
return result;
}
}
static Collection<PSObject> GetMembers(string comObjectName)
{
Regex r = new Regex(@"^[._0-9A-Za-z]+$");
if ( r.IsMatch(comObjectName) ) { // 危険なパラメータが混入しないように簡易チェック
string[] source = new string[] {
"$t = New-Object -ComObject " + comObjectName,
"Get-Member -InputObject $t"
};
using ( var invoker = new RunspaceInvoke() ) {
try {
Collection<PSObject> tmp = invoker.Invoke(source[0]);
Collection<PSObject> result = invoker.Invoke(source[1]);
return result;
}
catch (System.Management.Automation.CmdletInvocationException e) {
// memo:
// VideoRenderCtl.VideoRenderCtl.1 選んだらCreateInstanceに失敗したっぽい例外を吐いたので
// とりあえずcatchしておく
Console.WriteLine(e);
return new Collection<PSObject>();
}
}
}
else {
return new Collection<PSObject>();// 要素数 0 の Collection を返しておく
}
}
MainForm()
{
Text = "COM Object Browser";
btn = new Button();
btn.Size = new System.Drawing.Size(130,25);
btn.Text = "Get Object List";
btn.Click += (sender,e)=>{ReloadLsvObj();};
Controls.Add(btn);
txtClassName = new TextBox();
txtClassName.Location = new Point(160, 0);
txtClassName.Width = 250;
txtClassName.Text = "InternetExplorer.Application";
Controls.Add(txtClassName);
btnGetMembers = new Button();
btnGetMembers.Location = new Point(430, 0);
btnGetMembers.Size = new System.Drawing.Size(130,25);
btnGetMembers.Text = "Get Members";
btnGetMembers.Click += (sender,e)=>{ReloadLsvMemb(txtClassName.Text);};
Controls.Add(btnGetMembers);
spl = new SplitContainer();
spl.Location = new Point(0, btn.Bottom);
spl.Orientation = Orientation.Vertical;
Controls.Add(spl);
////// 左 Panel ここから
lsvObj = new ListView();
lsvObj.View = View.Details;
lsvObj.FullRowSelect =true;
lsvObj.GridLines = true;
lsvObj.Columns.Add("Name", 210, HorizontalAlignment.Left);
lsvObj.Dock = DockStyle.Fill;
lsvObj.SelectedIndexChanged += LsvObj_SelectedIndexChanged;
spl.Panel1.Controls.Add(lsvObj);
////// 左 Panel ここまで
////// 右 Panel ここから
lsvMemb = new ListView();
lsvMemb.View = View.Details;
lsvMemb.FullRowSelect =true;
lsvMemb.GridLines = true;
lsvMemb.Columns.Add("MemberType", 70, HorizontalAlignment.Left);
lsvMemb.Columns.Add("ReturnType", 100, HorizontalAlignment.Left);
lsvMemb.Columns.Add("Name", 130, HorizontalAlignment.Left);
lsvMemb.Columns.Add("Definition", 350, HorizontalAlignment.Left);
lsvMemb.Dock = DockStyle.Fill;
spl.Panel2.Controls.Add(lsvMemb);
////// 右 Panel ここまで
ClientSize = new System.Drawing.Size(800,530);
Load += Form_Resize;
Resize += Form_Resize;
ResizeEnd += Form_Resize;
}
void Form_Resize(object sender, EventArgs e)
{
spl.Size = new System.Drawing.Size(ClientSize.Width, ClientSize.Height - spl.Top);
}
void ReloadLsvObj()
{
Collection<PSObject> psObjs;
btn.Enabled = false; // 処理に時間がかかるので操作を禁止しておく。※結局押したら意味ないかも
try {
psObjs = GetObjNames();
}
finally {
btn.Enabled = true;
}
lsvObj.Items.Clear();
lsvObj.BeginUpdate();
try {
foreach ( var t in psObjs ) {
lsvObj.Items.Add(MyNewListItem_LsvObj(t));
}
}
finally {
lsvObj.EndUpdate();
}
}
void ReloadLsvMemb(string comName)
{
Collection<PSObject> psObjs;
btnGetMembers.Enabled = false;
try {
psObjs = GetMembers(comName);
}
finally {
btnGetMembers.Enabled = true;
}
lsvMemb.Items.Clear();
lsvMemb.BeginUpdate();
try {
foreach ( var t in psObjs ) {
lsvMemb.Items.Add(MyNewListItem_LsvMemb(t));
}
}
finally {
lsvMemb.EndUpdate();
}
}
ListViewItem MyNewListItem_LsvObj(PSObject psObj)
{
var itm = new ListViewItem(new string[]{psObj.ToString()});
itm.Tag = psObj;
return itm;
}
ListViewItem MyNewListItem_LsvMemb(PSObject psObj)
{
ListViewItem itm;
Regex r = new Regex(@"^([^ ]+)\b");
- // フォーマットが複雑すぎて分解することが困難なため、戻り値の型(っぽい)部分だけを取り出す。
+ // フォーマットが複雑すぎて分解することが困難なため、戻り値の型(っぽい)部分だけを取り出す。追記:単語区切り\bだとドットで切れてしまうはずなので要見直し…
// - overloadが1行に入ってたりする (例: System.Random)
// - 仮引数名があったりなかったり
// - ()がない場合もある
// - ()がネストしている場合もある
// - 後ろに{get} {set} がつく場合もある
Match m = r.Match(psObj.Members["Definition"].Value.ToString());
//Match m = r.Match(psObj.ToString());
if ( m.Success ) {
string memberType = (psObj.Members["MemberType"].Value).ToString(); // PSMemberTypes (Method / Property など)
string returnType = m.Groups[1].Value;
string methodName = psObj.Members["Name"].Value.ToString();
string definition = psObj.Members["Definition"].Value.ToString();
itm = new ListViewItem(new string[]{memberType, returnType , methodName, definition});
}
else {
// 想定外の形式の場合は、とりあえずToString()して表示しておく
itm = new ListViewItem(new string[]{"", "", "", psObj.ToString()});
}
return itm;
}
void LsvObj_SelectedIndexChanged(object sender, EventArgs e)
{
if (lsvObj.SelectedIndices.Count != 1) {return;}
int index = lsvObj.SelectedIndices[0];
PSObject psObj = (PSObject)(lsvObj.Items[index].Tag);
txtClassName.Text = psObj.ToString();
}
[STAThread]
static void Main(){
Application.Run(new MainForm());
}
}
```
判ったこと:
PSObjectのMembersプロパティやMethodsプロパティは、COMオブジェクトの情報は拾えないようである。。
機能追加したいこと:
・テキストコピーできるようにする
・ListView上の検索(filtering)
# コンパイル方法
```
csc ^
/r:C:\Windows\assembly\GAC_MSIL\System.Management.Automation\1.0.0.0__31bf3856ad364e35\System.Management.Automation.dll ^
xxxx.c
```
# 参考サイト
- [C# 上で PowerShell スクリプトを実行 (++C++; //未確認飛行 C)](https://ufcpp.net/study/powershell/interop.html)
- [PSObjectクラス (Microsoft) ](https://docs.microsoft.com/en-us/dotnet/api/system.management.automation.psobject?view=pscore-6.2.0)