殆ど出番はなさそうなのですが、 プログラムから開く の問題です。
そうですね。 引数を受け取る様にしなければ ... 。
最近、 WPF で書く事が多いので、それを元に書いて見ますが、 Form でも基本は同じです。
ある拡張子のファイルに対いて、自分で書いたものが大活躍と言うケースは少ないと思います。
大抵は、既成のものが大活躍で、その隙間を埋める形で、自分のものが働いてくれています。
ですから、 Windows Explorer で表示される 「プログラムから開く」 「Open With... 」 はあまり関係無い のですが ... 。
仮に、 普通 (?) の形で書いたプログラムは、
大抵の場合、 その中でボタン等を用いてファイルを選択し開いたり、場合によっては、ドラッグドロップ実装したりしますね。
ドラッグドロップ実装 とは言え、多いケースは 受け手側 です。
そして、それらは、プログラムが起動されて やっと 機能する様になります。
そのままでは、この 「プログラムから開く」 は機能しません。
プログラム自体は開きますが ... 。
つまり、 プログラムが開かれた時点で、既に、ファイルが選択された状態になっていなければいけないからですね。
答えは簡単。
起動時に 引数 を与えれば 良いのですね。
引数の中身は ファイル群 です。
半角スペース区切りの文字列が渡されるのですね。
半角 Double Quotation Mark " を前後に入れてファイルパスの中にある 半角スペース を区別したりする
のを経験なさっていると思いますが、
「プログラムから開く」に関しては、これは不要、と言うか 反映済み です。
半角スペース混ざりのファイルパスも正確にハンドリングします。
では、 ちょっとした実験プログラムを書いて見ましょう。
WPF で Visual Studio 2017 Community の VB です。
コマンドライン引数 を 配列 で取得するのですが、
引数はファイル名である事を前提条件として、その拡張子と存否を確認して 取捨選択 をしています。
本来、 「プログラムから開く」 で存否確認は不要ですが、万一、実行時に手打ちの引数を与える事も考えて、こうしています。.
対象拡張子を変える場合、配列 fileExt() の値を書き換えて下さい。 小文字で です。.
Function ふたつですが、 ひとつはもう片方から呼ばれます。
Private Function GetCmdArgs() As String()
Dim value() As String = Nothing
Dim valueList As New List(Of String)
Dim cmdArgs() As String = Environment.GetCommandLineArgs
Dim cmdArgTxt As New Text.StringBuilder
If cmdArgs.Count > 1 Then
For i As Integer = 1 To cmdArgs.Count - 1 'First Is AppFile
If IsMatchTarget(cmdArgs(i)) Then
valueList.Add(cmdArgs(i))
End If
Next
End If
value = valueList.ToArray
Return value
End Function
Private Function IsMatchTarget(fileName As String) As Boolean
Dim fileExt() As String = {".jpg", ".jpeg"} 'Set Lower Char.
Dim value As Boolean = False
'Check File Exists (For Mistyping)
If Not IO.File.Exists(fileName) Then
Return value
Exit Function
End If
'Check File's Extension
For i As Integer = 0 To fileExt.Count - 1
If IO.Path.GetExtension(fileName).ToLower = fileExt(i) Then
value = True
Exit For
End If
Next
'Check ... If You Need, Add Here
'If Then
'
'End If
Return value
End Function
実際には、こうして取得した引数を、実際のプログラムの中で所定場所に設定する必要もありますが ... 。
謂わば、ドラッグドロップの実装の時と同じ考えですね。
文末に全コードを掲載しますので、笑いながら、ご覧下さい。 お~、我が スパゲティ コード !!!.
尚、
そこでは、 ListBox のバインドをせず .Refresh で対応するもの(コメントアウト部分)と、
ObservableCollection でバインドしたものとを 併記 してあります。 xaml ではなく Code Behind で記述。.
さて、
GUI のものばかり書いて来た私ですが、 今回のケースは より コンソール アプリ 寄り です。
実行時の 引数 があるので、 デバック が ... 。
慣れない事 は 大変 です。
デバッグ(D) をクリックし、 展開された項目の一番下の xxx のプロパティ で開き、
コマンドライン引数 の所 に記述すれば、 デバッグ が可能です。
この時、ファイル名が半角スペースを含むパスの場合、 " で囲む事をお忘れなく。
でないと、 引数の区切りと認識され、まともにデバッグ出来ませんので。
構成を Debug から Release に替えると、 引数無しで実行されますので、留意を。.
おっと、 *1.
複数項目を引数に取れる様に書いたのですが、
実際に、 OS Explorer の 「 プログラムから開く 」 から実行させると、
複数ファイル選択時には これが表示されません。
ファイル関連付けをしても、 個別に複数のプログラムが立ち上がります。 これでは、メモリ圧迫が心配 ... 。.
つまり、 この書き方は、用途によっては、オーバースペック と言いう次第でして ... 。 *1.
しかし、 プログラムのアイコンをデスクトップに貼り付けると様相が変わります。 *2.
其処へ、複数のファイルをドロップする事で、当初の思惑通り、複数のものを指定したのと同じ状況を再現出来ます。
つまり、 ファイルがひとつなら 「 プログラムから開く 」 で、 複数ならドロップで、 と言う事になりそうです。 *2.
ではでは、お約束の 全コード。
WPF xaml
<Window x:Class="MainWindow"Code VB.Net
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:Try_WPF_OpenFromPrg_jpg"
mc:Ignorable="d"
Title="MainWindow" Height="350" Width="525">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="150*"/>
<RowDefinition Height="150*"/>
</Grid.RowDefinitions>
<TextBox x:Name="TextBox0_Args" Margin="10,25,10,10" TextWrapping="Wrap" Text="TextBox" HorizontalContentAlignment="Stretch" VerticalContentAlignment="Stretch"/>
<ListBox x:Name="listbox2_Sample" Margin="10,25,10,10" Grid.Row="1" VerticalContentAlignment="Stretch" HorizontalContentAlignment="Stretch" Background="#FFFAFAFA"/>
<TextBlock HorizontalAlignment="Left" Margin="10,9,0,0" TextWrapping="Wrap" Text="Exe Args" VerticalAlignment="Top"/>
<TextBlock HorizontalAlignment="Left" Margin="10,9,0,0" Grid.Row="1" TextWrapping="Wrap" Text="Exe Control" VerticalAlignment="Top"/>
<CheckBox x:Name="CheckBox1_Add" Content="Keep Old Data" HorizontalAlignment="Left" Margin="150,0,0,0" Grid.Row="1" VerticalAlignment="Top"/>
<CheckBox x:Name="CheckBox2_Items" Content="Exist Items" HorizontalAlignment="Left" Margin="279,0,0,0" Grid.Row="1" VerticalAlignment="Top"/>
<Button x:Name="Button1_Do" Content="Add Args" HorizontalAlignment="Right" Margin="0,0,10,0" Grid.Row="1" VerticalAlignment="Top" Width="75"/>
</Grid>
</Window>
Class MainWindow
Dim listSrc As New List(Of String) 'If Not Bind
Dim listSrcBind As New ObjectModel.ObservableCollection(Of String) 'If Bind
Private Sub MainWindow_Loaded(sender As Object, e As RoutedEventArgs) Handles Me.Loaded
Dim targetArgs() As String = GetCmdArgs()
Dim cmdArgTxt As New Text.StringBuilder
For Each item In targetArgs
cmdArgTxt.Append(item)
cmdArgTxt.Append(vbCrLf)
Next
Me.TextBox0_Args.Text = cmdArgTxt.ToString
'for Bind (WPF)
listbox2_Sample.ItemsSource = listSrcBind
End Sub
Private Function GetCmdArgs() As String()
Dim value() As String = Nothing
Dim valueList As New List(Of String)
Dim cmdArgs() As String = Environment.GetCommandLineArgs
Dim cmdArgTxt As New Text.StringBuilder
If cmdArgs.Count > 1 Then
For i As Integer = 1 To cmdArgs.Count - 1 'First Is AppFile
If IsMatchTarget(cmdArgs(i)) Then
valueList.Add(cmdArgs(i))
End If
Next
End If
value = valueList.ToArray
Return value
End Function
Private Function IsMatchTarget(fileName As String) As Boolean
Dim fileExt() As String = {".jpg", ".jpeg"} 'Set Lower Char.
Dim value As Boolean = False
'Check File Exists (For Mistyping)
If Not IO.File.Exists(fileName) Then
Return value
Exit Function
End If
'Check File's Extension
For i As Integer = 0 To fileExt.Count - 1
If IO.Path.GetExtension(fileName).ToLower = fileExt(i) Then
value = True
Exit For
End If
Next
'Check ... If You Need, Add Here
'If Then
'
'End If
Return value
End Function
Private Sub CheckBox2_Items_Checked(sender As Object, e As RoutedEventArgs) Handles CheckBox2_Items.Checked
'listSrc.Add("Test1.jpg")
'listSrc.Add("Test2.jpg")
'listbox2_Sample.ItemsSource = listSrc
'listbox2_Sample.Items.Refresh()
'For Bind
listSrcBind.Add("Test1.jpg")
listSrcBind.Add("Test2.jpg")
End Sub
Private Sub CheckBox2_Items_Unchecked(sender As Object, e As RoutedEventArgs) Handles CheckBox2_Items.Unchecked
'listSrc.Clear()
'listbox2_Sample.ItemsSource = listSrc
'listbox2_Sample.Items.Refresh()
'For Bind
listSrcBind.Clear()
End Sub
Private Sub Button1_Do_Click(sender As Object, e As RoutedEventArgs) Handles Button1_Do.Click
If CheckBox1_Add.IsChecked Then 'Add Args
Else 'Replace To Args
'listSrc.Clear()
listSrcBind.Clear()
End If
Dim targetArgs() As String = GetCmdArgs()
'listSrc.AddRange(targetArgs)
'listbox2_Sample.ItemsSource = listSrc
'listbox2_Sample.Items.Refresh()
'For Bind
For Each item In targetArgs
listSrcBind.Add(item)
Next
End Sub
End Class
[2017/06/10] 顛末を追記 *1.
[2017/06/13] デスクトップアイコンとしての機能を追記 *2.
0 件のコメント:
コメントを投稿