ファイルが使用中かどうかを取得したいです。 への返答

投稿で使用できる特殊コードの説明。(別タブで開きます。)
本名は入力しないようにしましょう。
投稿した後で削除するときに使うパスワードです。返答があった後は削除できません。
返答する人が目安にします。相手が小学生か社会人かで返答の仕方も変わります。
最初の投稿が質問の場合、質問者が解決時にチェックしてください。(以降も追加書き込み・返信は可能です。)
※「過去ログ」について書くときはその過去ログのURLも書いてください。

以下の返答は逆順(新しい順)に並んでいます。

投稿者 みどりこぶた  (高校生) 投稿日時 2017/9/7 20:52:53
回答ありがとうございますm(_ _)m

>HRESULT の意味についてはこちら。
エラーコードの値にもある程度のルールがあったりするのですね。
非常に勉強になります。

>基本的には、Windows SDK のヘッダーファイルから取得することになります。
今回もまた直球な解答ありがとうございます。
「何それ」レベルで理解してないので、WCF等の方をある程度理解してから、また今度調べてみようと思います。
参考リンクも感謝です。

細かいところまで親切丁寧な説明、ありがとうございました。
もし次投稿する機会ありましたら、そのときはまたご助力いただけましたら幸いですm(_ _)m
投稿者 魔界の仮面弁士  (社会人) 投稿日時 2017/9/7 18:44:59
HResult プロパティは、IOException のみならず、
素の Exception クラスにも用意されています。

ただし、.NET 3.5 までは Protected Get/Protected Set でした。
.NET 4 以降で、Public Get/Protected Set なスコープに変更されています。

HRESULT の意味についてはこちら。
https://msdn.microsoft.com/ja-jp/library/system.exception.hresult.aspx
http://ascii.jp/elem/000/001/432/1432965/


エラーコードに対応するメッセージを知りたければ、Win32Exception.Message を利用できます。
Dim ex As New System.ComponentModel.Win32Exception(STIERR_SHARING_VIOLATION)
MsgBox(ex.Message)
Throw ex



さて、ご質問の『定数一覧』ですが、基本的には、Windows SDK のヘッダーファイルから
取得することになります。公式のものでなくても良ければ、下記が便利でしょう。
http://ir9.jp/prog/ayu/win32err.htm#com

ただし、上記にも掲載されていないコードはありますので、あくまでも参考程度に。
 例:XPS_E_某系のエラー(0x8052**** 番台)

また、エラーの発生元が変わることで、同じエラーコードが別の意味を持つこともあります。
 例:0x80040200 = TS_E_INVALIDPOS = EVENT_E_FIRST = MPEG2_E_UNINITIALIZED
投稿者 みどりこぶた  (高校生) 投稿日時 2017/9/7 17:40:31
daive 様、回答ありがとうございます。
様々な候補ありがとうございます。ほとんどが vb.net だけではできないと思っていました。
もう一度、ひとつづつきちんと調べなおしてみようと思います。
>ディスク上のファイル
というのは私が考えていたものと似たようなものでしょうか。




魔界の仮面弁士 様、回答ありがとうございます。
>強いて言えば
直球な回答ありがとうございます。何というか、求めていた解答そのものズバリでした。
余談ですが、IOException.HResult の定数一覧のようなものは、どう調べると検索にヒットしますでしょうか…。
>Mutex、WCF、.NET Remoting、MemoryMappedFile、、
こちらも様々な候補ありがとうございます。上述しましたが、vb.net、いろいろできるのですね。




まず、検索・知識不足な面、失礼しました。
とりあえず、ex.HResult で判断、ということで解決とさせていただきますm(_ _)m
浅くですが調べた感じ、.NET Remoting か WCF あたりなら私にもできそうなので、時間がとれたときにそれに置き換えようと思います。
もう少し時間がとれた時、他に候補いただいた Windowsサービス、MemoryMappedFile、DB、同期サーバープログラム の方も調べてみようと思います。

ありがとうございました。
投稿者 魔界の仮面弁士  (社会人) 投稿日時 2017/9/6 19:47:00
強いて言えば、こんな感じでしょうか。
Try
 'ファイルオープン処理 
Catch ex As IOException When ex.HResult = STIERR_SHARING_VIOLATION '&H80070020 
 'プロセスはファイルにアクセスできません。別のプロセスが使用中です。 
Catch ex As IOException When ex.HResult = STIERR_DEVICE_LOCKED '&H80070021 
 'プロセスはファイルにアクセスできません。別のプロセスがファイルの一部をロックしています。 
Catch ex As Exception
 'その他の例外:必要に応じて再 Throw する 
Finally
 '後始末 
End Try



機能要件にもよりますが、プロセス間の排他制御だけが目的ならば、
ファイルではなく、System.Threading.Mutex を使った方が簡単かも知れません。

また、プロセス間でのデータ通信が目的ならば、
WCF を使うとか(System.ServiceModel 名前空間)、あるいは
昔ながらの .NET Remoting (System.Runtime.Remoting 名前空間)を
利用するという手もあります。

同一ファイルを複数のプロセスから編集する場合には、
System.IO.MemoryMappedFiles.MemoryMappedFile
を使うという手もあります。(排他制御とは別の話として)
投稿者 (削除されました)  () 投稿日時 2017/9/6 19:45:50
(削除されました)
投稿者 daive  (社会人) 投稿日時 2017/9/6 19:10:07
>もとはと言えば、別々のプロセス間でちょっとした同期をとりたくなり、
>それにファイルを使用しています。
>他に簡単な方法があればいいのですが、C++ などは書いたことなくて自身がなくて…、

古くからある方法は、
メモリーマップドファイル:だんだん使わなくなっている。
 ⇒もっと古いのは、アセンブラ時代に、共有実メモリ、実I/O でマッピング
ディスク上のファイル:DOS時代からある方法
Windowsサービス
同期サーバプログラムが、同期、スケジュール、を担う
プロセス間通信、WCF などなど
ほかに、DBを使ってしまう。
⇒SQlite など軽量DB
投稿者 みどりこぶた  (高校生) 投稿日時 2017/9/6 16:54:19
すみません、非常に不十分な質問文でした、少し補足します。

ファイルが使用中かどうか、というより、
ファイルの排他的なオープンを試行した結果、成功・ロック取得の失敗・それ以外の原因による失敗、で切り分けたいです。


最初は、 事前に IO.File.Exists で存在するかどうかなどチェックを入れていたのですが、
よく考えると、事前チェックでは意味が無いことに気づき、
更に良く考えると、そもそもオープンに失敗したとき、ファイルが存在さえすれば、ロック取得に失敗したとみなせるのか、と気づき…
上記のようなコードになりました。


指摘感謝します、もう一度調べなおしてみました。
みましたが、
・例外を catch したらファイル使用中とみなす
・APIを使う
しか見つけられませんでした…。
APIの方は「IsFileAlreadyOpen」などを使うのでしょうか…?
ロック取得の失敗(共有違反エラー?)は区別できたのですが、「Err.LastDllError」で取得する値は他のスレッドやプロセスと共有なのでしょうか…。



もとはと言えば、別々のプロセス間でちょっとした同期をとりたくなり、それにファイルを使用しています。
他に簡単な方法があればいいのですが、C++ などは書いたことなくて自身がなくて…、vb.net の範囲でもできる方法ありますでしょうか…?



もう少しヒント与えていただけましたら幸いですm(_ _)m
投稿者 daive  (社会人) 投稿日時 2017/9/6 12:52:33
代理検索:vb.net ファイル 使用中 チェック
https://www.google.co.jp/search?q=vb.net+%E3%83%95%E3%82%A1%E3%82%A4%E3%83%AB+%E4%BD%BF%E7%94%A8%E4%B8%AD+%E3%83%81%E3%82%A7%E3%83%83%E3%82%AF&oq=VB.NET+%E3%83%95%E3%82%A1%E3%82%A4%E3%83%AB%E3%80%80%E3%81%97&gs_l=psy-ab.3.3.0i4k1l5j0i4i30k1l3.8235763.8242341.0.8245833.16.16.0.0.0.0.201.1662.11j4j1.16.0....0...1.1j4.64.psy-ab..0.16.1653...0j0i131k1j0i3k1.tGFXgDhep8Y

サイト、フォーラムの書込みなどを渉猟して、知見得てください。
投稿者 みどりこぶた  (高校生) 投稿日時 2017/9/5 22:49:10
すみません、コードの上から8行目、間違えてました。
If ex.Message IsNot Nothing AndAlso sss.Length <= ex.Message.Length AndAlso ex.Message.Substring(0, sss.Length) = sss Then
投稿者 みどりこぶた  (高校生) 投稿日時 2017/9/5 20:01:42
ファイルが使用中かどうかを取得したいです。

    Dim ppp As String = "D:\Test.txt"
    Dim sss As String = "別のプロセスで使用されているため、"
    Try
        Using fs = New IO.FileStream(ppp, IO.FileMode.Open, IO.FileAccess.ReadWrite, IO.FileShare.None)
            MsgBox("オープン成功。")
        End Using
    Catch ex As Exception
        If sss.Length <= ex.Message AndAlso ex.Message.Substring(0, sss.Length) = sss Then
            MsgBox("ロックの取得に失敗。")
        Else
            MsgBox("何かしらの理由で失敗。" & vbNewLine & ex.Message)
        End If
    End Try

「Catch ex As Exception」の「ex.Message」に「別のプロセスで使用されているため、...」と文字列があるので、
とりあえずそれで判断しているのですが、本来どのように取得すれば良いのでしょうか?
低レベルな質問ですみません。


vb.net、vs2017で書いてます。勉強とかではなく趣味で、高校生です。常識無いかもしれませんが、指摘いただけると助かります。