2010年10月27日水曜日

◆Bits転送4 GUIクライアント版

これまで調べてきたBits転送機能を使ってGUI版のクライアントを作ってみた。
画面はこんな感じ。
image

ソースはこんな感じ。(Bits.ps1)

Set-PSDebug -Strict
$host.UI.RawUI.WindowTitle = "Bits転送ホスト"

Import-Module BitsTransfer
Add-Type -AssemblyName System.Windows.Forms
Add-Type -AssemblyName Microsoft.VisualBasic
$bindingSource = [System.Windows.Forms.BindingSource]
$bindingSource1 = New-Object $bindingSource
$bindingSource2 = New-Object $bindingSource
$path = Split-Path $myInvocation.MyCommand.path
$MessageBox = [System.WIndows.Forms.MessageBox]
$StartedEndMark,$endedEndMark = "☆","★"
 
function Main{
   
    #Formソースの読み込み
    Write-Host "Bits転送起動中・・・"
    $source1 = "Form1.cs"
    $source2 = "Form1.Designer.cs"
    $source3 = "CommonClasses.cs"
    $source = gc (Join-Path $path $source1)
    $source += gc (Join-Path $path $source2)
    $source += gc (Join-Path $path $source3)
    Add-Type -TypeDefinition ($source | out-string) -ReferencedAssemblies System.Windows.Forms,
                                                                          System.Drawing,
                                                                          System.Data,
                                                                          System.Core
    #Form表示
    $form = New-Object Bits.Form1
    $iconPath =  Join-Path $path "prodicon.ico"
    if(Test-Path $iconPath){
        $icon = New-Object System.Drawing.Icon (Join-Path $path "prodicon.ico")
        $form.icon = $icon
    }

    #イベント登録
    $form.Add_Load({formLoad})                      #フォームLoad処理
    $form.Add_FormClosing({formClosing})            #フォームクローズ処理
   
    $form.btnSync.Add_Click({btnSyncClick})         #同期実行処理
   
    $form.btnSerial.Add_Click({btnSerialClick})     #直列キュー投入処理
    $form.btnSuspend.Add_Click({btnSuspendClick})   #サスペンド処理
    $form.btnResume.Add_Click({btnResumeClick})     #Resume処理
    $form.btnDelete.Add_Click({btnDeleteClick})     #削除処理
   
    $form.btnParallel.Add_Click({btnParallelClick}) #並列キュー投入処理
    $form.btnSuspend2.Add_Click({btnSuspend2Click}) #サスペンド処理
    $form.btnResume2.Add_Click({btnResume2Click})   #Resume処理
    $form.btnDelete2.Add_Click({btnDelete2Click})   #削除処理
   
    $form.foreground.Add_Click({contextGridPriorityClick("foreground")})  #コンテキストメニュー
    $form.High.Add_Click({contextGridPriorityClick("High")})  #コンテキストメニュー
    $form.Normal.Add_Click({contextGridPriorityClick("Normal")})  #コンテキストメニュー
    $form.Low.Add_Click({contextGridPriorityClick("Low")})  #コンテキストメニュー
   
    #データソース設定
    $form.DataGridView1.DataSource = $bindingSource1
    $form.DataGridView2.DataSource = $bindingSource2
   
    fncRegistTimer
   
    cls
    [Windows.Forms.Application]::Run($form)
}

#フォームLoad処理
function formLoad{
    #投入済みで未完了のJOBを回復
    Get-BitsTransfer | %{
        $job = New-Object Bits.Job
        $_.FileList | Set file
        $job.FileName = Split-Path $file.RemoteName -Leaf
        $job.FromText = $file.RemoteName
        $job.ToText = $file.LocalName
        $job.Status = $_.JobState
        $job.JobID = $_.JobId
        $job.EndMark = $StartedEndMark
        if($_.DisplayName -eq "Serial"){
            $bindingSource1.Add($job)
        }else{
            $bindingSource2.Add($job)
        }
    }
   
    #直列キューの未投入分を回復
    $xmlpath = Join-Path $path "bindingsource1.xml"
    if(Test-Path $xmlpath){
        Import-Clixml $xmlpath | %{
            $job = New-Object Bits.Job
            $job.FileName = $_.FileName
            $job.FromText = $_.FromText
            $job.ToText = $_.ToText
            $job.Status = ""
            $job.EndMark = $StartedEndMark
            $bindingSource1.Add($job)
        }
    }
   
    #GridViewを選択解除&表示行調整
    if($bindingSource1.Count -gt 0){
        $form.DataGridView1.FirstDisplayedScrollingRowIndex = $bindingSource1.Count - 1
        $form.DataGridView1.ClearSelection()
    }
    if($bindingSource2.Count -gt 0){
        $form.DataGridView2.FirstDisplayedScrollingRowIndex = $bindingSource2.Count - 1
        $form.DataGridView2.ClearSelection()
    }
}

#フォームClosing処理
function formClosing{
    #$_.Cancel = $true
    $message1 = @"
キューに未終了のJOBが存在します。
JOBはそのまま継続されますが、
再度アプリケーションを実行するまで転送は完了しません。
"@
   
    #直列キュー未投入分を退避
    $bindingSource1 | ?{$_.Status -eq ""} | Export-Clixml -Path (Join-Path $path "bindingsource1.xml")
   
    foreach($job in $bindingSource1){
        if($job.EndMark -eq $StartedEndMark){
            $MessageBox::Show($message1)
            return
        }
    }
   
    foreach($job in $bindingSource2){
        if($job.EndMark -eq $StartedEndMark){
            $MessageBox::Show($message1)
            return
        }
    }
}

#同期実行処理
function btnSyncClick{
    if(fncCheckPath){
        [Microsoft.VisualBasic.Interaction]::AppActivate("Bits転送ホスト")
        Start-BitsTransfer $form.txtFrom.text $form.txtTo.text
        [Microsoft.VisualBasic.Interaction]::AppActivate("Bits転送")
    }else{
        $MessageBox::Show("転送元と転送先に正しいパスを指定してください")
        Return
    }
}

#直列キュー投入処理
function btnSerialClick{
    if(fncCheckPath){
        $job = New-Object Bits.Job
        $job.FileName = Split-Path $form.txtFrom.text -Leaf
        $job.FromText = $form.txtFrom.text
        $job.ToText = $form.txtTo.text
        $job.Status = ""
        $job.EndMark = $StartedEndMark
        $bindingSource1.Add($job)
        $form.DataGridView1.ClearSelection()
        $form.DataGridView1.FirstDisplayedScrollingRowIndex = $bindingSource1.Count - 1
    }else{
        $MessageBox::Show("転送元と転送先に正しいパスを指定してください")
        Return
    }
   
}

#コンテキストメニュー処理(プライオリティ変更処理)
function contextGridPriorityClick($priority){
    $arrJobIds = @()
    foreach ($row in $form.dataGridView2.SelectedRows)
    {
        if($bindingSource2[$row.Index].EndMark -eq $StartedEndmark){
            $arrJobIds += $bindingSource2[$row.Index].JobID
        }
    }
   
    if($arrJobIds.Count){
        Get-BitsTransfer -JobId $arrJobIds | Set-BitsTransfer -Priority $priority
    }
}

#パス中の不要文字削除&空白チェック
function fncCheckPath{
    $form.txtFrom.text = $form.txtFrom.text -replace '"',""
    $form.txtTo.text = $form.txtTo.text -replace '"',""
    try{
        if($form.txtFrom.text.StartsWith("http")){
            $result = Test-Path $form.txtTo.text -ea Stop
            if($result){
                $form.txtTo.text = Resolve-Path $form.txtTo.text
            }
            return $result
        }else{
            $result =  (Test-Path $form.txtFrom.text -ea Stop) -and (Test-Path $form.txtTo.text -ea Stop)
            if($result){
                $form.txtFrom.text = Resolve-Path $form.txtFrom.text
                $form.txtTo.text = Resolve-Path $form.txtTo.text
            }
            return $result
        }
    }Catch{
        Write-Warning $error[0]
        return $false
    }
}

#サスペンド処理
function btnSuspendClick{
    fncSuspend $form.DataGridView1 $bindingSource1
}
function btnSuspend2Click{
    fncSuspend $form.DataGridView2 $bindingSource2
}
function fncSuspend($grid,$bindingSource){
    $selectedRows = $grid.SelectedRows
    if($selectedRows.Count){
        $selectedRows | %{
            $job = $bindingSource[$_.index] #選択行に対応するJOBオブジェクト
            if($job.EndMark -eq $StartedEndMark -and $job.JobId){
                Get-BitsTransfer -JobId $job.JobId | Suspend-BitsTransfer
            }
        }
    }else{
        $MessageBox::Show("対象の行(JOB)を選択してください")
    }
}

#Resume処理
function btnResumeClick{
    foreach($job in $bindingSource1){
        if(("Transferring","Connecting") -contains $job.Status){
            $MessageBox::Show("他のJOBが実行中です")
            return
        }
    }
   
    fncResume $form.DataGridView1 $bindingSource1 {break}
    
}
function btnResume2Click{  
    fncResume $form.DataGridView2 $bindingSource2 {continue}
}
function fncResume($grid,$bindingSource,$script){
    $selectedRows = $grid.SelectedRows
    if($selectedRows.Count){
        foreach($selectedRow in $selectedRows){
            $job = $bindingSource[$selectedRow.index]
            if($job.Status -eq "Suspended"){
                Get-BitsTransfer -JobId $job.JobId | Resume-BitsTransfer -Asynchronous
                Invoke-Command $script #直列キューの時はResumeはひとつだけ
            }
        }
    }else{
        $MessageBox::Show("対象の行(JOB)を選択してください")
    }
}

#削除処理
function btnDeleteClick{
    fncDelete $form.DataGridView1 $bindingSource1
}
function btnDelete2Click{
    fncDelete $form.DataGridView2 $bindingSource2
}
function fncDelete($grid,$bindingSource){
    $selectedRows = $grid.SelectedRows
    if($selectedRows.Count){
        $selectedRows | %{
            $job = $bindingSource[$_.index] #選択行に対応するJOBオブジェクト
            #TransferredはComplete-Transferで既に消えている
            if($job.EndMark -eq $StartedEndMark -and $job.JobId){ 
                Get-BitsTransfer -JobId $job.JobId | Remove-BitsTransfer
            }
            $bindingSource.RemoveAt($_.index)
            $grid.Refresh()
        }
    }else{
        $MessageBox::Show("対象の行(JOB)を選択してください")
    }
}

#並列キュー投入処理
function btnParallelClick{
    if(fncCheckPath){
        $job = New-Object Bits.Job
        #JOB情報を取得しGridへ表示
        $job.FromText = $form.txtFrom.text
        $job.ToText = $form.txtTo.text
        $job.EndMark = $StartedEndMark

        #フォームからプライオリティ判定
        foreach($cntrl in $form.groupBox2.Controls){
            if($cntrl -is [System.Windows.Forms.RadioButton]){
                if($cntrl.Checked){
                    $priority = $cntrl.Text
                    break
                }
            }
        }
           
        #Tranfertype判定
        $type = fncSetTransfertype
        $job.FileName = Split-Path $form.txtFrom.text -Leaf
       
        #JOB投入
        $ret = Start-BitsTransfer $form.txtFrom.text $form.txtTo.text  `
                                    -Async -TransferType $type -Priority $priority
        Set-BitsTransfer -BitsJob $ret -DisplayName "Parallel"
       
        #JOBステータス更新処理
        fncSetJobInfo $job $ret   

        $bindingSource2.Add($job)
        $form.DataGridView2.ClearSelection()
        $form.DataGridView2.FirstDisplayedScrollingRowIndex = $bindingSource2.Count -1
    }else{
        $MessageBox::Show("転送元と転送先に正しいパスを指定してください")
        Return
    }
   
}

#タイマー処理
function fncRegistTimer{

    $form.timer1.Add_Tick({
        #直列キューJOBステータス更新処理
        fncUpdateJobStatus $bindingSource1
       
        #並列キューJOBステータス更新処理
        fncUpdateJobStatus $bindingSource2
       
        #直列キューJOB投入処理
        :outer foreach($job in $bindingSource1){
            switch($job.Status){
                "Transferring"{break outer}
                "Connecting" {break outer}
                "" {
                        $type = fncSetTransfertype
                        $ret = Start-BitsTransfer $job.FromText $job.ToText  `
                                    -Async -TransferType $type -Priority Foreground
                        Set-BitsTransfer -BitsJob $ret -DisplayName "Serial"
                        fncSetJobInfo $job $ret
                        break outer
                    }
                default{}
            }
        }
       
        #データグリッドリフレッシュ
        $form.DataGridView1.AutoResizeColumns()
        $form.DataGridView1.Refresh()
        $form.DataGridView2.AutoResizeColumns()
        $form.DataGridView2.Refresh()

       
    })
}

function fncSetTransfertype{
    if($form.txtFrom.text.StartsWith("http")){
        return "Download"
    }elseif($form.txtTo.text.StartsWith("\\")){
        return "Upload"
    }else{
        return "Download"
    }
}

#JOBステータス更新処理
function fncUpdateJobStatus($bindingSource){
    foreach($job in $bindingSource){
        if($job.EndMark -eq $endedEndMark){continue}
        if($job.JobID){
            $ret = Get-BitsTransfer -JobId $job.JobID
            fncSetJobInfo $job $ret
        }              
    }
}

#JOBステータス設定処理
function fncSetJobInfo($job,$bitsInfo){
    $job.Status = $bitsInfo.JobState
    $job.JobID = $bitsInfo.JobId
    $job.StartTime = $bitsInfo.CreationTime
    $job.Priority = $bitsInfo.Priority
    $job.Percent = [int](($bitsInfo.BytesTransferred/$bitsInfo.BytesTotal)*100)
    if($job.Status -eq "Transferred"){
        $job.EndTime = $bitsInfo.TransferCompletionTime
        $job.EndMark = $endedEndMark
        $job.Percent = 100
        Complete-BitsTransfer -BitsJob $bitsInfo.JobId
    }
}

Main

さすがに面倒なのでFormはVisualStudioで作ってAdd-Typeでソースを取り込んでいる。
起動用のバッチファイルとかと纏めて以下へ置いた。
http://cid-ddbd2fc6fc634eaa.office.live.com/self.aspx/.Public/BitsGUI.zip

そこそこ使い物になるように思うのですが、いかがなものでしょう。

0 件のコメント:

コメントを投稿