2013-03-28T01:40:48の更新内容

programming/netfx/tips/read_ini/index.wiki.txt

current previous
1,177 1,113
 
${smdncms:title,INI形式のファイルを読む}
${smdncms:title,INI形式のファイルを読む}
 
${smdncms:keywords,INI,StreamReader,Regex}
${smdncms:keywords,INI,StreamReader,Regex}
 
${smdncms:tags,lang/c#}
${smdncms:tags,lang/c#}
+
${smdncms:document_versions,codelang=cs,codelang=vb}
+

          
+
-関連するページ
+
--[[works/libs/Smdn.Formats.Ini]] C#で書いた.NET Framework/Mono用INIファイル読み込み/保存ライブラリ
+
--[[programming/netfx/fcl/Microsoft.VisualBasic.FileIO.TextFieldParser]] TextFieldParserクラスを用いてCSVファイルを読む
+
--[[programming/netfx/stream/2_streamreader_streamwriter]] StreamReaderクラスの使い方
+
--[[programming/netfx/regex/0_abstract]] 正規表現とRegexクラスの使い方
 

        

        
 
#googleadunit
#googleadunit
 

        

        
~
INI形式のファイルを読み込み、読み込んだセクション・キー・値を一覧にして表示する例。 ここで紹介する実装では、INI形式の解析に正規表現を使う。 また、'#' および ';' で始まる行、および各行の ';' 以降をコメントとして扱う。
INI形式のファイルを読み込み、読み込んだセクション・キー・値を一覧にして表示する。 INI形式の解析には正規表現を使う。
 

        

        
~
#tabpage(codelang=cs)
#code(cs){{
+
#code{{
 
using System;
using System;
 
using System.Collections.Generic;
using System.Collections.Generic;
 
using System.IO;
using System.IO;
-
using System.Text;
 
using System.Text.RegularExpressions;
using System.Text.RegularExpressions;
 

        

        
~
class Sample {
static void Main(string[] args)
~
  public static void Main()
{
-
  string iniFile = @"test.ini";
-
  StreamReader reader = null;
-

          
-
  Dictionary<string, Dictionary<string, string>> sections = new Dictionary<string, Dictionary<string, string>>();
-

          
-
  // セクション名が明示されていない先頭部分のセクション名を""として扱う
-
  sections.Add(string.Empty, new Dictionary<string, string>());
-

          
-
  try
 
  {
  {
~
    const string iniFile = @"test.ini";
    reader = new StreamReader(iniFile, Encoding.Default);
-

          
-
    Regex regexSection = new Regex(@"^\[(?<section>[^\]]+)\].*$", RegexOptions.Singleline);
-
    Regex regexKeyValue = new Regex(@"^(?<key>[^=]+)=(?<value>.*)$", RegexOptions.Singleline);
-
    Match match;
-
    string currentSection = string.Empty;
-

          
-
    for (; ; )
-
    {
-
      string line = reader.ReadLine();
-

          
-
      if (line == null) break;
 

        

        
~
    // INIファイルを読み込み、各セクション毎に表示する
      // コメント行は読み飛ばす
~
    foreach (var section in ReadIni(iniFile)) {
      if (line.StartsWith(";")) continue;
+
      Console.WriteLine("[{0}]", section.Key);
 

        

        
~
      foreach (var pair in section.Value) {
      // 空行は読み飛ばす
~
        Console.WriteLine("  <{0}>='{1}'", pair.Key, pair.Value);
      if (string.Empty.Equals(line.Trim())) continue;
~
      }

          
~
    }
      // "キー=値"の形式にマッチするか
~
  }
      match = regexKeyValue.Match(line);
-

          
-
      if (match.Success)
-
      {
-
        string key = match.Groups["key"].Value.Trim();
-
        string value = match.Groups["value"].Value.Trim();
 

        

        
~
  private static Dictionary<string, Dictionary<string, string>> ReadIni(string file)
        if (sections[currentSection].ContainsKey(key))
~
  {
        {
~
    using (var reader = new StreamReader(file)) {
          // キーが存在する場合は上書き
~
      var sections = new Dictionary<string, Dictionary<string, string>>(StringComparer.Ordinal);
          sections[currentSection][key] = value;
~
      var regexSection = new Regex(@"^\s*\[(?<section>[^\]]+)\].*$", RegexOptions.Singleline | RegexOptions.CultureInvariant);
        }
~
      var regexNameValue = new Regex(@"^\s*(?<name>[^=]+)=(?<value>.*?)(\s+;(?<comment>.*))?$", RegexOptions.Singleline | RegexOptions.CultureInvariant);
        else
~
      var currentSection = string.Empty;
        {
~

          
          // キーを追加する
~
      // セクション名が明示されていない先頭部分のセクション名を""として扱う
          sections[currentSection].Add(key, value);
+
      sections[string.Empty] = new Dictionary<string, string>();
+

          
+
      for (;;) {
+
        var line = reader.ReadLine();
+

          
+
        if (line == null)
+
          break;
+

          
+
        // 空行は読み飛ばす
+
        if (line.Length == 0)
+
          continue;
+

          
+
        // コメント行は読み飛ばす
+
        if (line.StartsWith(";", StringComparison.Ordinal))
+
          continue;
+
        else if (line.StartsWith("#", StringComparison.Ordinal))
+
          continue;
+

          
+
        var matchNameValue = regexNameValue.Match(line);
+

          
+
        if (matchNameValue.Success) {
+
          // name=valueの行
+
          sections[currentSection][matchNameValue.Groups["name"].Value.Trim()] = matchNameValue.Groups["value"].Value.Trim();
+
          continue;
 
        }
        }
 

        

        
~
        var matchSection = regexSection.Match(line);
        // 次の行を読む
-
        continue;
-
      }
 

        

        
~
        if (matchSection.Success) {
      // "[セクション]"の形式にマッチするか
~
          // [section]の行
      match = regexSection.Match(line);
+
          currentSection = matchSection.Groups["section"].Value;
 

        

        
~
          if (!sections.ContainsKey(currentSection))
      if (match.Success)
~
            sections[currentSection] = new Dictionary<string, string>();
      {
-
        currentSection = match.Groups["section"].Value;
-

          
-
        if (!sections.ContainsKey(currentSection))
-
        {
-
          // 新しいセクションを追加する
-
          sections.Add(currentSection, new Dictionary<string, string>());
-
        }
 

        

        
~
          continue;
        // 次の行を読む
~
        }
        continue;
 
      }
      }
-
    }
-
  }
-
  finally
-
  {
-
    if (reader != null) reader.Close();
-
  }
 

        

        
~
      return sections;
  // 読み込んだ結果を表示する
-
  foreach (KeyValuePair<string, Dictionary<string, string>> section in sections)
-
  {
-
    Console.WriteLine("[{0}]", section.Key);
-

          
-
    foreach (KeyValuePair<string, string> entry in section.Value)
-
    {
-
      Console.WriteLine("  {0}={1}", entry.Key, entry.Value);
 
    }
    }
 
  }
  }
 
}
}
 
}}
}}
+
#tabpage(codelang=vb)
+
#code{{
+
Imports System
+
Imports System.Collections.Generic
+
Imports System.IO
+
Imports System.Text.RegularExpressions
+

          
+
Class Sample
+
  Public Shared Sub Main()
+
    Const iniFile As String = "test.ini"
+

          
+
    ' INIファイルを読み込み、各セクション毎に表示する
+
    For Each section As KeyValuePair(Of String, Dictionary(Of String, String)) In ReadIni(iniFile)
+
      Console.WriteLine("[{0}]", section.Key)
+

          
+
      For Each pair As KeyValuePair(Of String, String) In section.Value
+
        Console.WriteLine("  <{0}>='{1}'", pair.Key, pair.Value)
+
      Next
+
    Next
+
  End Sub
+

          
+
  Private Shared Function ReadIni(ByVal file As String) As Dictionary(Of String, Dictionary(Of String, String))
+
    Using reader As New StreamReader(file)
+
      Dim sections As New Dictionary(Of String, Dictionary(Of String, String))(StringComparer.Ordinal)
+
      Dim regexSection As New Regex("^\s*\[(?<section>[^\]]+)\].*$", RegexOptions.Singleline Or RegexOptions.CultureInvariant)
+
      Dim regexNameValue As New Regex("^\s*(?<name>[^=]+)=(?<value>.*?)(\s+;(?<comment>.*))?$", RegexOptions.Singleline Or RegexOptions.CultureInvariant)
+
      Dim currentSection As String = String.Empty
+

          
+
      ' セクション名が明示されていない先頭部分のセクション名を""として扱う
+
      sections(String.Empty) = New Dictionary(Of String, String)()
+

          
+
      While True
+
        Dim line As String = reader.ReadLine()
+

          
+
        If line Is Nothing Then Exit While
+

          
+
        ' 空行は読み飛ばす
+
        If line.Length = 0 Then Continue While
+

          
+
        ' コメント行は読み飛ばす
+
        If line.StartsWith(";", StringComparison.Ordinal) Then
+
          Continue While
+
        Else If line.StartsWith("#", StringComparison.Ordinal) Then
+
          Continue While
+
        End If
+

          
+
        Dim matchNameValue As Match = regexNameValue.Match(line)
+

          
+
        If matchNameValue.Success Then
+
          ' name=valueの行
+
          sections(currentSection)(matchNameValue.Groups("name").Value.Trim()) = matchNameValue.Groups("value").Value.Trim()
+
          Continue While
+
        End If
+

          
+
        Dim matchSection As Match = regexSection.Match(line)
+

          
+
        If matchSection.Success Then
+
          ' [section]の行
+
          currentSection = matchSection.Groups("section").Value
+

          
+
          If Not sections.ContainsKey(currentSection) Then
+
            sections(currentSection) = New Dictionary(Of String, String)()
+
          End If
+

          
+
          Continue While
+
        End If
+
      End While
+

          
+
      Return sections
+
    End Using
+
  End Function
+
End Class
+
}}
+
#tabpage-end
 

        

        
 
例としてこのようなiniファイルの場合、
例としてこのようなiniファイルの場合、
 
#code(ini){{
#code(ini){{
~
#
; sample ini file
~
# ini file
username=test
~
#
password=xxxx
+

          
+
; default section
+
username=test     ; comment
+
password=xxxx     ; comment
 

        

        
 
; setting for screen
; setting for screen
 
[screen]
[screen]
181,30 117,35
 

        

        
 
; setting for input
; setting for input
 
[input]
[input]
~
shot=0
shot    = 0
~
 bomb  =  1
bomb    = 1
~
  skip=2
skip    = 2
~
   cancel  = 3    ;
cancel  = 3
 

        

        
 
[screen]
[screen]
 
screensize      = 800x600
screensize      = 800x600
+

          
 
}}
}}
 

        

        
 
次のような実行結果となる。
次のような実行結果となる。
 
#prompt{{
#prompt{{
 
[]
[]
~
  <username>='test'
  username=test
~
  <password>='xxxx'
  password=xxxx
 
[screen]
[screen]
~
  <screenmode>='fullscreen'
  screenmode=fullscreen
~
  <screensize>='800x600'
  screensize=800x600
~
  <refresh-rate>='60Hz'
  refresh-rate=60Hz
 
[input]
[input]
~
  <shot>='0'
  shot=0
~
  <bomb>='1'
  bomb=1
~
  <skip>='2'
  skip=2
~
  <cancel>='3'
  cancel=3
 
}}
}}
 

        

        
-
*関連ページ
-
-[[works/libs/Smdn.Formats.Ini]] C#で書いた.NET Framework/Mono用INIファイル読み込み/保存ライブラリ
-
-[[programming/netfx/fcl/Microsoft.VisualBasic.FileIO.TextFieldParser]] TextFieldParserクラスを用いてCSVファイルを読む
-
-[[programming/netfx/stream/2_streamreader_streamwriter]] StreamReaderクラスの使い方
-
-[[programming/netfx/regex/0_abstract]] 正規表現とRegexクラスの使い方
-

          
 

        

        

programming/netfx/tips/get_assembly_version_info/index.wiki.txt

current previous
1,294 1,40
~
${smdncms:title,アセンブリのバージョン情報を取得する}
${smdncms:title,現在実行中のアセンブリのバージョン情報を取得する}
~
${smdncms:keywords,VB.NET,C#,アセンブリ,ファイル,バージョン,情報,Assembly,AssemblyName.Version,FileVersionInfo,AssemblyVersionAttribute,AssemblyFileVersionAttribute,AssemblyInformationalVersionAttribute}
${smdncms:keywords,VB.NET,C#,アセンブリ,ファイル,バージョン,情報}
 
${smdncms:tags,api/.net,lang/vb,lang/c#}
${smdncms:tags,api/.net,lang/vb,lang/c#}
 
${smdncms:document_versions,codelang=cs,codelang=vb}
${smdncms:document_versions,codelang=cs,codelang=vb}
 

        

        
 
#googleadunit
#googleadunit
 

        

        
-
System.Reflection.Assembly.GetExecutingAssembly()により、現在実行中のアセンブリを取得できる。 アセンブリのファイルパスはAssembly.Locationプロパティで取得できる。 さらに、System.Diagnostics.FileVersionInfo.GetVersionInfo()により、ファイルのバージョンが取得できる。 System.Diagnostics.FileVersionInfoには様々なバージョン情報が含まれる。
-

          
 
-関連するページ
-関連するページ
 
--[[programming/netfx/classlibrary]]
--[[programming/netfx/classlibrary]]
+
--[[programming/netfx/environment/1_process]]
+
--[[programming/netfx/attributes]]
 
--[[programming/netfx/embeddedresource]]
--[[programming/netfx/embeddedresource]]
 
--[[programming/netfx/tips/plugin_assembly]]
--[[programming/netfx/tips/plugin_assembly]]
 

        

        
+
*アセンブリのバージョン情報を取得する (AssemblyVersionAttribute)
+
&msdn(netfx,member,System.Reflection.Assembly.GetName){Assembly.GetNameメソッド};を使ってバージョン情報を取得したいアセンブリの&msdn(netfx,type,System.Reflection.AssemblyName){AssemblyName};を取得し、&msdn(netfx,member,System.Reflection.AssemblyName.Version){AssemblyName.Versionプロパティ};を参照すればアセンブリのバージョン情報を取得できる。
+

          
+
#tabpage(codelang=cs)
+
#code{{
+
using System;
+
using System.Reflection;
+

          
+
[assembly: AssemblyVersion("1.2.*")]
+

          
+
class Sample {
+
  public static void Main()
+
  {
+
    // 現在実行しているアセンブリ(.exeのアセンブリ)を取得する
+
    var assm = Assembly.GetExecutingAssembly();
+

          
+
    // AssemblyNameを取得する
+
    var name = assm.GetName();
+

          
+
    // 名前とバージョンを取得して表示する
+
    Console.WriteLine("{0} {1}", name.Name, name.Version);
+
  }
+
}
+
}}
+
#tabpage(codelang=vb)
+
#code{{
+
Imports System
+
Imports System.Reflection
+

          
+
<Assembly: AssemblyVersion("1.2.*")>
+

          
+
Class Sample
+
  Public Shared Sub Main()
+
    ' 現在実行しているアセンブリ(.exeのアセンブリ)を取得する
+
    Dim assm As [Assembly] = [Assembly].GetExecutingAssembly()
+

          
+
    ' AssemblyNameを取得する
+
    Dim name As AssemblyName = assm.GetName()
+

          
+
    ' 名前とバージョンを取得して表示する
+
    Console.WriteLine("{0} {1}", name.Name, name.Version)
+
  End Sub
+
End Class
+
}}
+
#tabpage-end
+

          
+
#prompt(.NET Frameworkでの実行結果){{
+
E:\>csc /out:TestApplication.exe test.cs & TestApplication.exe
+

          
+
TestApplication 1.2.4834.43060
+
}}
+

          
+
#prompt(Monoでの実行結果){{
+
$ mcs -out:TestApplication.exe test.cs && mono TestApplication.exe 
+

          
+
TestApplication 1.2.4834.42292
+
}}
+

          
+
&msdn(netfx,type,System.Reflection.AssemblyVersionAttribute){AssemblyVersion属性};でアスタリスクを使ってバージョンを指定した場合は、ビルド時の時間を元に自動的に決定される。
+

          
+
*アセンブリのファイルバージョン情報を取得する (AssemblyFileVersionAttribute, FileVersionInfo)
+
&msdn(netfx,type,System.Reflection.AssemblyVersionAttribute){AssemblyVersion属性};で指定されているバージョン情報ではなく、ファイルに記録されているバージョン情報、もしくはAssemblyFileVersion属性で指定されているバージョン情報を取得したい場合は、&msdn(netfx,member,System.Diagnostics.FileVersionInfo.GetVersionInfo){FileVersionInfo.GetVersionInfoメソッド};を使うことができる。 このメソッドは任意のexeファイル・dllファイルのバージョン情報を取得できるが、&msdn(netfx,member,System.Reflection.Assembly.CodeBase){Assembly.CodeBaseプロパティ};を参照してアセンブリのファイルパスを指定することでアセンブリのファイルバージョン情報を取得できる。
+

          
+
なお、Assembly.CodeBaseプロパティが返す値はfile://スキーム形式のURLなので、Uriクラスに変換した後&msdn(netfx,member,System.Uri.LocalPath){Uri.LocalPathプロパティ};を参照してパス部分のみを取得する必要がある。
+

          
+
#tabpage(codelang=cs)
+
#code{{
+
using System;
+
using System.Diagnostics;
+
using System.Reflection;
+

          
+
[assembly: AssemblyVersion("1.2.*")]
+
[assembly: AssemblyFileVersion("4.3.2.1")]
+

          
+
class Sample {
+
  public static void Main()
+
  {
+
    // 現在実行しているアセンブリ(.exeのアセンブリ情報)を取得する
+
    var assm = Assembly.GetExecutingAssembly();
+

          
+
    // アセンブリのファイルパスを取得する
+
    var path = (new Uri(assm.CodeBase)).LocalPath;
+

          
+
    // アセンブリのFileVersionInfoを取得する
+
    var versionInfo = FileVersionInfo.GetVersionInfo(path);
+

          
+
    // ファイル名とバージョンを取得して表示する
+
    Console.WriteLine("{0} {1}", versionInfo.FileName, versionInfo.FileVersion);
+
  }
+
}
+
}}
+
#tabpage(codelang=vb)
+
#code{{
+
Imports System
+
Imports System.Diagnostics
+
Imports System.Reflection
+

          
+
<Assembly: AssemblyVersion("1.2.*")>
+
<Assembly: AssemblyFileVersion("4.3.2.1")>
+

          
+
Class Sample
+
  Public Shared Sub Main()
+
    ' 現在実行しているアセンブリ(.exeのアセンブリ)を取得する
+
    Dim assm As [Assembly] = [Assembly].GetExecutingAssembly()
+

          
+
    ' アセンブリのファイルパスを取得する
+
    Dim path As String = (New Uri(assm.CodeBase)).LocalPath
+

          
+
    ' アセンブリのFileVersionInfoを取得する
+
    Dim versionInfo As FileVersionInfo = FileVersionInfo.GetVersionInfo(path)
+

          
+
    ' ファイル名とバージョンを取得して表示する
+
    Console.WriteLine("{0} {1}", versionInfo.FileName, versionInfo.FileVersion)
+
  End Sub
+
End Class
+
}}
+
#tabpage-end
+

          
+
#prompt(.NET Frameworkでの実行結果){{
+
E:\>csc /out:TestApplication.exe test.cs & TestApplication.exe
+

          
+
E:\TestApplication.exe 4.3.2.1
+
}}
+

          
+
#prompt(Monoでの実行結果){{
+
$ mcs -out:TestApplication.exe test.cs && mono TestApplication.exe 
+

          
+
/home/smdn/TestApplication.exe 1.2.4834.41152
+
}}
+

          
+
なお、&msdn(netfx,member,System.Windows.Forms.dll,System.Windows.Forms.Application.ProductVersion){Application.ProductVersionプロパティ};を参照することでもこれと同じバージョン情報を取得することができる。 ただし、このプロパティは&msdn(netfx,type,System.Reflection.AssemblyInformationalVersionAttribute){AssemblyInformationalVersion属性};が指定されている場合はその値を返す。
+

          
 
#tabpage(codelang=cs)
#tabpage(codelang=cs)
 
#code{{
#code{{
~
using System;
System.Reflection.Assembly assembly;
~
using System.Reflection;
System.Diagnostics.FileVersionInfo versionInfo;
+
using System.Windows.Forms;
+

          
+
[assembly: AssemblyVersion("1.2.*")]
+
[assembly: AssemblyFileVersion("4.3.2.1")]
+
[assembly: AssemblyInformationalVersion("9.9.9.9")]
+

          
+
class Sample {
+
  public static void Main()
+
  {
+
    // Applicationクラスのプロパティを参照してバージョン情報を取得する
+
    Console.WriteLine("{0} {1}", Application.ProductName, Application.ProductVersion);
+
  }
+
}
+
}}
+
#tabpage(codelang=vb)
+
#code{{
+
Imports System
+
Imports System.Reflection
+
Imports System.Windows.Forms
+

          
+
<Assembly: AssemblyVersion("1.2.*")>
+
<Assembly: AssemblyFileVersion("4.3.2.1")>
+
<Assembly: AssemblyInformationalVersion("9.9.9.9")>
+

          
+
Class Sample
+
  Public Shared Sub Main()
+
    ' Applicationクラスのプロパティを参照してバージョン情報を取得する
+
    Console.WriteLine("{0} {1}", Application.ProductName, Application.ProductVersion)
+
  End Sub
+
End Class
+
}}
+
#tabpage-end
+

          
+
#prompt(.NET Frameworkでの実行結果){{
+
E:\>csc /out:TestApplication.exe test.cs & TestApplication.exe
 

        

        
~
Sample 9.9.9.9
assembly = System.Reflection.Assembly.GetExecutingAssembly();
+
}}
 

        

        
~
#prompt(Monoでの実行結果){{
versionInfo = System.Diagnostics.FileVersionInfo.GetVersionInfo(assembly.Location);
+
$ mcs -out:TestApplication.exe -r:System.Windows.Forms.dll test.cs && mono TestApplication.exe 
 

        

        
~
Sample 9.9.9.9
Console.WriteLine(versionInfo.FileName);
~
}}
Console.WriteLine(versionInfo.FileVersion);
+

          
+

          
+
*属性からバージョン情報を取得する
+
&msdn(netfx,member,System.Attribute.GetCustomAttributes){Attribute.GetCustomAttributesメソッド};を使ってアセンブリに指定されている属性を取得することでもバージョン情報を取得することはできる。 ただし、この方法ではAssemblyVersion属性を取得することはできない(GetCustomAttributesメソッドは空の配列を返す)。
+

          
+

          
+
#tabpage(codelang=cs)
+
#code{{
+
using System;
+
using System.Reflection;
+
using System.Linq;
+

          
+
[assembly: AssemblyVersion("1.2.*")]
+
[assembly: AssemblyFileVersion("4.3.2.1")]
+
[assembly: AssemblyInformationalVersion("9.9.9.9")]
+

          
+
class Sample {
+
  public static void Main()
+
  {
+
    // 現在実行しているアセンブリ(.exeのアセンブリ)を取得する
+
    var assm = Assembly.GetExecutingAssembly();
+

          
+
    // AssemblyFileVersion属性を取得する
+
    var assemblyFileVersion = (AssemblyFileVersionAttribute)Attribute.GetCustomAttributes(assm, typeof(AssemblyFileVersionAttribute)).First();
+

          
+
    Console.WriteLine("AssemblyFileVersion: {0}", assemblyFileVersion.Version);
+

          
+
    // AssemblyInformationalVersion属性を取得する
+
    var assemblyInformationalVersion = (AssemblyInformationalVersionAttribute)Attribute.GetCustomAttributes(assm, typeof(AssemblyInformationalVersionAttribute)).First();
+

          
+
    Console.WriteLine("AssemblyInformationalVersion: {0}", assemblyInformationalVersion.InformationalVersion);
+

          
+
    // AssemblyVersion属性を取得しようとする (実際には取得できない)
+
    var assemblyVersion = (AssemblyVersionAttribute)Attribute.GetCustomAttributes(assm, typeof(AssemblyVersionAttribute)).First();
+

          
+
    Console.WriteLine("AssemblyVersionAttribute: {0}", assemblyVersion.Version);
+
  }
+
}
 
}}
}}
 
#tabpage(codelang=vb)
#tabpage(codelang=vb)
 
#code{{
#code{{
~
Imports System
Dim [assembly] As System.Reflection.Assembly
~
Imports System.Reflection
Dim versionInfo As System.Diagnostics.FileVersionInfo
+
Imports System.Linq
+

          
+
<Assembly: AssemblyVersion("1.2.*")>
+
<Assembly: AssemblyFileVersion("4.3.2.1")>
+
<Assembly: AssemblyInformationalVersion("9.9.9.9")>
+

          
+
Class Sample
+
  Public Shared Sub Main()
+
    ' 現在実行しているアセンブリ(.exeのアセンブリ)を取得する
+
    Dim assm As [Assembly] = [Assembly].GetExecutingAssembly()
+

          
+
    ' AssemblyFileVersion属性を取得する
+
    Dim assemblyFileVersion As AssemblyFileVersionAttribute = DirectCast([Attribute].GetCustomAttributes(assm, GetType(AssemblyFileVersionAttribute)).First(), AssemblyFileVersionAttribute)
+

          
+
    Console.WriteLine("AssemblyFileVersion: {0}", assemblyFileVersion.Version)
+

          
+
    ' AssemblyInformationalVersion属性を取得する
+
    Dim assemblyInformationalVersion As AssemblyInformationalVersionAttribute = DirectCast([Attribute].GetCustomAttributes(assm, GetType(AssemblyInformationalVersionAttribute)).First(), AssemblyInformationalVersionAttribute)
 

        

        
~
    Console.WriteLine("AssemblyInformationalVersion: {0}", assemblyInformationalVersion.InformationalVersion)
[assembly] = System.Reflection.Assembly.GetExecutingAssembly()
 

        

        
~
    ' AssemblyVersion属性を取得しようとする (実際には取得できない)
versionInfo = System.Diagnostics.FileVersionInfo.GetVersionInfo([assembly].Location)
+
    Dim assemblyVersion As AssemblyVersionAttribute = DirectCast([Attribute].GetCustomAttributes(assm, GetType(AssemblyVersionAttribute)).First(), AssemblyVersionAttribute)
 

        

        
~
    Console.WriteLine("AssemblyVersionAttribute: {0}", assemblyVersion.Version)
Console.WriteLine(versionInfo.FileName)
~
  End Sub
Console.WriteLine(versionInfo.FileVersion)
+
End Class
 
}}
}}
 
#tabpage-end
#tabpage-end
 

        

        
+
#prompt(.NET Frameworkでの実行結果){{
+
E:\>csc /out:TestApplication.exe test.cs & TestApplication.exe
+

          
+
AssemblyFileVersion: 4.3.2.1
+
AssemblyInformationalVersion: 9.9.9.9
+

          
+
ハンドルされていない例外: System.InvalidOperationException: シーケンスに要素が含まれていません
+
   場所 System.Linq.Enumerable.First[TSource](IEnumerable`1 source)
+
   場所 Sample.Main()
+
}}
+

          
+
#prompt(Monoでの実行結果){{
+
$ mcs test.cs -out:TestApplication.exe && mono TestApplication.exe 
+

          
+
AssemblyFileVersion: 4.3.2.1
+
AssemblyInformationalVersion: 9.9.9.9
+

          
+
Unhandled Exception:
+
System.InvalidOperationException: Sequence contains no elements
+
  at System.Linq.Enumerable.First[Attribute] (IEnumerable`1 source) [0x00000] in <filename unknown>:0 
+
  at Sample.Main () [0x00000] in <filename unknown>:0 
+
[ERROR] FATAL UNHANDLED EXCEPTION: System.InvalidOperationException: Sequence contains no elements
+
  at System.Linq.Enumerable.First[Attribute] (IEnumerable`1 source) [0x00000] in <filename unknown>:0 
+
  at Sample.Main () [0x00000] in <filename unknown>:0 
+
}}
+

          
+

          

programming/netfx/tips/quoted_printable/index.wiki.txt

current previous
18,7 18,7
 
--[[programming/netfx/tips/compute_md5sum]]
--[[programming/netfx/tips/compute_md5sum]]
 
--[[programming/netfx/fcl/System.Net.Mail.SmtpClient]]
--[[programming/netfx/fcl/System.Net.Mail.SmtpClient]]
 

        

        
~
エンコード・デコードを行うメソッドは、ヘッダ用のものとボディ用のものを用意している。 ヘッダ用にエンコード(Qエンコード)する場合は空白・水平タブに加えてエクスクラメーションマーク '?' とアンダースコア '_' もクオートするようにしている。 ボディ用にエンコードする場合は、76文字程度で自動的に改行するようにしてある。 デコードの場合は、ヘッダ用の場合のみアンダースコア '_' を空白に変換する。
エンコード処理では、76文字程度で自動的に改行するようにしてある。
 

        

        
 
#code(cs){{
#code(cs){{
 
using System;
using System;
35,23 35,15
 
  };
  };
 

        

        
 
  // エンコード
  // エンコード
~
  public static string EncodeBody(string quoteString, Encoding encoding)
  public static string Encode(string quoteString, Encoding encoding)
 
  {
  {
 
    if (encoding == null)
    if (encoding == null)
 
      throw new ArgumentNullException("encoding");
      throw new ArgumentNullException("encoding");
 

        

        
~
    return Encode(encoding.GetBytes(quoteString), false);
    return Encode(encoding.GetBytes(quoteString));
 
  }
  }
 

        

        
~
  public static string EncodeHeader(string quoteString, Encoding encoding)
  public static string Encode(byte[] quoteBytes)
+
  {
+
    if (encoding == null)
+
      throw new ArgumentNullException("encoding");
+

          
+
    return Encode(encoding.GetBytes(quoteString), true);
+
  }
+

          
+
  private static string Encode(byte[] quoteBytes, bool quoteHeader)
 
  {
  {
 
    if (quoteBytes == null)
    if (quoteBytes == null)
 
      throw new ArgumentNullException("quoteBytes");
      throw new ArgumentNullException("quoteBytes");
61,7 53,7
 
      var charcount = 0;
      var charcount = 0;
 

        

        
 
      foreach (var octet in quoteBytes) {
      foreach (var octet in quoteBytes) {
~
        if (!quoteHeader && 73 < charcount) {
        if (73 < charcount) {
 
          // 次のエスケープで76文字を越える可能性がある場合、ソフト改行を入れる
          // 次のエスケープで76文字を越える可能性がある場合、ソフト改行を入れる
 
          var escaped = false;
          var escaped = false;
 

        

        
84,40 76,23
 
            continue;
            continue;
 
        }
        }
 

        

        
~
        var quote = false;
        if ((0x21 <= octet && octet <= 0x3c) ||
-
            (0x3e <= octet && octet <= 0x7e) ||
-
            octet == 0x09 ||
-
            octet == 0x20) {
-
          // printable char (except '=' 0x3d)
-
          quoted.WriteByte(octet);
 

        

        
~
        switch (octet) {
          charcount++;
+
          case 0x09: // horizontal tab
+
          case 0x20: // space
+
          case 0x3f: // '?'
+
          case 0x5f: // '_'
+
            quote = quoteHeader;
+
            break;
+

          
+
          case 0x3d: // '='
+
            quote = true;
+
            break;
+

          
+
          default:
+
            // quote non-printable chars
+
            quote = (octet < 0x21 || 0x7f < octet);
+
            break;
 
        }
        }
~

          
        else {
~
        if (quote) {
          // '=' 0x3d or control char
+
          // '=' 0x3d or non printable char
 
          quoted.WriteByte(0x3d); // '=' 0x3d
          quoted.WriteByte(0x3d); // '=' 0x3d
 
          quoted.WriteByte(hexChars[(octet & 0xf0) >> 4]);
          quoted.WriteByte(hexChars[(octet & 0xf0) >> 4]);
 
          quoted.WriteByte(hexChars[octet & 0x0f]);
          quoted.WriteByte(hexChars[octet & 0x0f]);
 

        

        
 
          charcount += 3;
          charcount += 3;
 
        }
        }
+
        else {
+
          // printable char (except '=' 0x3d)
+
          quoted.WriteByte(octet);
+

          
+
          charcount++;
+
        }
 
      } // foreach
      } // foreach
 

        

        
 
      return Encoding.ASCII.GetString(quoted.ToArray());
      return Encoding.ASCII.GetString(quoted.ToArray());
125,23 100,15
 
  }
  }
 

        

        
 
  // デコード
  // デコード
~
  public static string DecodeBody(string quotedString, Encoding encoding)
  public static string Decode(string quotedString, Encoding encoding)
+
  {
+
    if (encoding == null)
+
      throw new ArgumentNullException("encoding");
+

          
+
    return encoding.GetString(Decode(quotedString, false));
+
  }
+

          
+
  public static string DecodeHeader(string quotedString, Encoding encoding)
 
  {
  {
 
    if (encoding == null)
    if (encoding == null)
 
      throw new ArgumentNullException("encoding");
      throw new ArgumentNullException("encoding");
 

        

        
~
    return encoding.GetString(Decode(quotedString, true));
    return encoding.GetString(Decode(quotedString));
 
  }
  }
 

        

        
~
  private static byte[] Decode(string quotedString, bool dequoteHeader)
  public static byte[] Decode(string quotedString)
 
  {
  {
 
    if (quotedString == null)
    if (quotedString == null)
 
      throw new ArgumentNullException("quotedString");
      throw new ArgumentNullException("quotedString");
155,8 122,6
 
          if (octet == 0x3d) // '=' 0x3d
          if (octet == 0x3d) // '=' 0x3d
 
            // quoted
            // quoted
 
            buffer[bufferOffset++] = octet;
            buffer[bufferOffset++] = octet;
+
          else if (dequoteHeader && octet == 0x5f) // '_' 0x5f
+
            decoded.WriteByte(0x20); // ' ' 0x20
 
          else
          else
 
            // non-quoted
            // non-quoted
 
            decoded.WriteByte(octet);
            decoded.WriteByte(octet);
216,33 181,6
 

        

        
 
以下、使用例と実行結果。
以下、使用例と実行結果。
 

        

        
+
#prompt(実行結果){{
+
[encode/decode]
+
text = '漢字abc かな?123カナ'
+
EncodeBody:   =1B$B4A;z=1B(Babc =1B$B$+$J=1B(B?123=1B$B%+%J=1B(B
+
EncodeHeader: =1B$B4A;z=1B(Babc=20=1B$B$+$J=1B(B=3F123=1B$B%+%J=1B(B
+

          
+
text = '=1B$B4A;z=1B(Babc_=1B$B$+$J=1B(B=3F123=1B$B%+%J=1B(B'
+
DecodeBody:   漢字abc_かな?123カナ
+
DecodeHeader: 漢字abc かな?123カナ
+

          
+
text = '=1B=24B4A=3Bz=1B=28Babc_=1B=24B=24=2B=24J=1B=28B=3F123=1B=24B=25=2B=25J5'
+
DecodeBody:   漢字abc_かな?123カナ
+
DecodeHader:  漢字abc かな?123カナ
+

          
+
[decode soft newline]
+
Now's the time for all folk to come to the aid of their country.
+
Now's the time for all folk to come to the aid of their country.
+

          
+
[encode soft newline]
+
The quick brown fox jumps over the lazy dog=0AThe quick brown fox jumps ov=
+
er the lazy dog=0AThe quick brown fox jumps over the lazy dog=0AThe quick =
+
brown fox jumps over the lazy dog=0AThe quick brown fox jumps over the laz=
+
y dog=0AThe quick brown fox jumps over the lazy dog
+

          
+
The=20quick=20brown=20fox=20jumps=20over=20the=20lazy=20dog=0AThe=20quick=20brown=20fox=20jumps=20over=20the=20lazy=20dog=0AThe=20quick=20brown=20fox=20jumps=20over=20the=20lazy=20dog=0AThe=20quick=20brown=20fox=20jumps=20over=20the=20lazy=20dog=0AThe=20quick=20brown=20fox=20jumps=20over=20the=20lazy=20dog=0AThe=20quick=20brown=20fox=20jumps=20over=20the=20lazy=20dog
+
}}
+

          
 
#code(cs){{
#code(cs){{
 
using System;
using System;
 
using System.Text;
using System.Text;
250,42 188,19
 
class Sample {
class Sample {
 
  public static void Main(string[] args)
  public static void Main(string[] args)
 
  {
  {
~
    var iso2022jp = Encoding.GetEncoding("iso-2022-jp");
    Console.WriteLine(QuotedPrintable.Encode("漢字abcかな123カナ", Encoding.GetEncoding("iso-2022-jp")));
~

          
    Console.WriteLine(QuotedPrintable.Encode("漢字abcかな123カナ", Encoding.GetEncoding("euc-jp")));
+
    Console.WriteLine("[encode/decode]");
+

          
+
    var text = "漢字abc かな?123カナ";
+
    Console.WriteLine("text = '{0}'", text);
+
    Console.WriteLine("EncodeBody:   {0}", QuotedPrintable.EncodeBody  (text, iso2022jp));
+
    Console.WriteLine("EncodeHeader: {0}", QuotedPrintable.EncodeHeader(text, iso2022jp));
+
    Console.WriteLine();
+

          
+
    text = "=1B$B4A;z=1B(Babc_=1B$B$+$J=1B(B=3F123=1B$B%+%J=1B(B";
+
    Console.WriteLine("text = '{0}'", text);
+
    Console.WriteLine("DecodeBody:   {0}", QuotedPrintable.DecodeBody  (text, iso2022jp));
+
    Console.WriteLine("DecodeHeader: {0}", QuotedPrintable.DecodeHeader(text, iso2022jp));
+
    Console.WriteLine();
 

        

        
+
    text = "=1B=24B4A=3Bz=1B=28Babc_=1B=24B=24=2B=24J=1B=28B=3F123=1B=24B=25=2B=25J5";
+
    Console.WriteLine("text = '{0}'", text);
+
    Console.WriteLine("DecodeBody:   {0}", QuotedPrintable.DecodeBody  (text, iso2022jp));
+
    Console.WriteLine("DecodeHader:  {0}", QuotedPrintable.DecodeHeader(text, iso2022jp));
 
    Console.WriteLine();
    Console.WriteLine();
-
    Console.WriteLine(QuotedPrintable.Decode("=1B$B4A;z=1B(Babc=1B$B$+$J=1B(B123=1B$B%+%J=1B(B", Encoding.GetEncoding("iso-2022-jp")));
-
    Console.WriteLine(QuotedPrintable.Decode("=1B=24B4A=3Bz=1B=28Babc=1B=24B=24=2B=24J=1B=28B123=1B=24B=25=2B=25J5", Encoding.GetEncoding("iso-2022-jp")));
-
    Console.WriteLine(QuotedPrintable.Decode("Now's the time =\r\nfor all folk to come=\r\n to the aid of their country.", Encoding.ASCII));
-
    Console.WriteLine(QuotedPrintable.Decode("Now's the=\n time =\rfor all folk to come =\r\nto the aid=\r=\n of their country.", Encoding.ASCII));
 

        

        
+
    Console.WriteLine("[decode soft newline]");
+
    Console.WriteLine(QuotedPrintable.DecodeBody("Now's the time =\r\nfor all folk to come=\r\n to the aid of their country.", Encoding.ASCII));
+
    Console.WriteLine(QuotedPrintable.DecodeBody("Now's the=\n time =\rfor all folk to come =\r\nto the aid=\r=\n of their country.", Encoding.ASCII));
 
    Console.WriteLine();
    Console.WriteLine();
~

          
    Console.WriteLine(QuotedPrintable.Encode(@"The quick brown fox jumps over the lazy dog
+
    Console.WriteLine("[encode soft newline]");
+
    Console.WriteLine(QuotedPrintable.EncodeBody(@"The quick brown fox jumps over the lazy dog
+
The quick brown fox jumps over the lazy dog
+
The quick brown fox jumps over the lazy dog
 
The quick brown fox jumps over the lazy dog
The quick brown fox jumps over the lazy dog
 
The quick brown fox jumps over the lazy dog
The quick brown fox jumps over the lazy dog
+
The quick brown fox jumps over the lazy dog", Encoding.ASCII));
+
    Console.WriteLine();
+
    Console.WriteLine(QuotedPrintable.EncodeHeader(@"The quick brown fox jumps over the lazy dog
 
The quick brown fox jumps over the lazy dog
The quick brown fox jumps over the lazy dog
 
The quick brown fox jumps over the lazy dog
The quick brown fox jumps over the lazy dog
 
The quick brown fox jumps over the lazy dog
The quick brown fox jumps over the lazy dog
295,3 210,20
 
}
}
 
}}
}}
 

        

        
-
#prompt(実行結果){{
-
=1B$B4A;z=1B(Babc=1B$B$+$J=1B(B123=1B$B%+%J=1B(B
-
=B4=C1=BB=FAabc=A4=AB=A4=CA123=A5=AB=A5=CA
-

          
-
漢字abcかな123カナ
-
漢字abcかな123カナ
-
Now's the time for all folk to come to the aid of their country.
-
Now's the time for all folk to come to the aid of their country.
-

          
-
The quick brown fox jumps over the lazy dog=0D=0AThe quick brown fox jumps=20
-
over the lazy dog=0D=0AThe quick brown fox jumps over the lazy dog=0D=0ATh=
-
e quick brown fox jumps over the lazy dog=0D=0AThe quick brown fox jumps o=
-
ver the lazy dog=0D=0AThe quick brown fox jumps over the lazy dog=0D=0AThe=20
-
quick brown fox jumps over the lazy dog=0D=0AThe quick brown fox jumps ove=
-
r the lazy dog
-
}}
-

          

programming/netfx/tips/compute_cdrom_md5/index.wiki.txt

current previous
1,139 1,339
 
${smdncms:title,CD-ROMのMD5ハッシュ値を計算する}
${smdncms:title,CD-ROMのMD5ハッシュ値を計算する}
 
${smdncms:keywords,CD-ROM,MD5,ハッシュ}
${smdncms:keywords,CD-ROM,MD5,ハッシュ}
~
${smdncms:tags,std/md5,lang/c#,plat/win,api/win32}
${smdncms:tags,std/md5,lang/vb,plat/win,api/win32}
 

        

        
 
#googleadunit
#googleadunit
 

        

        
 
ISOイメージを作成することなく、CD-ROMから直接データを読み込んでMD5ハッシュ値を計算するための方法。
ISOイメージを作成することなく、CD-ROMから直接データを読み込んでMD5ハッシュ値を計算するための方法。
 

        

        
~
&msdn(netfx,member,System.Security.CryptoGraphy.MD5.ComputeHash){MD5.ComputeHashメソッド};でMD5を計算する際、CD-ROMのデータを一度バイト配列に落としてからComputeHashメソッドに渡すのはムダが多いので、なんらかの方法でStreamから直接読み込ませる方法を考える。
MD5を計算するには、System.Security.Cryptography.MD5クラスのComputeHashメソッドを使用することが出来る。 このメソッドは、引数としてSystem.IO.Streamクラスのインスタンスか、Byte()をとる。 CD-ROMのデータを一度Byte()に落としてからComputeHashメソッドに渡すのはムダが多いので、Streamから直接読み込ませる方法を考える。
 

        

        
~
-関連するページ
*CdromIsoStreamクラス
~
--[[programming/netfx/tips/eject_cdrom]]
まずは、Streamクラスを派生してCD-ROMのデータを直接読み込むためのクラスを作る。
~
--[[programming/netfx/tips/compute_md5sum]]

          
-
参考資料: [[CD-ROM から ISO イメージをつくるのは ?:http://blogs.sqlpassj.org/yoshihirokawabata/archive/2005/03/02/7779.aspx]]
-

          
-
#code(vb){{
-
Imports System
-
Imports System.IO
-
Imports System.Runtime.InteropServices
-

          
-
Public Class CdromIsoStream
-

          
-
    Inherits System.IO.Stream
-

          
-
    <DllImport("kernel32.dll")> _
-
    Private Shared Function CreateFile( _
-
        ByVal lpFileName As String, _
-
        ByVal dwDesiredAccess As Integer, _
-
        ByVal dwShareMode As Integer, _
-
        ByVal lpSecurityAttributes As IntPtr, _
-
        ByVal dwCreationDisposition As Integer, _
-
        ByVal dwFLagsAndAttributes As Integer, _
-
        ByVal hTemplateFile As IntPtr _
-
    ) As IntPtr
-
    End Function
-

          
-
    <DllImport("kernel32.dll")> _
-
    Public Shared Function GetFileSizeEx( _
-
        ByVal hFile As IntPtr, _
-
        ByRef lpFileSize As Long _
-
        ) As Boolean
-
    End Function
-

          
-
    <DllImport("kernel32.dll")> _
-
    Private Shared Function ReadFile( _
-
        ByVal hFile As IntPtr, _
-
        ByVal buffer As Byte(), _
-
        ByVal nNumberOfBytesToRead As Integer, _
-
        ByRef lpNumberOfBytesRead As Integer, _
-
        ByVal lpOverlapped As IntPtr _
-
    ) As Integer
-
    End Function
-

          
-
    <DllImport("kernel32.dll")> _
-
    Private Shared Function SetFilePointer( _
-
        ByVal hFile As IntPtr, _
-
        ByVal lDistanceToMove As Integer, _
-
        ByRef lpDistanceToMoveHigh As Integer, _
-
        ByVal dwMoveMethod As FP_MOVE_METHOD _
-
    ) As Integer
-
    End Function
-

          
-
    <DllImport("kernel32.dll")> _
-
    Private Shared Function CloseHandle( _
-
        ByVal hObject As IntPtr _
-
    ) As Boolean
-
    End Function
-

          
-
    <DllImport("kernel32.dll")> _
-
    Private Shared Function GetLastError() As Integer
-
    End Function
-

          
-
    Private Shared ReadOnly INVALID_HANDLE_VALUE As IntPtr = New IntPtr(-1)
-

          
-
    Private Const GENERIC_READ As Integer = &H80000000
-
    Private Const OPEN_EXISTING As Integer = 3
-

          
-
    Private Const FILE_SHARE_READ As Integer = &H1
-

          
-
    Private Const NO_ERROR As Integer = 0
-

          
-
    Private Enum FP_MOVE_METHOD As Integer
-

          
-
        FILE_BEGIN = 0
-
        FILE_CURRENT = 1
-
        FILE_END = 2
-

          
-
    End Enum
-

          
-
    Private hFile As IntPtr = IntPtr.Zero
-

          
-
    ' ドライブレターを指定しないでCD-ROMドライブを開くためのコンストラクタ
-
    Public Sub New()
-

          
-
        hFile = CreateFile("\\?\CdRom0", GENERIC_READ, FILE_SHARE_READ, IntPtr.Zero, OPEN_EXISTING, 0, IntPtr.Zero)
-

          
-
        If INVALID_HANDLE_VALUE.Equals(hFile) Then Throw New IOException("New() failed")
-

          
-
    End Sub
-

          
-
    ' ドライブレターを指定してCD-ROMドライブを開くためのコンストラクタ
-
    Public Sub New(ByVal drive As String)
-

          
-
        hFile = CreateFile(String.Format("\\.\{0}", drive), GENERIC_READ, FILE_SHARE_READ, IntPtr.Zero, OPEN_EXISTING, 0, IntPtr.Zero)
-

          
-
        If INVALID_HANDLE_VALUE.Equals(hFile) Then Throw New IOException("New() failed")
-

          
-
    End Sub
-

          
-
    Protected Overrides Sub Finalize()
-

          
-
        If Not IntPtr.Zero.Equals(hFile) Then Close()
-

          
-
    End Sub
-

          
-
    Public Overrides ReadOnly Property CanRead() As Boolean
-
        Get
-
            Return True
-
        End Get
-
    End Property
-

          
-
    Public Overrides ReadOnly Property CanSeek() As Boolean
-
        Get
-
            Return True
-
        End Get
-
    End Property
-

          
-
    Public Overrides ReadOnly Property CanWrite() As Boolean
-
        Get
-
            Return False
-
        End Get
-
    End Property
-

          
-
    Public Overridable ReadOnly Property Handle() As IntPtr
-
        Get
-
            Return hFile
-
        End Get
-
    End Property
-

          
-
    Public Overrides Sub Flush()
-

          
-
        ' 何もしない
-
        'BOOL FlushFileBuffers(HANDLE hFile);
-

          
-
    End Sub
-

          
-
    Public Overrides ReadOnly Property Length() As Long
-

          
-
        Get
-

          
-
            Dim len As Long = 0
-

          
-
            ' なぜかGetFileSizeExではうまく取得できないが、
-
            ' Lengthを使用することがないので放置
-
            If GetFileSizeEx(hFile, len) Then
-

          
-
                Return len
-

          
-
            Else
-

          
-
                Dim err As Integer = GetLastError()
-

          
-
                Return 0
-

          
-
            End If
-

          
-
            ' シークをサポートしていないので失敗する
-
            'Dim pos As Long = Me.Position
-

          
-
            'Dim len As Long = Seek(0, SeekOrigin.End)
-

          
-
            'Seek(pos, SeekOrigin.Begin)
-

          
-
            'Return len
-

          
-
        End Get
-

          
-
    End Property
-

          
-
    Public Overrides Property Position() As Long
-

          
-
        Get
-

          
-
            Dim posHigh As Integer = 0
-
            Dim posLow As Integer = 0
-

          
-
            posLow = SetFilePointer(hFile, posLow, posHigh, FP_MOVE_METHOD.FILE_CURRENT)
-

          
-
            If posLow = &HFFFFFFFF And GetLastError() <> NO_ERROR Then
-

          
-
                Throw New IOException("Position() failed")
-

          
-
            End If
 

        

        
~
*CdromIsoStreamクラス
            Return CLng(posLow) Or CLng(posHigh) * &H100000000
~
まずは、FileStreamクラスを継承してCD-ROMのデータを直接読み込むためのクラスを作る。

          
-
        End Get
-

          
-
        Set(ByVal Value As Long)
-

          
-
            Seek(Value, SeekOrigin.Begin)
-

          
-
        End Set
-

          
-
    End Property
-

          
-
    Public Overrides Function Read(ByVal buffer() As Byte, ByVal offset As Integer, ByVal count As Integer) As Integer
-

          
-
        Dim ret As Integer = 0
-
        Dim readBytes As Integer = 0
-

          
-
        ' offsetの設定は未対応
-
        If offset <> 0 Then Throw New ArgumentException
-

          
-
        ret = ReadFile(hFile, buffer, count, readBytes, IntPtr.Zero)
-

          
-
        If ret <> 0 Then
-

          
-
            Return readBytes
-

          
-
        Else
-

          
-
            Throw New IOException("Read() failed")
-

          
-
        End If
-

          
-
    End Function
-

          
-
    Public Overrides Function Seek(ByVal offset As Long, ByVal origin As System.IO.SeekOrigin) As Long
-

          
-
        Dim moveMethod As FP_MOVE_METHOD
-

          
-
        Select Case origin
-

          
-
            Case SeekOrigin.Begin
-
                moveMethod = FP_MOVE_METHOD.FILE_BEGIN
-

          
-
            Case SeekOrigin.Current
-
                moveMethod = FP_MOVE_METHOD.FILE_CURRENT
-

          
-
            Case SeekOrigin.End
-
                moveMethod = FP_MOVE_METHOD.FILE_END
-

          
-
            Case Else
-
                Throw New ArgumentOutOfRangeException("origin")
-

          
-
        End Select
-

          
-
        Dim posHigh As Integer = CInt((offset \ &H10000000) And &HFFFFFFFF)
-
        Dim posLow As Integer = CInt(offset And &HFFFFFFFF)
-

          
-
        posLow = SetFilePointer(hFile, posLow, posHigh, moveMethod)
-

          
-
        Dim err As Integer = GetLastError()
-

          
-
        If posLow = &HFFFFFFFF And err <> NO_ERROR Then
-

          
-
            Throw New IOException("Seek() failed")
-

          
-
        End If
-

          
-
        Return CLng(posLow) Or CLng(posHigh) * &H100000000
-

          
-
    End Function
-

          
-
    Public Overrides Sub SetLength(ByVal value As Long)
-

          
-
        Throw New IOException("read only")
-

          
-
    End Sub
-

          
-
    Public Overrides Sub Write(ByVal buffer() As Byte, ByVal offset As Integer, ByVal count As Integer)
-

          
-
        Throw New IOException("read only")
-

          
-
    End Sub
-

          
-
    Public Overrides Sub Close()
-

          
-
        If CloseHandle(hFile) Then
-

          
-
            hFile = IntPtr.Zero
-

          
-
        Else
-

          
-
            Throw New IOException("Close() failed")
-

          
-
        End If
 

        

        
~
-参考
        MyBase.Close()
+
--[[C# - Create ISO image from CD/DVD:http://dotnet-snippets.com/dns/snippet_detail.aspx?=641]]
 

        

        
~
&color(red){注意};: この実装を使った場合だとCD-ROMの最終セクタの途中までしか読み込まないようなので、ISOイメージ作成ツールを使ってダンプした場合とは異なるチェックサムとなる。 あくまで参考として掲載する。 なお、以下のコードを使用して作成したISOイメージは問題なくマウントできる模様。
    End Sub
 

        

        
~
#code(cs,CdromIsoStream){{
End Class
+
using System;
+
using System.ComponentModel;
+
using System.IO;
+
using System.Runtime.InteropServices;
+
using Microsoft.Win32.SafeHandles;
+

          
+
public class CdromIsoStream : FileStream
+
{
+
  public CdromIsoStream(DriveInfo drive)
+
    : base(Open(drive), FileAccess.Read)
+
  {
+
  }
+

          
+
  [DllImport("kernel32", SetLastError = true, CharSet = CharSet.Auto)]
+
  private static extern IntPtr CreateFile(string lpFIleName,
+
                                          uint dwDesiredAccess,
+
                                          uint dwShareMode,
+
                                          IntPtr lpSecurityAttributes,
+
                                          uint dwCreationDisposition,
+
                                          uint dwFlagsAndAttributes,
+
                                          IntPtr hTemplateFile);
+

          
+
  private const uint GENERIC_READ = 0x80000000;
+
  private const uint GENERIC_WRITE = 0x40000000;
+
  private const uint FILE_SHARE_READ = 0x00000001;
+
  private const uint FILE_SHARE_WRITE = 0x00000002;
+
  private const uint OPEN_EXISTING = 3;
+

          
+
  private static readonly IntPtr INVALID_HANDLE_VALUE = new IntPtr(-1);
+

          
+
  private static SafeFileHandle Open(DriveInfo drive)
+
  {
+
    if (drive == null)
+
      throw new ArgumentNullException("drive");
+

          
+
    var handle = CreateFile(string.Format(@"\\.\{0}:", drive.Name[0]),
+
                            GENERIC_READ,
+
                            FILE_SHARE_READ,
+
                            IntPtr.Zero,
+
                            OPEN_EXISTING,
+
                            0,
+
                            IntPtr.Zero);
+

          
+
    if (handle == INVALID_HANDLE_VALUE)
+
      throw new Win32Exception(Marshal.GetLastWin32Error());
+

          
+
    return new SafeFileHandle(handle, true);
+
  }
+
}
 
}}
}}
 

        

        
-
*MD5の計算
-
前述のクラスを使うことで、CD-ROMのデータをStreamとして読み込めるようになったので、早速ComputeHashメソッドにこのインスタンスを渡してMD5を計算させる。 ここでは計算したMD5に対して、Convert.ToBase64Stringメソッドを使用してBase64エンコードしている。
-
#code(vb){{
-
Class ComputeCDRomMD5
 

        

        
~
*MD5の計算
    Public Shared Sub Main()
~
前述のクラスを使うことでCD-ROMのデータをStreamとして読み込めるようになったので、早速ComputeHashメソッドにこのインスタンスを渡してMD5を計算させる。

          
-
        Console.WriteLine("MD5 Hash(Base64) : {0}", ComputeMD5HashBase64("I:"))
-

          
-
    End Sub
-

          
-
    Private Shared Function ComputeMD5HashBase64(ByVal drive As String) As String
-

          
-
        Dim stream As CdromIsoStream = Nothing
-

          
-
        Try
-

          
-
            ' CD-ROMデバイスを開く
-
            stream = New CdromIsoStream(drive)
-

          
-
            ' MD5ハッシュ値を計算する
-
            Dim md5 As System.Security.Cryptography.MD5 = System.Security.Cryptography.MD5.Create()
-

          
-
            ' Base64
-
            Return Convert.ToBase64String(md5.ComputeHash(stream))
-

          
-
        Catch ex As Exception
-

          
-
            Console.WriteLine(ex.Message)
-

          
-
        Finally
-

          
-
            If Not stream Is Nothing Then stream.Close()
 

        

        
~
#code(cs){{
        End Try
+
using System;
+
using System.IO;
+
using System.Linq;
+
using System.Security.Cryptography;
+

          
+
class Sample
+
{
+
  static void Main()
+
  {
+
    // 光学ドライブのDriveInfoを取得
+
    var drive = DriveInfo.GetDrives().Where(d => d.DriveType == DriveType.CDRom).First();
+

          
+
    Console.WriteLine(drive);
+

          
+
    using (var cdromStream = new CdromIsoStream(drive)) {
+
      using (var md5 = MD5.Create()) {
+
        // StreamのMD5ハッシュ値を計算
+
        var md5hash = md5.ComputeHash(cdromStream);
+

          
+
        // 文字列形式に変換して表示
+
        var md5sum = BitConverter.ToString(md5hash).Replace("-", string.Empty).ToLowerInvariant();
+

          
+
        Console.WriteLine(md5sum);
+
      }
+
    }
+
  }
+
}
+
}}
 

        

        
-
        Return String.Empty
 

        

        
~
*ISOイメージの作成
    End Function
+
MD5の計算以だけでなく、読み込んだデータをそのままFileStreamに書きだせばISOイメージを作成することができる。
 

        

        
~
#code(cs){{
End Class
+
using System;
+
using System.IO;
+
using System.Linq;
+
using System.Security.Cryptography;
+

          
+
class Sample
+
{
+
  static void Main()
+
  {
+
    // 光学ドライブのDriveInfoを取得
+
    var drive = DriveInfo.GetDrives().Where(d => d.DriveType == DriveType.CDRom).First();
+

          
+
    Console.WriteLine(drive);
+

          
+
    using (var cdromStream = new CdromIsoStream(drive)) {
+
      using (var fileStream = File.Create("test.iso")) {
+
        cdromStream.CopyTo(fileStream);
+
      }
+
    }
+
  }
+
}
 
}}
}}
 

        

        
+
*メモ
+
-[[Win32 ベースのアプリケーション CD-ROM の読み取りセクターの Windows NT:http://support.microsoft.com/kb/138434/ja]]
+
-[[C#でセクタリード:http://blogs.wankuma.com/andochin/archive/2008/08/08/152221.aspx]]

programming/netfx/tips/eject_cdrom/index.wiki.txt

current previous
31,7 31,6
 
using System.ComponentModel;
using System.ComponentModel;
 
using System.IO;
using System.IO;
 
using System.Runtime.InteropServices;
using System.Runtime.InteropServices;
+
using Microsoft.Win32.SafeHandles;
 

        

        
 
class Sample {
class Sample {
 
  public static void Main()
  public static void Main()
77,15 76,15
 
  /// <summary>ドライブにメディアがセットされているかどうかを返す</summary>
  /// <summary>ドライブにメディアがセットされているかどうかを返す</summary>
 
  public static bool HasMedia(this DriveInfo drive)
  public static bool HasMedia(this DriveInfo drive)
 
  {
  {
~
    using (var volume = Open(drive, false)) {
    using (var volume = new Volume(drive, false)) {
~
      return IOControl.IOCtl(volume.DangerousGetHandle(), IOControl.IOCTL_STORAGE_CHECK_VERIFY);
      return IOControl.IOCtl(volume.Handle, IOControl.IOCTL_STORAGE_CHECK_VERIFY);
 
    }
    }
 
  }
  }
 

        

        
 
  /// <summary>ドライブのトレイが開いているかどうかを返す</summary>
  /// <summary>ドライブのトレイが開いているかどうかを返す</summary>
 
  public unsafe static bool IsTrayOpened(this DriveInfo drive)
  public unsafe static bool IsTrayOpened(this DriveInfo drive)
 
  {
  {
~
    using (var volume = Open(drive, true)) {
    using (var volume = new Volume(drive, true)) {
 
      /*
      /*
 
       * http://www.eggheadcafe.com/conversation.aspx?messageid=33820121&threadid=33794406
       * http://www.eggheadcafe.com/conversation.aspx?messageid=33820121&threadid=33794406
 
       * http://forum.sources.ru/index.php?showtopic=225102
       * http://forum.sources.ru/index.php?showtopic=225102
110,7 109,7
 

        

        
 
      uint bytesReturned;
      uint bytesReturned;
 

        

        
~
      if (!IOControl.DeviceIoControl(volume.DangerousGetHandle(), IOControl.IOCTL_SCSI_PASS_THROUGH_DIRECT, (void*)sptd, (uint)size, (void*)sptd, (uint)size, out bytesReturned, IntPtr.Zero))
      if (!IOControl.DeviceIoControl(volume.Handle, IOControl.IOCTL_SCSI_PASS_THROUGH_DIRECT, (void*)sptd, (uint)size, (void*)sptd, (uint)size, out bytesReturned, IntPtr.Zero))
 
        throw new Win32Exception(Marshal.GetLastWin32Error());
        throw new Win32Exception(Marshal.GetLastWin32Error());
 

        

        
 
      return ((data[1] & 0x10) == 0x10);
      return ((data[1] & 0x10) == 0x10);
120,8 119,8
 
  /// <summary>メディアをセットする、またはドライブのトレイを閉じる</summary>
  /// <summary>メディアをセットする、またはドライブのトレイを閉じる</summary>
 
  public static void Load(this DriveInfo drive)
  public static void Load(this DriveInfo drive)
 
  {
  {
~
    using (var volume = Open(drive, false)) {
    using (var volume = new Volume(drive, false)) {
~
      if (!IOControl.IOCtl(volume.DangerousGetHandle(), IOControl.IOCTL_STORAGE_LOAD_MEDIA))
      if (!IOControl.IOCtl(volume.Handle, IOControl.IOCTL_STORAGE_LOAD_MEDIA))
 
        throw new Win32Exception(Marshal.GetLastWin32Error());
        throw new Win32Exception(Marshal.GetLastWin32Error());
 
    }
    }
 
  }
  }
129,7 128,7
 
  /// <summary>メディアの取り外す、またはドライブのトレイを開く</summary>
  /// <summary>メディアの取り外す、またはドライブのトレイを開く</summary>
 
  public static void Eject(this DriveInfo drive)
  public static void Eject(this DriveInfo drive)
 
  {
  {
~
    using (var volume = Open(drive, false)) {
    using (var volume = new Volume(drive, false)) {
 
      /*
      /*
 
       * http://support.microsoft.com/kb/165721/
       * http://support.microsoft.com/kb/165721/
 
       */
       */
138,7 137,7
 
      var locked = false;
      var locked = false;
 

        

        
 
      for (var t = 0; t < maxRetry; t++) {
      for (var t = 0; t < maxRetry; t++) {
~
        if (IOControl.IOCtl(volume.DangerousGetHandle(), IOControl.FSCTL_LOCK_VOLUME)) {
        if (IOControl.IOCtl(volume.Handle, IOControl.FSCTL_LOCK_VOLUME)) {
 
          locked = true;
          locked = true;
 
          break;
          break;
 
        }
        }
150,7 149,7
 
      if (!locked)
      if (!locked)
 
        throw new IOException("デバイスがビジー状態です");
        throw new IOException("デバイスがビジー状態です");
 

        

        
~
      if (!IOControl.IOCtl(volume.DangerousGetHandle(), IOControl.FSCTL_DISMOUNT_VOLUME))
      if (!IOControl.IOCtl(volume.Handle, IOControl.FSCTL_DISMOUNT_VOLUME))
 
        throw new Win32Exception(Marshal.GetLastWin32Error());
        throw new Win32Exception(Marshal.GetLastWin32Error());
 

        

        
 
      unsafe {
      unsafe {
159,61 158,15
 

        

        
 
        inBuffer[0].PreventMediaRemoval = 0; // FALSE
        inBuffer[0].PreventMediaRemoval = 0; // FALSE
 

        

        
~
        if (!IOControl.DeviceIoControl(volume.DangerousGetHandle(), IOControl.IOCTL_STORAGE_MEDIA_REMOVAL, (void*)inBuffer, (uint)Marshal.SizeOf(typeof(PREVENT_MEDIA_REMOVAL)), (void*)IntPtr.Zero, 0, out bytesReturned, IntPtr.Zero))
        if (!IOControl.DeviceIoControl(volume.Handle, IOControl.IOCTL_STORAGE_MEDIA_REMOVAL, (void*)inBuffer, (uint)Marshal.SizeOf(typeof(PREVENT_MEDIA_REMOVAL)), (void*)IntPtr.Zero, 0, out bytesReturned, IntPtr.Zero))
 
          throw new Win32Exception(Marshal.GetLastWin32Error());
          throw new Win32Exception(Marshal.GetLastWin32Error());
 
      }
      }
 

        

        
~
      if (!IOControl.IOCtl(volume.DangerousGetHandle(), IOControl.IOCTL_STORAGE_EJECT_MEDIA))
      if (!IOControl.IOCtl(volume.Handle, IOControl.IOCTL_STORAGE_EJECT_MEDIA))
 
        throw new Win32Exception(Marshal.GetLastWin32Error());
        throw new Win32Exception(Marshal.GetLastWin32Error());
 
    }
    }
 
  }
  }
 

        

        
+
  /// <summary>ドライブを開いてSafeFileHandleを取得する</summary>
+
  private static SafeFileHandle Open(DriveInfo drive, bool accessWrite)
+
  {
+
    uint accessFlags;
+

          
+
    if (drive.DriveType == DriveType.CDRom)
+
      accessFlags = GENERIC_READ;
+
    else if (drive.DriveType == DriveType.Removable)
+
      accessFlags = GENERIC_READ | GENERIC_WRITE;
+
    else
+
      throw new NotSupportedException("リムーバブルドライブではありません");
+

          
+
    if (accessWrite)
+
      accessFlags |= GENERIC_WRITE;
+

          
+
    var handle = CreateFile(string.Format(@"\\.\{0}:", drive.Name[0]),
+
                            accessFlags,
+
                            FILE_SHARE_READ | FILE_SHARE_WRITE,
+
                            IntPtr.Zero,
+
                            OPEN_EXISTING,
+
                            0,
+
                            IntPtr.Zero);
+

          
+
    if (handle == INVALID_HANDLE_VALUE)
+
      throw new Win32Exception(Marshal.GetLastWin32Error());
+

          
+
    return new SafeFileHandle(handle, true);
+
  }
+

          
+
  [DllImport("kernel32", SetLastError = true, CharSet = CharSet.Auto)]
+
  private static extern IntPtr CreateFile(string lpFIleName,
+
                                          uint dwDesiredAccess,
+
                                          uint dwShareMode,
+
                                          IntPtr lpSecurityAttributes,
+
                                          uint dwCreationDisposition,
+
                                          uint dwFlagsAndAttributes,
+
                                          IntPtr hTemplateFile);
+

          
+
  private const uint GENERIC_READ = 0x80000000;
+
  private const uint GENERIC_WRITE = 0x40000000;
+
  private const uint FILE_SHARE_READ = 0x00000001;
+
  private const uint FILE_SHARE_WRITE = 0x00000002;
+
  private const uint OPEN_EXISTING = 3;
+

          
+
  private static readonly IntPtr INVALID_HANDLE_VALUE = new IntPtr(-1);
+

          
 
  // DeviceIoControl呼び出し関連のクラス
  // DeviceIoControl呼び出し関連のクラス
 
  private static class IOControl {
  private static class IOControl {
 
    [DllImport("kernel32", SetLastError = true)]
    [DllImport("kernel32", SetLastError = true)]
291,6 244,67
 
  private struct PREVENT_MEDIA_REMOVAL {
  private struct PREVENT_MEDIA_REMOVAL {
 
    public byte PreventMediaRemoval;
    public byte PreventMediaRemoval;
 
  }
  }
-

          
-
  /// <summary>ボリュームのハンドルとCreateFile/CloseHandleをラップするクラス</summary>
-
  private class Volume : IDisposable {
-
    [DllImport("kernel32", SetLastError = true, CharSet = CharSet.Auto)]
-
    private static extern IntPtr CreateFile(string lpFIleName,
-
                                            uint dwDesiredAccess,
-
                                            uint dwShareMode,
-
                                            IntPtr lpSecurityAttributes,
-
                                            uint dwCreationDisposition,
-
                                            uint dwFlagsAndAttributes,
-
                                            IntPtr hTemplateFile);
-

          
-
    [DllImport("kernel32", SetLastError = true)]
-
    private static extern bool CloseHandle(IntPtr hObject);
-

          
-
    private const uint GENERIC_READ = 0x80000000;
-
    private const uint GENERIC_WRITE = 0x40000000;
-
    private const uint FILE_SHARE_READ = 0x00000001;
-
    private const uint FILE_SHARE_WRITE = 0x00000002;
-
    private const uint OPEN_EXISTING = 3;
-

          
-
    private static readonly IntPtr INVALID_HANDLE_VALUE = new IntPtr(-1);
-

          
-
    public IntPtr Handle {
-
      get; private set;
-
    }
-

          
-
    public Volume(DriveInfo drive, bool accessWrite)
-
    {
-
      uint accessFlags;
-

          
-
      if (drive.DriveType == DriveType.CDRom)
-
        accessFlags = GENERIC_READ;
-
      else if (drive.DriveType == DriveType.Removable)
-
        accessFlags = GENERIC_READ | GENERIC_WRITE;
-
      else
-
        throw new NotSupportedException("リムーバブルドライブではありません");
-

          
-
      if (accessWrite)
-
        accessFlags |= GENERIC_WRITE;
-

          
-
      this.Handle = CreateFile(string.Format(@"\\.\{0}:", drive.Name[0]),
-
                               accessFlags,
-
                               FILE_SHARE_READ | FILE_SHARE_WRITE,
-
                               IntPtr.Zero,
-
                               OPEN_EXISTING,
-
                               0,
-
                               IntPtr.Zero);
-

          
-
      if (this.Handle == INVALID_HANDLE_VALUE)
-
        throw new Win32Exception(Marshal.GetLastWin32Error());
-
    }
-

          
-
    public void Dispose()
-
    {
-
      if (Handle != INVALID_HANDLE_VALUE) {
-
        CloseHandle(Handle); // ignore any errors
-
        Handle = INVALID_HANDLE_VALUE;
-
      }
-
    }
-
  }
 
}
}
 
}}
}}
 
#tabpage(codelang=vb)
#tabpage(codelang=vb)
300,7 314,6
 
Imports System.IO
Imports System.IO
 
Imports System.Runtime.CompilerServices
Imports System.Runtime.CompilerServices
 
Imports System.Runtime.InteropServices
Imports System.Runtime.InteropServices
+
Imports Microsoft.Win32.SafeHandles
 

        

        
 
Class Sample
Class Sample
 
  Shared Sub Main()
  Shared Sub Main()
343,15 356,15
 
  ''' <summary>ドライブにメディアがセットされているかどうかを返す</summary>
  ''' <summary>ドライブにメディアがセットされているかどうかを返す</summary>
 
  <Extension()> _
  <Extension()> _
 
  Public Function HasMedia(ByVal drive As DriveInfo) As Boolean
  Public Function HasMedia(ByVal drive As DriveInfo) As Boolean
~
    Using volume As SafeFileHandle = Open(drive, False)
    Using volume As New Volume(drive, False)
~
      Return IOControl.IOCtl(volume.DangerousGetHandle(), IOControl.IOCTL_STORAGE_CHECK_VERIFY)
      Return IOControl.IOCtl(volume.Handle, IOControl.IOCTL_STORAGE_CHECK_VERIFY)
 
    End Using
    End Using
 
  End Function
  End Function
 

        

        
 
  ''' <summary>ドライブのトレイが開いているかどうかを返す</summary>
  ''' <summary>ドライブのトレイが開いているかどうかを返す</summary>
 
  <Extension()> _
  <Extension()> _
 
  Public Function IsTrayOpened(ByVal drive As DriveInfo) As Boolean
  Public Function IsTrayOpened(ByVal drive As DriveInfo) As Boolean
~
    Using volume As SafeFileHandle = Open(drive, True)
    Using volume As New Volume(drive, True)
 
      '
      '
 
      ' http://www.eggheadcafe.com/conversation.aspx?messageid=33820121&threadid=33794406
      ' http://www.eggheadcafe.com/conversation.aspx?messageid=33820121&threadid=33794406
 
      ' http://forum.sources.ru/index.php?showtopic=225102
      ' http://forum.sources.ru/index.php?showtopic=225102
374,7 387,7
 
        sptd.Cdb(0) = &hBD ' mechanism status
        sptd.Cdb(0) = &hBD ' mechanism status
 
        sptd.Cdb(9) = 8 ' timeout value
        sptd.Cdb(9) = 8 ' timeout value
 

        

        
~
        If Not IOControl.DeviceIoControl(volume.DangerousGetHandle(), IOControl.IOCTL_SCSI_PASS_THROUGH_DIRECT, sptd, CUInt(size), sptd, CUInt(size), bytesReturned, IntPtr.Zero) Then
        If Not IOControl.DeviceIoControl(volume.Handle, IOControl.IOCTL_SCSI_PASS_THROUGH_DIRECT, sptd, CUInt(size), sptd, CUInt(size), bytesReturned, IntPtr.Zero) Then
 
          Throw New Win32Exception(Marshal.GetLastWin32Error())
          Throw New Win32Exception(Marshal.GetLastWin32Error())
 
        End If
        End If
 

        

        
388,8 401,8
 
  ''' <summary>メディアをセットする、またはドライブのトレイを閉じる</summary>
  ''' <summary>メディアをセットする、またはドライブのトレイを閉じる</summary>
 
  <Extension()> _
  <Extension()> _
 
  Public Sub Load(ByVal drive As DriveInfo)
  Public Sub Load(ByVal drive As DriveInfo)
~
    Using volume As SafeFileHandle = Open(drive, True)
    Using volume As New Volume(drive, True)
~
      If Not IOControl.IOCtl(volume.DangerousGetHandle(), IOControl.IOCTL_STORAGE_LOAD_MEDIA) Then
      If Not IOControl.IOCtl(volume.Handle, IOControl.IOCTL_STORAGE_LOAD_MEDIA) Then
 
        Throw New Win32Exception(Marshal.GetLastWin32Error())
        Throw New Win32Exception(Marshal.GetLastWin32Error())
 
      End If
      End If
 
    End Using
    End Using
398,7 411,7
 
  ''' <summary>メディアの取り外す、またはドライブのトレイを開く</summary>
  ''' <summary>メディアの取り外す、またはドライブのトレイを開く</summary>
 
  <Extension()> _
  <Extension()> _
 
  Public Sub Eject(ByVal drive As DriveInfo)
  Public Sub Eject(ByVal drive As DriveInfo)
~
    Using volume As SafeFileHandle = Open(drive, True)
    Using volume As New Volume(drive, True)
 
      '
      '
 
      ' http://support.microsoft.com/kb/165721/
      ' http://support.microsoft.com/kb/165721/
 
      '
      '
406,7 419,7
 
      Dim locked As Boolean = False
      Dim locked As Boolean = False
 

        

        
 
      For t As Integer = 0 To maxRetry - 1
      For t As Integer = 0 To maxRetry - 1
~
        If IOControl.IOCtl(volume.DangerousGetHandle(), IOControl.FSCTL_LOCK_VOLUME) Then
        If IOControl.IOCtl(volume.Handle, IOControl.FSCTL_LOCK_VOLUME) Then
 
          locked = True
          locked = True
 
          Exit For
          Exit For
 
        Else
        Else
416,7 429,7
 

        

        
 
      If Not locked Then Throw New IOException("デバイスがビジー状態です")
      If Not locked Then Throw New IOException("デバイスがビジー状態です")
 

        

        
~
      If Not IOControl.IOCtl(volume.DangerousGetHandle(), IOControl.FSCTL_DISMOUNT_VOLUME) Then
      If Not IOControl.IOCtl(volume.Handle, IOControl.FSCTL_DISMOUNT_VOLUME) Then
 
        Throw New Win32Exception(Marshal.GetLastWin32Error())
        Throw New Win32Exception(Marshal.GetLastWin32Error())
 
      End If
      End If
 

        

        
425,61 438,16
 

        

        
 
      pmr.PreventMediaRemoval = 0 ' FALSE
      pmr.PreventMediaRemoval = 0 ' FALSE
 

        

        
~
      If Not IOControl.DeviceIoControl(volume.DangerousGetHandle(), IOControl.IOCTL_STORAGE_MEDIA_REMOVAL, pmr, CUInt(Marshal.SizeOf(GetType(PREVENT_MEDIA_REMOVAL))), IntPtr.Zero, CUInt(0), bytesReturned, IntPtr.Zero) Then
      If Not IOControl.DeviceIoControl(volume.Handle, IOControl.IOCTL_STORAGE_MEDIA_REMOVAL, pmr, CUInt(Marshal.SizeOf(GetType(PREVENT_MEDIA_REMOVAL))), IntPtr.Zero, CUInt(0), bytesReturned, IntPtr.Zero) Then
 
        Throw New Win32Exception(Marshal.GetLastWin32Error())
        Throw New Win32Exception(Marshal.GetLastWin32Error())
 
      End If
      End If
 

        

        
~
      If Not IOControl.IOCtl(volume.DangerousGetHandle(), IOControl.IOCTL_STORAGE_EJECT_MEDIA) Then
      If Not IOControl.IOCtl(volume.Handle, IOControl.IOCTL_STORAGE_EJECT_MEDIA) Then
 
        Throw New Win32Exception(Marshal.GetLastWin32Error())
        Throw New Win32Exception(Marshal.GetLastWin32Error())
 
      End If
      End If
 
    End Using
    End Using
 
  End Sub
  End Sub
 

        

        
+
  ''' <summary>ドライブを開いてSafeFileHandleを取得する</summary>
+
  Private Function Open(ByVal drive As DriveInfo, ByVal accessWrite As Boolean) As SafeFileHandle
+
    Dim accessFlags As UInteger
+

          
+
    If drive.DriveType = DriveType.CDRom Then
+
      accessFlags = GENERIC_READ
+
    Else If drive.DriveType = DriveType.Removable Then
+
      accessFlags = GENERIC_READ Or GENERIC_WRITE
+
    Else
+
      Throw New NotSupportedException("リムーバブルドライブではありません")
+
    End If
+

          
+
    If accessWrite Then accessFlags = accessFlags Or GENERIC_WRITE
+

          
+
    Dim handle As IntPtr = CreateFile(String.Format("\\.\{0}:", drive.Name(0)), _
+
                                       accessFlags, _
+
                                       FILE_SHARE_READ Or FILE_SHARE_WRITE, _
+
                                       IntPtr.Zero, _
+
                                       OPEN_EXISTING, _
+
                                       0, _
+
                                       IntPtr.Zero)
+

          
+
    If handle = INVALID_HANDLE_VALUE Then Throw New Win32Exception(Marshal.GetLastWin32Error())
+

          
+
    Return New SafeFileHandle(handle, True)
+
  End Function
+

          
+
  <DllImport("kernel32", SetLastError := True, CharSet := CharSet.Auto)> _
+
  Private Function CreateFile(ByVal lpFIleName As String, _
+
                              ByVal dwDesiredAccess As UInteger, _
+
                              ByVal dwShareMode As UInteger, _
+
                              ByVal lpSecurityAttributes As IntPtr, _
+
                              ByVal dwCreationDisposition As UInteger, _
+
                              ByVal dwFlagsAndAttributes As UInteger, _
+
                              ByVal hTemplateFile As IntPtr) As IntPtr
+
  End Function
+

          
+
  Private Const GENERIC_READ As UInteger = &h80000000UI
+
  Private Const GENERIC_WRITE As UInteger = &h40000000UI
+
  Private Const FILE_SHARE_READ As UInteger = &h00000001UI
+
  Private Const FILE_SHARE_WRITE As UInteger = &h00000002UI
+
  Private Const OPEN_EXISTING As UInteger = 3
+

          
+
  Private ReadOnly INVALID_HANDLE_VALUE As IntPtr = New IntPtr(-1)
+

          
 
  ' DeviceIoControl呼び出し関連のクラス
  ' DeviceIoControl呼び出し関連のクラス
 
  Private Class IOControl
  Private Class IOControl
 
    <DllImport("kernel32", SetLastError := True)> _
    <DllImport("kernel32", SetLastError := True)> _
579,6 547,72
 
  Private Structure PREVENT_MEDIA_REMOVAL
  Private Structure PREVENT_MEDIA_REMOVAL
 
    Public PreventMediaRemoval As Byte
    Public PreventMediaRemoval As Byte
 
  End Structure
  End Structure
-

          
-
  ''' <summary>ボリュームのハンドルとCreateFile/CloseHandleをラップするクラス</summary>
-
  Private Class Volume
-
    Implements IDisposable
-

          
-
    <DllImport("kernel32", SetLastError := True, CharSet := CharSet.Auto)> _
-
    Private Shared Function CreateFile(ByVal lpFIleName As String, _
-
                                       ByVal dwDesiredAccess As UInteger, _
-
                                       ByVal dwShareMode As UInteger, _
-
                                       ByVal lpSecurityAttributes As IntPtr, _
-
                                       ByVal dwCreationDisposition As UInteger, _
-
                                       ByVal dwFlagsAndAttributes As UInteger, _
-
                                       ByVal hTemplateFile As IntPtr) As IntPtr
-
    End Function
-

          
-
    <DllImport("kernel32", SetLastError := True)> _
-
    Private Shared Function CloseHandle(ByVal hObject As IntPtr) As Boolean
-
    End Function
-

          
-
    Private Const GENERIC_READ As UInteger = &h80000000UI
-
    Private Const GENERIC_WRITE As UInteger = &h40000000UI
-
    Private Const FILE_SHARE_READ As UInteger = &h00000001UI
-
    Private Const FILE_SHARE_WRITE As UInteger = &h00000002UI
-
    Private Const OPEN_EXISTING As UInteger = 3
-

          
-
    Private Shared ReadOnly INVALID_HANDLE_VALUE As IntPtr = New IntPtr(-1)
-

          
-
    Private _handle As IntPtr
-

          
-
    Public ReadOnly Property Handle As IntPtr
-
      Get
-
        Return _handle
-
      End Get
-
    End Property
-

          
-
    Public Sub New(ByVal drive As DriveInfo, ByVal accessWrite As Boolean)
-
      Dim accessFlags As UInteger
-

          
-
      If drive.DriveType = DriveType.CDRom Then
-
        accessFlags = GENERIC_READ
-
      Else If drive.DriveType = DriveType.Removable Then
-
        accessFlags = GENERIC_READ Or GENERIC_WRITE
-
      Else
-
        Throw New NotSupportedException("リムーバブルドライブではありません")
-
      End If
-

          
-
      If accessWrite Then accessFlags = accessFlags Or GENERIC_WRITE
-

          
-
      _handle = CreateFile(String.Format("\\.\{0}:", drive.Name(0)), _
-
                           accessFlags, _
-
                           FILE_SHARE_READ Or FILE_SHARE_WRITE, _
-
                           IntPtr.Zero, _
-
                           OPEN_EXISTING, _
-
                           0, _
-
                           IntPtr.Zero)
-

          
-
      If _handle = INVALID_HANDLE_VALUE Then Throw New Win32Exception(Marshal.GetLastWin32Error())
-
    End Sub
-

          
-
    Public Sub Dispose() Implements IDisposable.Dispose
-
      If _handle <> INVALID_HANDLE_VALUE Then
-
        CloseHandle(_handle) ' ignore any errors
-
        _handle = INVALID_HANDLE_VALUE
-
      End If
-
    End Sub
-
  End Class
 
End Module
End Module
 
}}
}}
 
#tabpage-end
#tabpage-end