Skip to content

Instantly share code, notes, and snippets.

@harujoh
Created February 3, 2016 06:20
Show Gist options
  • Save harujoh/f05f263e90ae51c2f26f to your computer and use it in GitHub Desktop.
Save harujoh/f05f263e90ae51c2f26f to your computer and use it in GitHub Desktop.
USBカメラのシリアルIDをDXDiagを使って取得する。8秒程かかり非常に低速だが、汎用性は高い。
using System;
using System.Diagnostics;
using System.Dynamic;
using System.IO;
using System.Linq;
using System.Xml;
using System.Xml.Linq;
namespace ConsoleApplication3
{
class Program
{
static void Main(string[] args)
{
dynamic doc = new DynamicXml(XDocument.Parse(RunDxDiag()));
var test = doc.VideoCaptureDevices.VideoCaptureDevice;
for (int i = 0; i < test.Count; i++)
{
Console.WriteLine(test[i].FriendlyName);
Console.WriteLine(test[i].Parent.ToString().Split('\\')[2]);
Console.WriteLine("");
}
Console.Read();
}
static private string RunDxDiag()
{
var psi = new ProcessStartInfo();
if (IntPtr.Size == 4 && Environment.Is64BitOperatingSystem)
{
// Need to run the 64-bit version
psi.FileName = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Windows),"sysnative\\dxdiag.exe");
}
else {
// Okay with the native version
psi.FileName = Path.Combine(Environment.SystemDirectory,"dxdiag.exe");
}
string path = Path.GetTempFileName();
try
{
psi.Arguments = "/x " + path;
using (var prc = Process.Start(psi))
{
prc.WaitForExit();
if (prc.ExitCode != 0)
{
throw new Exception("DXDIAG failed with exit code " + prc.ExitCode);
}
}
return File.ReadAllText(path);
}
finally
{
File.Delete(path);
}
}
}
public class DynamicXml : DynamicObject
{
XElement element;
/// <summary>
/// XElement を与えて初期化。
/// </summary>
/// <param name="element">読み取り対象の XElement。</param>
public DynamicXml(XElement element) { this.element = element; }
/// <summary>
/// XDocument を与えて初期化。
/// ルート要素を読み出し。
/// </summary>
/// <param name="doc">読み取り対象の XDocument。</param>
public DynamicXml(XDocument doc) : this(doc.Root) { }
/// <summary>
/// ファイルのパスを与えて初期化。
/// </summary>
/// <param name="uri">読み取り対象の XML ファイル名。</param>
public DynamicXml(string uri) : this(XDocument.Load(uri)) { }
public override bool TryGetMember(GetMemberBinder binder, out object result)
{
var name = binder.Name;
// 属性値は _属性名 で取得。文字列として返す。
if (name.StartsWith("_"))
{
var attName = name.Substring(1);
result = this.element.Attribute(attName).Value;
return true;
}
var subElements = this.element.Elements(name).ToList();
// 要素がないときは null 返す。
if (subElements.Count == 0)
{
result = (string)null;
return true;
}
// 要素が1個だけの時は素直にその要素を返す。
if (subElements.Count == 1)
{
var e = subElements[0];
result = new DynamicXml(e);
return true;
}
// 要素が複数ある時はリストで要素一覧を返す。
var es = subElements.Select(x => new DynamicXml(x));
result = es.ToList();
return true;
}
public override bool TryConvert(ConvertBinder binder, out object result)
{
// string へのキャストで、要素の値を取得。
if (binder.Type == typeof(string))
{
result = this.element.Value;
return true;
}
// int へのキャストで int.Parse。
// Parse できないときは例外丸投げ。
if (binder.Type == typeof(int))
{
result = int.Parse(this.element.Value);
return true;
}
// 要素単体に対して foreach やっちゃったときでもエラーにならないように、IEnumerable へのキャストを定義。
// これやっとかないと、元々複数要素あったのに XML を修正して要素が1個だけになった時に挙動おかしくなる。
if (binder.Type == typeof(System.Collections.IEnumerable))
{
result = new[] { this };
return true;
}
result = null;
return false;
}
public override bool TryInvokeMember(InvokeMemberBinder binder, object[] args, out object result)
{
switch (binder.Name)
{
case "GetEnumerator": // IEnumerable へのキャストと同様の理由。
result = new[] { this }.GetEnumerator();
return true;
case "All": // All() 呼び出しで、子要素を全部取得できるようにする。
result = this.element.Elements().Select(x => new DynamicXml(x)).ToList();
return true;
case "Name": // Name() で要素名を取得。
result = this.element.Name.ToString();
return true;
}
return base.TryInvokeMember(binder, args, out result);
}
public override string ToString()
{
return this.element.Value;
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment