ファイルを関連付けられたアプリケーションで開く方法

タグの編集
投稿者 Tさん  (社会人) 投稿日時 2023/1/21 23:37:21
皆さんはじめましてTさんと申します。
今、Visual Studio 2022 Community を用いて
vb.netの勉強中の超初心者です。

今、vb.netでファイルを関連付けられたアプリケーションで開きたいのですがうまくいきません。

ひとつは
Shell("c:\users\owner\Dsktop\画像.png")
で試ししましたが、
「ファイルが見つかりません」とエラーとなります。

もつひとつは
Process.Start("c:\users\owner\Dsktop\画像.png")
で試しましたが
「An error occurred trying to start process 'C:\Users\owneri\Desktop\画像.png' with working directory 'C:\作業フォルダ\プロジェクト\bin\Debug\net6.0-windows'. The specified executable is not a valid application for this OS platform.」とエラーになります。

OSはWindow11Proです。
ネットでいろいろ調べましたが分からず、
またこの問題を解決するためにどのような情報が必要かもわかっていません。

全くの初心者で情報不足申し訳ありませんが、解決策わかる方がいらっしゃれば教えて頂きたいです。

投稿者 魔界の仮面弁士  (社会人) 投稿日時 2023/1/22 07:29:33
> Shell("c:\users\owner\Dsktop\画像.png")
Dsktop ?
Desktop ではなく?

スペルミスなどが無いようにするため、
Shift キーを押しながら、既存のファイルを右クリックして、
[パスのコピー]を試してみてください。


ただし Shell には、関連付けによる起動はできません。
Shell("notepad.exe C:\test\sample.txt") などのように
実行可能ファイルのパラメーターとして渡すしかないので
今回の目的にはそぐわないでしょう。


> Process.Start("c:\users\owner\Dsktop\画像.png")
こちらも Dsktop になっていますね。

また、エラーメッセージが英語になっている所を見ると、
.NET Framework 用のプロジェクト テンプレートではなく
.NET 用のものを使っておられるようですね。
ターゲット フレームワークのバージョンは .NET 6.0 でしょうか、.NET 7.0 でしょうか?

また、できればどのテンプレートを使っているのかも教えてください。
コンソール アプリ、Windows フォーム、WPF、ASP .NET Web アプリなど。

たとえば ASP.NET の場合、こうした方法をとることはできないので、
質問内容によっては、プロジェクトの種類が重要になることもあるためです。
投稿者 Tさん  (社会人) 投稿日時 2023/1/22 09:33:24
魔界の仮面弁士さんはじめまして。
ご回答ありがとうございます。
Shellはだめなのですね。勉強不足でした。

ターゲット フレームワークのバージョンは .NET 6.0で、
テンプレートはWindowsフォー厶です。

ファイルパスについてはこちらへ記述ミスです。
すみません。

実際にはOpenFileDialogを用いて、パスを取得し、
SQLServerデータベースに書き込み。
そのデータをlistviewに読み出して
選択したパスを開こうとしています。

ウォッチで開こうとしているパスを確認、コピーでエクスプローラーに貼り付けでは開くので、パスはあっているはずです。

問題点はどこになるでしょうか?無知ですみません。
投稿者 魔界の仮面弁士  (社会人) 投稿日時 2023/1/22 10:43:03
> 実際にはOpenFileDialogを用いて、パスを取得し、
> SQLServerデータベースに書き込み。

クライアント側にあるファイルの絶対パスを、データベースにフルパスで記録するのは
あまり一般的では無いように思いますが…それはさておき。

今回使ったこのコードですが、実は
Process.Start(filePath)
WinFormsApp 「Windows フォーム アプリ」 の場合と
WindowsApp「Windows フォーム アプリケーション (.NET Framework)」とで
その振る舞いが異なるのです。特に、実行可能ファイルではなくドキュメントを渡した時には。

ドキュメントのパスを渡した場合、.NET Framework 版であれば、
そのまま既定のアプリで関連付け実行されますが、.NET 版ではそうではありません。

.NET Core および .NET 版の場合、既にお試しいただいたように
 The specified executable is not a valid application for this OS platform.
のエラーになってしまうでしょう。Shell 関数と同様に「実行可能ファイル」を指定せねばなりません。

Shell($"cmd.exe /C ""{filePath}""", AppWinStyle.Hide)
'Process.Start("cmd.exe", "/C ""{filePath}""") 


.NET で既定のアプリを開くには、UseShellExecute を True にする必要があります。
Process.Start(New ProcessStartInfo(filePath) With {.UseShellExecute = True})


なお下記は .NET Framework や Mono では True、.NET では False となります。
MsgBox(New ProcessStartInfo().UseShellExecute)



.NET Framework と .NET とでは、このような細かい差異が色々とありますのでご注意ください。
ゆえに質問時には、ターゲット フレームワークなどの環境情報も重要だったりします。
投稿者 Tさん  (社会人) 投稿日時 2023/1/22 11:38:49
>クライアント側にあるファイルの絶対パスを、データベースにフルパスで記録するのは
>あまり一般的では無いように思いますが…
試験的にいろいろ試しており一旦このような形にしております。
共有ディスクに保存したファイルをアプリで管理できるような仕組みを考えおります。
当初の質問とは異なりますが、ご教授ください。
一般的にはデータサーバーにファイルをコピー、そのパスをデータベースに保存、読み出しのイメージですか?

>.NET で既定のアプリを開くには、UseShellExecute を True にする必要があります。
ご教示頂いた方法で成功しました。
ありがとうございます!

ターゲットフームで違いがあるとは知りませんでした。
勉強になりました。ありがとうございます。
今後はそのあたりも注意して、調べたり質問させて頂きます。


投稿者 魔界の仮面弁士  (社会人) 投稿日時 2023/1/23 00:39:39
> ターゲットフームで違いがあるとは知りませんでした。
下記も参考にしてみてください。
.NET Framework から移行する場合の、API の非互換性についてまとめられています。
https://learn.microsoft.com/ja-jp/dotnet/core/compatibility/fx-core

今見てみると、この資料の最初の項目が今回の UseShellExecute の件ですね…!


> 共有ディスクに保存したファイルをアプリで管理できるような仕組みを考えおります。
共有ディスクに管理しているのであれば、
>>> c:\users\ownerではなく、UNC パスなどで記録されるはずでは……?

それと、OpenFileDialog からだと指定する方法をそのまま用いた場合、
そのままだとリムーバブルメディア(CD-ROM や USB メモリーなどのパス)が
記録されてしまうといった懸念もあります。

とはいえ、LocalDB によるスタンドアロン構成のアプリなどであれば、たとえば先のように
c:\users\owner\ なローカルのフルパスを記録する形式を用いることもあるので、
どういう管理方法をとるのかはケースバイケースであるとはいえます。

しかし一般的なデータベースで記録する場合、特定の PC に依存した情報で記録すると
他環境からの接続に対しての移植性が失われます。可能であれば、複数のクライアントから
接続可能なデータ設計をあらかじめ検討しておいた方が良いでしょう。


> 一般的にはデータサーバーにファイルをコピー、
> そのパスをデータベースに保存、読み出しのイメージですか?
ファイルの保存先が Windows Server なら「データ重複除去」の恩恵も得られますので、
クライアント ローカルで保持するよりは、ちゃんとした「サーバー」にファイルを集約した方が良いと思います。
(こうした重複除去機能をもったファイルシステムは、Windows 以外にもあります)
https://learn.microsoft.com/ja-jp/windows-server/storage/data-deduplication/overview


とはいえ、そのためにデータベース サーバーにファイルをコピーするのが一般的かというと、
必ずしもそうとは限らないです。

もちろん、データベース ローカルに持たせておくのも選択肢の一つではありますが、
パス情報ではなく「ファイルのバイナリそのものをデータベース上に保存する」方式が使われたり、
他にも「データベース サーバー以外の共有保存先」に集約するという選択肢もあるでしょう。

バイナリ保存の場合、たとえば SQL Server であれば、VARBINARY(MAX) FILESTREAM や LOB を使うことができます。
この場合、先ほど書いた「リムーバブル メディアの情報」であっても、問題なく保持することができますし、
ファイルシステムとデータベースの情報が不一致になることがなく、データの一元管理ができます。
その分、データベースのストレージ消費は増えるのでバックアップ計画は考慮する必要がありますし、
そのファイルを保存/取り出すための仕組みを構築する必要はありますけれどね。

データベースサーバー以外に補完する場合、たとえば AD 構成があれば、
DFS (分散ファイルシステム)を併用するのも良いでしょう。これならば、
自分自身に保存しようと他のサーバーに保存しようと、あるいは複数台で保存したとしても、
また、保存先のサーバーが変更になったとしても、UNC パスを変更させる必要がありません。

そうした DFS が使えないような場合は、フルパスを指定する方式の代わりに、
「(基準ディレクトリからの)相対パス」で管理する手法がしばしば取られます。
この場合の基準ディレクトリとは、NAS 上のパスでも構いません。

あるいはファイルをクラウドストレージに保存し、データベースはそのアドレスを保持するとか。

処理系によっては Database FileSystem といった、ファイル管理用の仕組みを持っているケースもありますね。
投稿者 Tさん  (社会人) 投稿日時 2023/1/23 04:42:12
>下記も参考にしてみてください。
参考先までありがとうございます!
目を通してみます!

データ管理の仕組みについても詳細に記載いただきありがとうございます!!

私自身、こういった分野の専門的な職種でもなくプログラミングなどもVBAからネットの情報を拾い集めて覚えたような人間なので知らない言葉だらけです…。
(専門分野の方々から見るとそんなことも知らないの?何んでそんな変な手法とるの?というレベルだと思います)

頂いた情報から更に深めて勉強していきます!

またこの掲示板でご質問させて頂くこともあるかと思いますので、御縁があればいろいろとご教授頂けると幸いです。

魔界の仮面弁士さん、この度は色々ありがとう御座いました!!