エクスプローラのコピー、切り取りを判定したい。

解決


いか  2003-08-16 20:18:03  No: 108127

エクスプローラなどで、ファイル、フォルダを切り取り、貼り付けるようなことをVBで行いたいと思うのですが、

VBアプリ単体なら、できるのですが、エクスプローラと自アプリ間で切り取り、貼り付けを行いたいと考えています。以下の処理ができればと考えているのですが。

1)クリックボードからのデータの取得。
VBのクリップボードメソッドでは、取得できなかったのですが?
エクスプローラ上で切り取り、コピーは、単純にパスを覚えているだけのような気がしますが。

2)エクスプローラ上で切り取りをしたのか、コピーしたのかの判定


魔界の仮面弁士  2003-08-17 06:39:31  No: 108128

> VBのクリップボードメソッドでは、取得できなかったのですが?

VB.NETですか? ならばこんな感じで。

Dim DataObject As System.Windows.Forms.IDataObject
DataObject = Clipboard.GetDataObject()

Dim DropEffect As Object = DataObject.GetData("Preferred DropEffect")
If TypeOf DropEffect Is System.IO.MemoryStream Then
  Dim Stm As System.IO.MemoryStream = DirectCast(DropEffect, System.IO.MemoryStream)
  Dim Effect As Integer = BitConverter.ToInt32(Stm.ToArray(), 0)

  Const DROPEFFECT_NONE As Integer = 0
  Const DROPEFFECT_COPY As Integer = 1
  Const DROPEFFECT_MOVE As Integer = 2
  Const DROPEFFECT_LINK As Integer = 4

  If (Effect And DROPEFFECT_COPY) <> 0 Then
    Trace.WriteLine("コピー")
  End If
  If (Effect And DROPEFFECT_MOVE) <> 0 Then
    Trace.WriteLine("切り取り")
  End If
  If (Effect And DROPEFFECT_LINK) <> 0 Then
    Trace.WriteLine("ショートカット")
  End If
End If

Dim Files As Object = DataObject.GetData(DataFormats.FileDrop)
If TypeOf Files Is String() Then
  Dim X As String
  For Each X In DirectCast(Files, String())
    Trace.WriteLine(X)
  Next
End If

VB6以下の場合は、Clipboardオブジェクトからは取得できません。
クリップボードにあるかどうかの確認だけならば、
   Const CF_HDROP = 15
   If Clipboard.GetFormat(15) Then
などで行えますが、どうしてもファイル名を取得したいなら、
クリップボード系のAPIを使う必要があります。

ただし、『FolderItemVerbオブジェクト』を使えば、
「コピー」「切り取り」「貼り付け」を実行する事はできますので、
VB6でも、APIを使わずに済ます事は可能です。

> エクスプローラ上で切り取り、コピーは、単純にパスを覚えているだけのような気がしますが。

ファイル名の一覧は、CF_HDROP形式のクリップボードデータとして保持されています。
また、これらとは別に、切り取りかコピーか(そしてショートカットを作成可能か)の情報として、
"Preferred DropEffect"というデータも同時に保持されています。


いか  2003-08-17 17:28:15  No: 108129

たいへんありがとうございます。

もしよろしけらば、VB6を使っているので、そのへんのさわりだけでもお教えて頂きたいのですが。


魔界の仮面弁士  2003-08-18 13:23:40  No: 108130

私の回答では、『クリップボード系のAPI』を使う方法と、
『FolderItemVerbオブジェクト』を使う方法の2案を出しましたが、
この場合の「そのへんのさわり」とは、どちらの事でしょうか?(^^;

とりあえず、APIで取得するなら、

1. 『"Preferred DropEffect"形式のデータ』を取得する。
 (RegisterClipboardFormat APIを使って、この識別値を得ます)
  この形式のデータは、切り取りかコピーかを示すビットフラグです。
    &H1 が立っていれば、コピー
    &H2 が立っていれば、移動
    &H4 が立っていれば、ショートカットを作成可能

2. 『CF_HDROP形式のデータ』を取得する。
 (識別値の定義は、 Const CF_HDROP = 15 のようになります)
  この形式のデータは、ファイル名の一覧を示す文字列です。

の2手順にて、必要な情報を得る事ができますので、あとは、
SHFileOperation APIか、もしくはVBのファイル操作ステートメント等で
実際に、それらのファイル郡を操作する事になるでしょう。
(クリップボードAPIの操作方法に付いては、ご自身で調べてみて下さい)

一方、FolderItemVerbオブジェクトを使った方法は、要するに
  『  フォルダを右クリックした時のメニュー項目にある
      [コピー]や[貼り付け]の動作を、VBから指示する。  』
という処理です。

この方法の場合は、クリップボードの内容をVB側で確認する事はありません。
それゆえ、実際にどのファイルが移動(あるいは複写)されるのかまでは
VB側では把握しません(把握する必要がありません)。

FolderItemVerbを使う場合は、[Microsoft Shell Controls And Automation]を参照設定した後に、

Dim Path As String
Dim oShell As Shell32.Shell
Dim oFItem As Shell32.FolderItem
Dim oFVerb As Shell32.FolderItemVerb

Path = "C:\test\"

Set oShell = CreateObject("Shell.Application")
Set oFItem = oShell.NameSpace(CVar(Path)).Items().Item()
For Each oFVerb In oFItem.Verbs
    If oFVerb.Name Like "貼り付け*" Then
        oFVerb.DoIt
        Exit For
    End If
Next
Set oFItem = Nothing
Set oShell = Nothing

などのようなコードで、貼り付け動作を行います。

なお上記は、参照設定無しでも動作させられますが、その場合は、
  Dim oShell As Shell32.Shell
  Dim oFItem As Shell32.FolderItem
  Dim oFVerb As Shell32.FolderItemVerb
の部分を、全て  As Object  で宣言するようにしてください。


いか  2003-08-22 02:09:24  No: 108131

ありがとうございます。

まずAPIの方なのですが、

1. 『"Preferred DropEffect"形式のデータ』を取得する。
 (RegisterClipboardFormat APIを使って、この識別値を得ます)
  この形式のデータは、切り取りかコピーかを示すビットフラグです。
    &H1 が立っていれば、コピー
    &H2 が立っていれば、移動
    &H4 が立っていれば、ショートカットを作成可能

dim kekka as long
kekka = RegisterClipboardFormat("Preferred DropEffect")
のようにやってみたのですが、
コピー、切り取りをエクスプローラでやって戻り値をみてみたのですが、
49324が返ってきて、変化ありませんでした。
たぶん、やり方がおかしいと思いますが。

FolderItemVerbを使ったサンプルでやってみたところうまく動きました。
ステップして追っていったところ、確かに右クリックメニューの文字が列挙されていました。
この場合に、複数のパス、ファイル名をコピー、切り取りということは、可能なのでしょうか?


魔界の仮面弁士  2003-08-22 02:26:45  No: 108132

> kekka = RegisterClipboardFormat("Preferred DropEffect")
> のようにやってみたのですが、
> コピー、切り取りをエクスプローラでやって戻り値をみてみたのですが、
> 49324が返ってきて、変化ありませんでした。

RegisterClipboardFormatが返すのは、データ形式を表す識別番号です。
クリップボードの内容を示しているのではありません。(^_^;)

その、49324(別の番号になる可能性もあります)という値を使って、
クリップボードから、情報を取得するのです。

VB6のClipboardオブジェクトの場合も、クリップボードから情報を
(GetTextやGetDataで)取得するときには、識別値——例えば、
vbCFText(=&H1)、vbCFEMetafile(=&HE)、vbCFRTF(=&HBF01)など——を
指定しますよね。APIの場合もそれと同じ事です。

> この場合に、複数のパス、ファイル名をコピー、切り取りということは、可能なのでしょうか?
可能ですよ。詳細はPlatform SDKで調べて、ご自身で試して見てください。


魔界の仮面弁士  2003-08-22 06:47:34  No: 108133

>> この場合に、複数のパス、ファイル名をコピー、切り取りということは、可能なのでしょうか?
> 可能ですよ。詳細はPlatform SDKで調べて、ご自身で試して見てください。

って、肝心な『手順』を書かないと、調べようが無いですよね。。。(^^;

複数のパスを指示したい場合は、ShellFolderViewオブジェクトを利用します。
ShellFolderViewのSelectItemメソッドで、サブフォルダやファイルを
選択状態にできます。また、選択状態にしたファイル/フォルダは、
SelectedItemsメソッドにて、FolderItemsコレクションとして取得できます。
FolderItemsとして取得したあとの処理は、先と同様、FolderItemVerbメソッドで処理すればOKです。

なお、これらのオブジェクトに関しては、下記を参照してください。
[Shell Objects for Scripting and Microsoft Visual Basic]
http://msdn.microsoft.com/library/en-us/shellcc/platform/shell/reference/objects/objects.asp


いか  2003-08-30 00:26:33  No: 108134

わざわざありがとうございます。
NSDNをみながらやってみたのですが、

    Dim Path(2) As String
    Dim lop As Integer
    
    Dim oShell As Shell32.Shell
    Dim oFItem As Shell32.FolderItem
    Dim oFItems As Shell32.FolderItems
    Dim oFVerb As Shell32.FolderItemVerb
    Dim oFView As Shell32.ShellFolderView
    
    Path(0) = "C:\test"
    Path(1) = "C:\test2"
    
    Set oShell = CreateObject("Shell.Application")
 
    For lop = 0 To 1
        Set oFItem = oShell.NameSpace(Path(lop)).Items.Item
        oFView.SelectItem oFItem, 1
    Next
    
    Set oFItems = oFView.SelectedItems
    
    For Each oFVerb In oFItems.Verbs
        If oFVerb.Name Like "貼り付け*" Then
            oFVerb.DoIt
            Exit For
        End If
    Next
    
    Set oFItem = Nothing
    Set oShell = Nothing

 oFView.SelectItem oFItem, 1の行で

実行時エラー'91':
オブジェクト変数またはWithブロック変数が設定されていません。

がでてさきに進みません。
SelectItemの引数が違うと思うのですが、

ShellFolderView.SelectItem(vItem, dwFlags)
Parameters

vItem Required. 
The FolderItem object for which the selection state will be set. 

VItemは、どのようにして取得するのでしょうか?
FolderItemでは、ない?


魔界の仮面弁士  2003-08-30 01:11:35  No: 108135

>  oFView.SelectItem oFItem, 1の行で
> 実行時エラー'91':
> オブジェクト変数またはWithブロック変数が設定されていません。

オブジェクト変数oFViewが設定されていない(Nothing状態)だからです。


いか  2003-08-30 01:46:06  No: 108136

>オブジェクト変数oFViewが設定されていない(Nothing状態)だからです。

たいへんありがとうございます。
MSDNをもう一度みてみたいと思います。


いか  2003-08-30 02:06:21  No: 108137

みてみたのですが、わかりませんでした。
これ以上教えていただくのも悪いので、実現をあきらめます。


いか  2003-09-04 19:42:52  No: 108138

>オブジェクト変数oFViewが設定されていない(Nothing状態)だからです。

このオブジェクトは、どのスクリプトで取得するのでしょうか?


魔界の仮面弁士  2003-09-04 21:51:36  No: 108139

エクスプローラあるいはInternet Explorer等を起動して、
そこにフォルダを表示させてください。例えば、こんな感じ。

Private Sub Command1_Click()
    Dim W       As Object   'As InternetExplorer
    Dim oFView  As Object   'As ShellFolderView
    Dim oFItems As Object   'As FolderItems
    Dim oFItem  As Object   'As FolderItem

    
    Set W = CreateObject("InternetExplorer.Application")
    W.Navigate2 "C:\Program Files\"
    W.Visible = True    '表示/非表示の切り替え
    
    Do
       DoEvents
    Loop Until W.busy = 4
    
    Set oFView = W.Document
    Set oFItems = oFView.SelectedItems
    Set oFItem = oFView.FocusedItem
    Debug.Print "oFView : " & TypeName(oFView)
    Debug.Print "oFItems: " & TypeName(oFItems)
    Debug.Print "oFItem : " & TypeName(oFItem)
    
    Debug.Print "このフォルダの項目数", oFView.Folder.Items().Count
    Debug.Print "現在選択されている項目数", oFItems.Count
    If oFItem Is Nothing Then
        Debug.Print "フォーカスがありません。"
    Else
        Debug.Print oFItem.Name
    End If

    Set oFItem = Nothing
    Set oFItems = Nothing
    Set oFView = Nothing

    W.Quit  '終了
    Set F = Nothing
End Sub


魔界の仮面弁士  2003-09-04 21:54:54  No: 108140

———訂正。m(_ _)m

>    Loop Until W.busy = 4
これは、 
     Loop While W.busy
もしくは、
     Loop Until W.readystate = 4
に。

>    Set F = Nothing
これは、Set W = Nothing で。


※返信する前に利用規約をご確認ください。

※Google reCAPTCHA認証からCloudflare Turnstile認証へ変更しました。






  このエントリーをはてなブックマークに追加