C# と VB.NET の質問掲示板

ASP.NET、C++/CLI、Java 何でもどうぞ

ログ内検索
  • キーワードを複数指定する場合は 半角スペース で区切ってください。
  • 検索条件は、(AND)=[A かつ B] (OR)=[A または B] となっています。
  • [返信]をクリックすると返信ページへ移動します。
キーワード/ 検索条件 /
検索範囲/ 強調表示/ ON (自動リンクOFF)
結果表示件数/ 記事No検索/ ON
大文字と小文字を区別する

全過去ログを検索

<< 0 >>
■85029  複数ファイルをコピーする時に進捗ダイアログを表示する
□投稿者/ カンガルー -(2017/09/05(Tue) 19:05:14)

    分類:[.NET 全般] 

    例えば、100MBのファイルを100個コピーすると、
    ダイアログが表示され、
    コピーの進捗を知ることができます。

    これをVB.NETで行いたいのですが
    どのようにすれば良いですか?

    https://dobon.net/vb/dotnet/file/filecopy.html

    My.Computer.FileSystemを使用すれば
    ダイアログは表示されるのですが
    ファイル全体ではなく
    ファイル一つずつの進捗状況が表示されてしまいます。

    一体どのようにすれば良いですか?

親記事 /過去ログ145より / 関連記事表示
削除チェック/

■85033  Re[1]: 複数ファイルをコピーする時に進捗ダイアログを表示する
□投稿者/ Azulean -(2017/09/05(Tue) 22:13:49)
    No85029 (カンガルー さん) に返信
    > ファイル全体ではなく
    > ファイル一つずつの進捗状況が表示されてしまいます。
    >
    > 一体どのようにすれば良いですか?

    どこまで予想がつきますか?
    なお、一撃でそこまでやってくれる便利なメソッドはないので、ファイルコピーや進捗表示含めて自作する必要がありますが、それでもチャレンジしたい状況ですか?

    ・バックグラウンドで処理を実行するということ
    ・コピー対象のファイルの列挙、コピー先の状況の確認が必要(上書き確認など)
    ・必要であれば自力でアニメーション表示
    ・ファイル数単位で進捗表示でよければ File.Copy、ダメなら自分で File を読み込んで書き込む処理の実装
    ・キャンセル対応
    ・エラー処理、エラーメッセージ表示

    仮に続行する場合でも全部のやり方を教えてくれでは、「質問」ではなく「依頼」になるのでどこかの業者にお願いしてください。
    それぞれのキーワードを元に調べ、試行錯誤した結果について、具体的な質問をするようにした方が答えを得られやすいでしょう。
記事No.85029 のレス /過去ログ145より / 関連記事表示
削除チェック/

■85034  Re[2]: 複数ファイルをコピーする時に進捗ダイアログを表示する
□投稿者/ カンガルー -(2017/09/06(Wed) 01:19:36)
    ご回答ありがとうございます。

    いまやりたいことは
    Windowsの標準機能を使いたい、だけなので
    VSを使えば簡単にできるのではないかと思って質問したのですが
    簡単にできるコマンドは存在せず
    自分で、同じような挙動をするコードを作るしかない、ということですか?
     
記事No.85029 のレス /過去ログ145より / 関連記事表示
削除チェック/

■85035  Re[3]: 複数ファイルをコピーする時に進捗ダイアログを表示する
□投稿者/ カンガルー -(2017/09/06(Wed) 01:22:50)
    すいません、ご回答に、そう書かれてありましたね。

    自分でコードの書き方が分からない部分は
    複数のファイルをコピー中に
    1つのファイルのバイトデータをコピーしている
    進捗状況を取得するというところだけです。

    そこだけで良いのでできればお教えいただけないでしょうか?

     
記事No.85029 のレス /過去ログ145より / 関連記事表示
削除チェック/

■85036  Re[4]: 複数ファイルをコピーする時に進捗ダイアログを表示する
□投稿者/ Azulean -(2017/09/06(Wed) 07:21:03)
    No85035 (カンガルー さん) に返信
    > 自分でコードの書き方が分からない部分は
    > 複数のファイルをコピー中に
    > 1つのファイルのバイトデータをコピーしている
    > 進捗状況を取得するというところだけです。
    >
    > そこだけで良いのでできればお教えいただけないでしょうか?

    1 つのファイルコピーに絞るのであれば、Win32API を使ってコールバック関数に進捗を通知してもらうようにすれば良いでしょうね。
    https://msdn.microsoft.com/ja-jp/library/windows/desktop/aa363852

    My.Computer.FileSystem ではどうしようもありませんので、ファイルを検索する、進捗ダイアログを作るあたりの自作とセットです。
記事No.85029 のレス /過去ログ145より / 関連記事表示
削除チェック/

■85037  Re[3]: 複数ファイルをコピーする時に進捗ダイアログを表示する
□投稿者/ とっちゃん -(2017/09/06(Wed) 11:05:23)
    No85034 (カンガルー さん) に返信
    > ご回答ありがとうございます。
    >
    > いまやりたいことは
    > Windowsの標準機能を使いたい、だけなので
    > VSを使えば簡単にできるのではないかと思って質問したのですが
    > 簡単にできるコマンドは存在せず
    > 自分で、同じような挙動をするコードを作るしかない、ということですか?
    >  

    Windowsの標準機能というよりは、エクスプローラの挙動と同じことができればよい
    ということですかね?

    .NET Framework から使うとなるといろいろ面倒なところはありますが(COM全般の問題)
    IFileOperation という COM Interface が、エクスプローラのファイル操作全般を扱う
    インターフェースとなっています。

    ざっくりですが

    http://d.hatena.ne.jp/Tan90909090/20160111/1452441478

    のブログで紹介されていたのでリンクを張っておきます。

    多分探せばほかにもあると思いますが、詳しく探してないのでわかりません。


    .NET Framework から COM インターフェースを利用するというのはそんなに単純な話ではないところもあるので
    これを簡単とみなすか?といわれるとかなり微妙ですが、自分でファイルをコピーするなどの
    実装は必要ないので、そういう意味ではだいぶ楽ではある。。。かもしれませんw

    なお、ごみ箱に移動の処理はこのインターフェースを使うことになります。
    ここだけは覚えておくとよいと思います。
    (System.IO.File.Delete などではごみ箱に移動させることはできません)
記事No.85029 のレス /過去ログ145より / 関連記事表示
削除チェック/

■85091  Re[4]: 複数ファイルをコピーする時に進捗ダイアログを表示する
□投稿者/ カンガルー -(2017/09/11(Mon) 11:44:39)

    No85037 (とっちゃん さん) に返信


    http://www.asahi-net.or.jp/~fq7y-krsk/vba_v1.2/Win32API_VBA/xSHFileOperation.html

    ありがとうございます。

    上記ページに書かれた方法でうまく実現することができました。

    ところで、一つ疑問なのですが、
    pFromに単一のファイルパスを指定すると、pToはファイルパスとして引数を受け取ります。
    一方で、vbNullcharでファイルパスを連結して
    複数ファイルパスをpFromに渡すと、
    pToはフォルダーパスとして引数を受け取ります。

    このように、コピー元のファイルパスの数によって
    コピー先のパスがファイルになったりフォルダーになったりして
    使いづらいので、コピー元が単一ファイルであっても
    コピー先がフォルダーになるようにして使いたいのですが
    そのようなことは可能でしょうか?

    FOF_MULTIDESTFILES
    を試してみましたが駄目でした。

    .pFrom = sPath & vbNullChar sPath & vbNullChar

    というようにして、
    同じファイルを二回コピーするようにすると
    確かに所望のことはできるのですが
    冗長的になってしまいます。

    良い方法があれば教えてください。


記事No.85029 のレス /過去ログ145より / 関連記事表示
削除チェック/

■85093  Re[5]: 複数ファイルをコピーする時に進捗ダイアログを表示する
□投稿者/ 魔界の仮面弁士 -(2017/09/11(Mon) 12:12:28)
    No85091 (カンガルー さん) に返信
    > コピー元が単一ファイルであっても
    > コピー先がフォルダーになるようにして使いたいのですが
    > そのようなことは可能でしょうか?

    pTo の指定がどうなっているか分かりませんが、
    コピー先を「末尾が \ で終わるフルパス」で指定したら
    フォルダーへのコピーになると思います。

    この場合、コピー先のフォルダーは事前に用意しておく必要がありますが。


    > http://www.asahi-net.or.jp/~fq7y-krsk/vba_v1.2/Win32API_VBA/xSHFileOperation.html
    > 上記ページに書かれた方法でうまく実現することができました。
    上記は VBA の場合ですよね。

    SHFILEOPSTRUCT 構造体のアライメントは、本来は 1 バイトパッキングです。
    提示 URL の VBA コードだと fFlags の後続メンバーの配置がずれますのでご注意ください。

    VB.NET に移植する場合は、StructLayoutAttribute で Pack:=1 を指定すればすむのですが、
    VBA(x86) は 4 バイト単位で配置される仕様なので…。
    http://www.gizcollabo.jp/vbtomo/log/archive/vbqanda_41630_0.html

    # そういえば、x64 版の VBA はどうなんだろう。
記事No.85029 のレス /過去ログ145より / 関連記事表示
削除チェック/

■85094  Re[6]: 複数ファイルをコピーする時に進捗ダイアログを表示する
□投稿者/ カンガルー -(2017/09/11(Mon) 12:20:53)

    No85093 (魔界の仮面弁士 さん) に返信

    ありがとうございます。

    \を付けることでうまくいきました。

    実際には、上記のVBAのコードを参考にしつつ
    VB.NETで書かれたコードを流用して使っているので問題は起きていないのですが

    > SHFILEOPSTRUCT 構造体のアライメントは、本来は 1 バイトパッキングです。
    > 提示 URL の VBA コードだと fFlags の後続メンバーの配置がずれますのでご注意ください。

    これってどういう意味ですか?


記事No.85029 のレス /過去ログ145より / 関連記事表示
削除チェック/

■85096  Re[7]: 複数ファイルをコピーする時に進捗ダイアログを表示する
□投稿者/ 魔界の仮面弁士 -(2017/09/11(Mon) 13:02:08)
    No85094 (カンガルー さん) に返信
    >>SHFILEOPSTRUCT 構造体のアライメントは、本来は 1 バイトパッキングです。
    >>提示 URL の VBA コードだと fFlags の後続メンバーの配置がずれますのでご注意ください。
    > これってどういう意味ですか?

    紹介した URL で解説していますが、ファイルコピーがユーザによってキャンセルされた場合、
    SHFILEOPSTRUCT の fAnyOperationsAborted メンバーに 1 がセットされる仕様なのです。
    (先のサンプルでは、キャンセルを判定するようなコードにはなっていないですけれどね)

    32bit環境においては、SHFILEOPSTRUCT 構造体のメモリ配置は、
     0x00-0x03 → HWND 型 hWnd
     0x04-0x07 → UINT 型 wFunc
     0x08-0x0B → PCZZTSTR 型 pFrom
     0x0C-0x0F → PCZZTSTR 型 pTo
     0x10-0x11 → FILEOP_FLAGS 型 fFlags
     0x12-0x15 → BOOL 型 fAnyOperationsAborted
     0x16-0x19 → LPVOID 型 hNameMappings
     0x1A-0x1D → PCTSTR 型 lpszProgressTitle
    と並んでいます。


    ところが VBA は、4バイト単位に再配置して呼び出す仕様です。

    0x00、0x04、0x08、0x0C というのは 4 バイト単位の位置に並んでいるので問題ないのですが、
    fAnyOperationsAborted が配置されているのは、「0x10-0x13 の後半」と「0x14-0x17 の前半」に
    またがるメモリ位置になっています。

    そこで VBA は、API の呼び出し時に自動的に 2 バイト分調整し、 No85091 の構造体を
     0x00-0x03 → Long 型 hWnd
     0x04-0x07 → Long 型 wFunc
     0x08-0x0B → String 型 pFrom
     0x0C-0x0F → String 型 pTo
     0x10-0x11 → Integer 型 fFlags
     0x12-0x13 → 【2 バイトのパディング】
     0x14-0x17 → Long 型 fAnyOperationsAborted
     0x18-0x1B → Long 型 hNameMappings
     0x1C-0x1F → String 型 lpszProgressTitle
    のメモリ配置に変換して渡すようになっています。


    ところが、API がキャンセル結果を書き込むのは
    0x12-0x15 のメモリ位置なので、結果を正しく受け取れなくなるわけです。

    受け取れないだけならまだ良いですが、ポインタである
    lpszProgressTitle に文字列を渡してから呼び出せば、
    クラッシュしてしまう可能性すらあるわけです。


    一方 VB.NET の場合は、StructLayoutAttibute 属性を付与することで、
    このアライメント調整を明示的に指定することができるようになっています。


    'SHFileOperationA を呼び出す場合は、CharSet.Ansi をセットします。
    'SHFileOperationW を呼び出す場合は、CharSet.Unicode をセットします。
    <StructLayout(LayoutKind.Sequential, CharSet:=CharSet.Unicode, Pack:=1)> _
    Public Structure SHFILEOPSTRUCT
      Public hwnd As IntPtr
      <MarshalAs(UnmanagedType.U4)> Public wFunc As Integer '(Enum FILEOP As Int32)
      <MarshalAs(UnmanagedType.LPWStr)> Public pFrom As String
      <MarshalAs(UnmanagedType.LPWStr)> Public pTo As String
      <MarshalAs(UnmanagedType.U2)> Public fFlags As Short '(Enum FILEOP_FLAGS As Int16)
      <MarshalAs(UnmanagedType.Bool)> Public fAnyOperationsAborted As Boolean
      Public hNameMappings As IntPtr
      <MarshalAs(UnmanagedType.LPWStr)> Public lpszProgressTitle As String
    End Structure
記事No.85029 のレス /過去ログ145より / 関連記事表示
削除チェック/

■85097  Re[8]: 複数ファイルをコピーする時に進捗ダイアログを表示する
□投稿者/ カンガルー -(2017/09/11(Mon) 13:20:28)
記事No.85029 のレス /過去ログ145より / 関連記事表示
削除チェック/

■85100  Re[9]: 複数ファイルをコピーする時に進捗ダイアログを表示する
□投稿者/ 魔界の仮面弁士 -(2017/09/11(Mon) 16:25:00)
    2017/09/11(Mon) 16:36:24 編集(投稿者)

    No85097 (カンガルー さん) に返信
    > よく内容が理解できませんでした。

    ざっくり言えば、「StructLayoutAttribute.Pack フィールドに 1 を指定するべき」ということです。

    そのための正しい宣言例は既に No85096 で示しております。ファイルの先頭に
    「Imports System.Runtime.InteropServices」を記述しておくことも忘れずに。


    実際、構造体のサイズを
    Dim sz As Integer = System.Runtime.InteropServices.Marshal.SizeOf(GetType(SHFILEOPSTRUCT))
    で調べてみると、2 バイトのパディングが入ることにより、
    No85096 の宣言が、x86ビルドで 30、x64 ビルドで 48 を返すのに対し、
    No85097 の宣言は、x86ビルドで 32、x64 ビルドで 50 になってしまいます。


    > 要はStructureのところの宣言の違いだけですよね?

    いえ。Pack 指定以外にも、Ansi/Unicode 指定や IntPtr の扱いなど、
    大切なことは他にもあります。


    問題となりそうな箇所は 3 つ。

    (1) Shift_JIS に無い文字、たとえば「立方メートル」記号を含んだファイル名を正しく処理できるか?
    (2) x86 だけでなく、x64 でも動作するコードになっているか?
    (3) fAnyOperationsAborted や lpszProgressTitle を利用できるような形になっているか?


    上記 3 点を満たせるかどうか、という点で考えてみると、
    No85097 の宣言では明らかに NG であると言えます。

    しかしながら、特定の条件下…具体的には、
     ・Shift_JIS 前提のファイルパスしか扱わない。
     ・x86 ビルドでコンパイルする。
     ・fAnyOperationsAborted以降のメンバーを読み書きしない。
    という前提を満たせる場合に限っては No85097 の間違った構造体宣言の
    ままであっても、一見、問題なく呼び出せてしまうかも知れません。
    (SHFileOperation をどのように宣言し、それをどのように
     呼び出しているのかにもよりますが)


    そうした状況を問題ないと捉えるか、問題ありと考えるかは、
    カンガルーさん自身の判断にお任せします。
記事No.85029 のレス /過去ログ145より / 関連記事表示
削除チェック/

■85103  Re[10]: 複数ファイルをコピーする時に進捗ダイアログを表示する
□投稿者/ カンガルー -(2017/09/11(Mon) 16:50:09)
    ありがとうございます。
    
    
    詳細な原理は理解できていませんが、
    とりあえず、
    No85096 で示してくださったStructureをコピーして使ってみました。
    
    しかし、この方法だとファイルがコピーされなくなりました。
    
    x86でコンパイルしており、ファイルパスは全て半角文字を使っています。
    
    コピー用のFunctionは以下の物を用いています。
    
    何が原因でしょうか?
    
    
    
    
        Private Declare Function SHFileOperation Lib "shell32.dll" Alias "SHFileOperationA" (ByRef lpFileOp As SHFILEOPSTRUCT) As Integer
    
    
        Public Function SH_Copy(ByVal sPath As String, ByVal dPath As String) As Integer
    
            Dim shf As SHFILEOPSTRUCT
    
            With shf
                .wFunc = FO_COPY
                .pFrom = sPath & vbNullChar
                .pTo = dPath & vbNullChar
                .fFlags = FOF_ALLOWUNDO Or FOF_NOCONFIRMATION Or FOF_NOCONFIRMMKDIR
                .lpszProgressTitle = "Sending " & sPath & " to " & dPath
            End With
    
            Return SHFileOperation(shf)
    
        End Function
    
    
    
記事No.85029 のレス /過去ログ145より / 関連記事表示
削除チェック/

■85105  Re[11]: 複数ファイルをコピーする時に進捗ダイアログを表示する
□投稿者/ とっちゃん -(2017/09/11(Mon) 17:02:13)
    No85103 (カンガルー さん) に返信
    > 何が原因でしょうか?
    >
    >
    >
    >
    > Private Declare Function SHFileOperation Lib "shell32.dll" Alias "SHFileOperationA" (ByRef lpFileOp As SHFILEOPSTRUCT) As Integer
    >
    ここですね。

    SHFileOperationA を指定しているので、文字コードはANSI形式が要求されます。
    .NET から使う場合、よっぽどの理由がない限りは、SHFileOperationW など、UNICODE形式の文字コードを要求するバージョンの
    APIを使うことをお勧めします。

記事No.85029 のレス /過去ログ145より / 関連記事表示
削除チェック/

■85107  Re[11]: 複数ファイルをコピーする時に進捗ダイアログを表示する
□投稿者/ 魔界の仮面弁士 -(2017/09/11(Mon) 17:23:03)
    2017/09/11(Mon) 17:36:22 編集(投稿者)

    No85103 (カンガルー さん) に返信
    > No85096 で示してくださったStructureをコピーして使ってみました。

    SHFILEOPSTRUCT を Structure で宣言する場合は、ByRef な引数で渡すようにし、
    SHFILEOPSTRUCT を Class で宣言する場合は、ByVal な引数で渡す必要があります。
    今回は前者を選択されたのですね。


    > Private Declare Function SHFileOperation Lib "shell32.dll" Alias "SHFileOperationA" (ByRef lpFileOp As SHFILEOPSTRUCT) As Integer

    No85096 に、
     'SHFileOperationA を呼び出す場合は、CharSet.Ansi をセットします。
     'SHFileOperationW を呼び出す場合は、CharSet.Unicode をセットします。
    と書いておいた筈ですが、そもそも読んですらもらえていないのかな…。orz

    〜A 系の関数に渡すのであれば、StructLayout での CharSet:= 指定を
    CharSet.Ansi に変更する必要があります。
    ただしこの場合、Shift_JIS 相当の文字しか扱えなくなります。


    Unicode の文字を使えるようにする場合は、構造体宣言の方を
    CharSet:=CharSet.Unicode としておいた上で、関数宣言の方を
     Private Declare Unicode Function SHFileOperation Lib "shell32" Alias "SHFileOperationW" (ByRef lpFileOp As SHFILEOPSTRUCT) As Integer
    もしくは
     <DllImport("shell32", SetLastError:=True, CharSet:=CharSet.Unicode)> _
     Private Shared Function SHFileOperation(ByRef lpFileOp As SHFILEOPSTRUCT) As Integer
     End Function
    のようにします。
    (後者を Module 内に書く場合は、"Private Shared Function" を "Private Function" にしてください)


    どちらの記述か迷った場合は No85105 でとっちゃんさんが書かれたように、
    基本的には Unicode 版の組み合わせを選択するべきです。


    --- 以下蛇足 ---
    古い VBA コードは、Win98 世代の古い OS 向けのアプリを作っていた頃の名残で
    SHFileOperationA などの 〜A 系 API を呼びだしているサンプルが非常に多いのですが、今となっては
    SHFileOperationW などの 〜W 系 API への呼び出しに改めるのが望ましいです。

    Win98 世代も意識した書きかたを考えるなら、下記のように
    書き分けも必要ですが、今となってはその必要も無いでしょうし。
    (下記は別の API での例ですが、一応参考情報として)
    http://www5b.biglobe.ne.jp/~yone-ken/VBNET/Reference/ref2_GetPrivateProfileString.html
    http://www5b.biglobe.ne.jp/~yone-ken/VBNET/special/sp06_GetPrivateProfileString.html
記事No.85029 のレス /過去ログ145より / 関連記事表示
削除チェック/

■85196  Re[12]: 複数ファイルをコピーする時に進捗ダイアログを表示する
□投稿者/ カンガルー -(2017/09/19(Tue) 11:15:38)
    皆様ご回答ありがとうございます。

    細かいところはこれから勉強したいと思いますが
    とりあえずうまくいきました。
     
記事No.85029 のレス / END /過去ログ145より / 関連記事表示
削除チェック/



<< 0 >>

パスワード/

- Child Tree -