tagCANDY CGI VBレスキュー(花ちゃん)の Visual Basic 6.0用 掲示板 [ツリー表示へ]   [Home]
一括表示(VB6.0)
タイトルポータブルデバイスのフォルダパス取得
記事No15986
投稿日: 2014/11/07(Fri) 21:48
投稿者NANA
お世話になります。

この掲示板を初めて利用させていただきます。

現在、ダイアログでスマートフォンのポータブルデバイスからフォルダをコピーする処理を作成しておりますが、選択したフォルダパスの取得が出来ず悩んでおります。


下記のコードで、選択したフォルダパスは取得できるのですが
階層を深くするとエラーが表示され選択できません。
【エラー内容】フォルダーを使用できません。別のフォルダーを選択してください。

Set Shell = CreateObject("Shell.Application")
Set f = Shell.BrowseForFolder(0, "フォルダを選んでください", &H200, "")

また、コモンダイアログでも試してみましたが、パスの取得は出来ませんでした。
何か良い方法がございましたら、ご教授いただけないでしょうか?
よろしくお願いいたします。


利用環境:windows7 vb6.0

[ツリー表示へ]
タイトルRe: ポータブルデバイスのフォルダパス取得
記事No15987
投稿日: 2014/11/08(Sat) 21:30
投稿者花ちゃん
> 階層を深くするとエラーが表示され選択できません。
> 【エラー内容】フォルダーを使用できません。別のフォルダーを選択してください。

何階層以上になると取得できないのでしょうか?
(試した限りでは、20 階層でも取得できましたが)

パス文字列長の制限(255? 文字以上)が超えているのではないのですか?
それとも特殊なフォルダーとかの場合だけとかではないですか?

もう少し詳しい状況を書いて頂かないとこれ以上の判断は...。
エラー内容と質問内容が合っていないような?
実際にエラーが発生して止まってしまったところのコードを投稿して下さい。

[ツリー表示へ]
タイトルRe^2: ポータブルデバイスのフォルダパス取得
記事No15988
投稿日: 2014/11/10(Mon) 09:35
投稿者NANA
花ちゃん 様


ご連絡ありがとうございます。

連絡が遅くなり申し訳ありません。


スマートフォンをパソコンで接続するとMTPデバイスとなります。

>何階層以上になると取得できないのでしょうか?
>(試した限りでは、20 階層でも取得できましたが)

取得できる場合:コンピューター\SC-02C\Phone\○○○
取得できない場合:コンピューター\SC-02C\Phone\○○○\■■■

4階層以上になると取得出来ておりません。


>パス文字列長の制限(255? 文字以上)が超えているのではないのですか?

255文字以上になっていました。310文字です。
パスの文字列長の255文字を超えると駄目なのでしょうか?

>それとも特殊なフォルダーとかの場合だけとかではないですか?

MTPデバイスのフォルダの4階層以上で取得した時だけエラーとなります。
また仮想ディレクトリ扱いになっており、フォルダパスはIDで表示されております。


>実際にエラーが発生して止まってしまったところのコード

Dim Shell As Object
Dim f As Object

Set Shell = CreateObject("Shell.Application")
Set f = Shell.BrowseForFolder(0, "フォルダを選んでください", &H200, "")  ←ここでエラーになります。
MsgBox f.Items.Item.Path


よろしくお願いいたします。

[ツリー表示へ]
タイトルRe^3: ポータブルデバイスのフォルダパス取得
記事No15989
投稿日: 2014/11/10(Mon) 10:29
投稿者花ちゃん
> 取得できる場合:コンピューター\SC-02C\Phone\○○○
> 取得できない場合:コンピューター\SC-02C\Phone\○○○\■■■
>
> 4階層以上になると取得出来ておりません。

階層 に問題があるのではなく、そのフォルダーに問題があるのではないのですか?
例えば、エクスプローラーで同様に操作できますか?
(そのフォルダー内へファイルを保存したりとか)

> 255文字以上になっていました。310文字です。
> パスの文字列長の255文字を超えると駄目なのでしょうか?
一応、制限はあるようなので?

> MTPデバイスのフォルダの4階層以上で取得した時だけエラーとなります。
> また仮想ディレクトリ扱いになっており、フォルダパスはIDで表示されております。
詳しくは知りませんが、下記のような条件が必要だったりとか? パスワードのようなセキュリティがかかっているとか?
http://heaya.blog52.fc2.com/blog-entry-65.html

[ツリー表示へ]
タイトルRe^4: ポータブルデバイスのフォルダパス取得
記事No15990
投稿日: 2014/11/10(Mon) 11:24
投稿者NANA
花ちゃん 様


返信ありがとうございます。


>階層 に問題があるのではなく、そのフォルダーに問題があるのではないのですか?
>例えば、エクスプローラーで同様に操作できますか?
>(そのフォルダー内へファイルを保存したりとか)

確認した限り、4階層以上のフォルダ全て、ダイアログ上から選択すると
エラーとなります。

エクスプローラーから同様に操作は可能です。
コピー、削除、上書き保存、ファイル新規作成、閲覧は可能でした。


>一応、制限はあるようなので?

そうなんですか。
255文字超えているから、エラーになっているんですかね?


>詳しくは知りませんが、下記のような条件が必要だったりとか? パスワードのようなセキュリティがかかっているとか?

パソコンとスマートフォンは正常に認識して動作しております。
デバイスマネージャからも警告マークは表示されておりません。


よろしくおねがいいたします。

[ツリー表示へ]
タイトルRe^5: ポータブルデバイスのフォルダパス取得
記事No15991
投稿日: 2014/11/10(Mon) 12:00
投稿者花ちゃん
> 確認した限り、4階層以上のフォルダ全て、ダイアログ上から選択すると
> エラーとなります。
それならば、目的のフォルダーを2階層とかになるようにコピーしたら取得できるという事でしょうか?

> そうなんですか。
> 255文字超えているから、エラーになっているんですかね?
それを実際の環境で確認して下さい。
そのフォルダーをコピーしてフォルダー名を変更して確認すればできるかと思いますが。

> コピー、削除、上書き保存、ファイル新規作成、閲覧は可能でした。
それができるのなら、問題がどこにあるのか実際の環境で確認できるはずですが。
コンピューター\SC-02C\Phone\ab\cd\ef\ のようなフォルダーを作成した場合は取得できるかどうかとか

[ツリー表示へ]
タイトルRe^6: ポータブルデバイスのフォルダパス取得
記事No15992
投稿日: 2014/11/10(Mon) 12:58
投稿者NANA
花ちゃん 様

返信ありがとうございます。


>それならば、目的のフォルダーを2階層とかになるようにコピーしたら取得できるという事でしょうか?

はい、ダイアログから対象フォルダ選択して、OKボタンを押すと取得出来ております。


>コンピューター\SC-02C\Phone\ab\cd\ef\ のようなフォルダーを作成した場合は取得できるかどうかとか

取得できませんでした。


コンピューター\SC-02C\Phone\ab の場合は下記のようにパス取得出来ております。
(パスの文字列長:232文字)

::{20D04FE0-3AEA-1069-A2D8-08002B30309D}\\\?\usb#vid_0000&pid_0000&ms_comp_mtp&samsung_android#
0&00000000&0&0000#{00000000-0000-0000-0000-000000000000}\SID-{00000,0000000000000000,00000000000}\
{00DF0090-00D2-00A3-9000-D70064006300}

コンピューター\SC-02C\Phone\ab\cd の場合は、パスの文字列長が更に39文字追加されるので、合計271文字になります。

やはり、パスの文字列長の制限エラーが原因のようですね。



ダイアログで、MTPデバイスの4階層以上のフォルダパスを取得することは出来ないのでしょうか?

[ツリー表示へ]
タイトルRe^7: ポータブルデバイスのフォルダパス取得
記事No15993
投稿日: 2014/11/10(Mon) 14:05
投稿者花ちゃん
> やはり、パスの文字列長の制限エラーが原因のようですね。
> ダイアログで、MTPデバイスの4階層以上のフォルダパスを取得することは出来ないのでしょうか?

4階層以上 にこだわっておられますが、パスの文字列長が制限を超えているのが原因では?
階層に制限があるとは思えませんが。
階層に問題があるのか? パス文字列長に問題があるのか? フォルダーのセキュリティ上に問題があるのかを
切り分けて頂いたのと違ったのですか。

パスの文字列長が原因なら、コンピューター\SC-02C\Phone の部分を短く読む方法を探さないと。
(エクスプローラー上なら自動的に短いパス名に変更してくれますが)

VB6.0 を使っているのなら、DirListBox コントロールを使った場合、表示やフォルダーを取得する事は
できませんか?
Dir1.Path = "コンピューター\SC-02C\" のように途中のフォルダーからでも

[ツリー表示へ]
タイトルRe^8: ポータブルデバイスのフォルダパス取得
記事No15994
投稿日: 2014/11/10(Mon) 14:51
投稿者NANA
花ちゃん 様

返信ありがとうございます。

>4階層以上 にこだわっておられますが、パスの文字列長が制限を超えているのが原因では?
>階層に制限があるとは思えませんが。
>階層に問題があるのか? パス文字列長に問題があるのか? フォルダーのセキュリティ上に問題があるのかを
>切り分けて頂いたのと違ったのですか。

ある事情で、ディレクトリ構成を変更できないので、そのままの構成で取得できる方法を考えておりました。
今回の原因は、おっしゃる通りパスの文字列長が原因ということが分かりましたが、
また別のダイアログを使えば、取得できるという回答がほしかった次第で聞きました。

>パスの文字列長が原因なら、コンピューター\SC-02C\Phone の部分を短く読む方法を探さないと。
>(エクスプローラー上なら自動的に短いパス名に変更してくれますが)

取得するパスの文字列長を短く読む方法があるかどうか調べてみます。

>VB6.0 を使っているのなら、DirListBox コントロールを使った場合、表示やフォルダーを取得する事は
>できませんか?
>Dir1.Path = "コンピューター\SC-02C\" のように途中のフォルダーからでも

DirListBoxコントロールは使ったことがないため、こちらも含め調べてみます。
SC-02C\Phone の部分は固定ではく動的に変わります。(
スマートフォン1機種ではない為)
動的に対応できるやり方も、再度調べてみます。


ありがとうございました。

[ツリー表示へ]
タイトルRe^9: ポータブルデバイスのフォルダパス取得
記事No15995
投稿日: 2014/11/10(Mon) 16:47
投稿者花ちゃん
Windows 7 上で開発されているのなら念のために、IDE 上からだけでなく EXE にしてから
動作確認をするようにして下さい。

一部の機能が IDE 上と EXE 上では違う場合がありますので。

[ツリー表示へ]
タイトルRe^10: ポータブルデバイスのフォルダパス取得
記事No15996
投稿日: 2014/11/10(Mon) 18:32
投稿者NANA
花ちゃん 様

> Windows 7 上で開発されているのなら念のために、IDE 上からだけでなく EXE にしてから
> 動作確認をするようにして下さい。
>
> 一部の機能が IDE 上と EXE 上では違う場合がありますので。

了解しました。EXEで動作確認いたします。

先ほど、DirListBoxで下記のように試すと「パスが見つかりませんでした。」
とエラーになりました。

Private Sub Dir1_Change()
 Dir1.Path = "コンピューター\SC-02C\"
End Sub


また調べている最中、下記のサイトを見つけ、エクスプローラを
起動してからフォルダを選択したパス取得は出来ました。
(パスの文字列長:310文字)

ただ、エクスプローラの場合、選択するまでは問題ないのですが
右クリックしてコピー、切り取り等が出来てしまうので
これを無効にする方法ってないでしょうか?
もし、無効にできるのであれば採用したいと思っております。

http://hanatyan.sakura.ne.jp/patio/read.cgi?mode=view2&f=214&no=0

よろしくおねがいいたします。

[ツリー表示へ]
タイトルRe^11: ポータブルデバイスのフォルダパス取得
記事No15997
投稿日: 2014/11/10(Mon) 20:27
投稿者花ちゃん
確認ですが、エクスプローラーでフォルダーを見た場合は、どのようなフォルダー名に
なっているのでしょうか?
>コンピューター\SC-02C\Phone\ab の場合は下記のようにパス取得出来ております。
と投稿されたパスが文字化けしているのではありませんか?
SC-02C\Phone\ab のパスが見当たりませんが。

文字化けしているのなら、Win32API の SHBrowseForFolderW (Unicode対応のフォルダー選択ダイアログ) の方を
使えば取得できるかも知れません。
http://hpcgi1.nifty.com/MADIA/VBBBS/wwwlng.cgi?print+200604/06040042.txt

[ツリー表示へ]
タイトルRe^12: ポータブルデバイスのフォルダパス取得
記事No15998
投稿日: 2014/11/10(Mon) 21:21
投稿者NANA
花ちゃん 様


>確認ですが、エクスプローラーでフォルダーを見た場合は、どのようなフォルダー名に
>なっているのでしょうか?

【コンピューター\SC-02C\Phone\ab\cd\ef】の場合
エクスプローラーのアドレスバーの表示は、
コンピューター\SC-02C\Phone\ab\cd\efになっており、
取得した文字列をDebug.Printすると下記のようになっております。
(パスの文字列長:310文字)

::{20D04FE0-3AEA-1069-A2D8-08002B30309D}\\\?\usb#vid_0000&pid_0000&ms_comp_mtp&samsung_android#
0&00000000&0&0000#{00000000-0000-0000-0000-000000000000}\SID-{00000,0000000000000000,00000000000}\
{00DF0090-00D2-00A3-9000-D70064006300}\{00DF00F4-00D2-00A3-9000-D7009300C600}\{010E00F4-0137-0109-9000-D7009300C600}


>>コンピューター\SC-02C\Phone\ab の場合は下記のようにパス取得出来ております。
>と投稿されたパスが文字化けしているのではありませんか?
>SC-02C\Phone\ab のパスが見当たりませんが。

確信はありませんが、恐らく、MTPデバイスの場合、仮想扱いとなり
上記のようなフォルダパスになるかと思われます。

::{20D04FE0-3AEA-1069-A2D8-08002B30309D} ⇒ コンピューター名

usb#vid_0000&pid_0000&ms_comp_mtp&samsung_android#
0&00000000&0&0000#{00000000-0000-0000-0000-000000000000 ⇒ SC-02C

SID-{00000,0000000000000000,00000000000} ⇒ phone

{00DF0090-00D2-00A3-9000-D70064006300} ⇒ ab


また、上記のパス(310文字)をコピーして、エクスプローラーのアドレスバーに
張り付けてEnterキーを押すとMTPデバイス内のフォルダを開くことが出来ます。


>文字化けしているのなら、Win32API の SHBrowseForFolderW (Unicode対応のフォルダー選択ダイアログ) の方を
>使えば取得できるかも知れません。

明日、確認させてください。すみません。


よろしくお願いいたします。

[ツリー表示へ]
タイトルRe^13: ポータブルデバイスのフォルダパス取得
記事No16000
投稿日: 2014/11/11(Tue) 11:45
投稿者NANA
花ちゃん 様


>文字化けしているのなら、Win32API の SHBrowseForFolderW (Unicode対応のフォルダー選択ダイアログ) の方を
>使えば取得できるかも知れません。

教えていただいたURLを参考にして、試しにC:\Testを選択すると
パス取得は出来ますがMTPデバイス内のフォルダ全てパス取得は
出来ませんでした。(値は無し)

よろしくおねがいいたします。

[ツリー表示へ]
タイトルRe^12: ポータブルデバイスのフォルダパス取得
記事No15999
投稿日: 2014/11/10(Mon) 22:06
投稿者魔界の仮面弁士
現状のエラーは、MAX_PATH の上限に引っかかっているのでは無いでしょうか。
内部で SHGetPathFromIDList API が呼ばれているのかも知れませんけど。

相手が「仮想フォルダー」として扱われるものであるならば、
パス文字列に変換せず、SHBrowseForFolder API から
PIDL のまま扱ってみては如何でしょうか。

このあたりの解説が参考になるかもしれません。(未検証)
http://pg-torch-ic.jugem.jp/?eid=31

[ツリー表示へ]
タイトルRe^13: ポータブルデバイスのフォルダパス取得
記事No16001
投稿日: 2014/11/11(Tue) 11:52
投稿者NANA
魔界の仮面弁士 様

ご連絡ありがとうございます。

MTPデバイス内のPIDよりパスを取得することは
出来ませんでした。(値は無し)

よろしくおねがいいたします。

'標準モジュール
************************************************
    'フォルダ名最大
    Private Const MAX_PATH  As Long = 256
    
    'フォルダ選択ダイアログを表示
    Private Declare Function SHBrowseForFolder Lib "shell32" (lpbi As BROWSEINFO) As Long
    
    '上記関数で取得したポインタを元にフォルダを取得
    Private Declare Function SHGetPathFromIDList Lib "shell32" (ByVal pidl As Long, ByVal pszPath As String) As Long

    'SH〜で取得したメモリブロックを開放する
    Private Declare Sub CoTaskMemFree Lib "ole32" (ByVal pidl As Long)
    
    'デスクトップハンドルを取得する
    Private Declare Function GetDesktopWindow Lib "USER32" () As Long

    'Root定数
    'デスクトップ
    Private Const CSIDL_DESKTOP As Long = &H0&

    'Flags定数
    'フォルダのみ選択可能
    Private Const BIF_RETURNONLYFSDIRS As Long = &H1&

    'ブラウザ情報構造体
    Private Type BROWSEINFO
        hWndOwner       As Long
        pidlRoot        As Long
        pszDisplayName  As String
        lpszTitle       As String
        ulFlags         As Long
        lpfn            As Long
        lParam          As String
        iImage          As Long
    End Type

' フォルダー選択ダイアログを表示する。
'   strCaption ダイアログのキャプション
'   lngOwnerHwnd  ダイアログのオーナーウィンドウ。
'   lngRoot ルートフォルダ    CSIDL*** 定数を使用する。
'   lngFlags
'       BIF_xxx の定数の組み合わせを指定。
'       省略時はフォルダーのみを選択。
'   strParam
'       デフォルトのフォルダー名。
'       省略時はマイコンピューターやルートに指定したフォルダ。
Public Function selectFolder( _
    Optional ByRef strCaption As String = vbNullString, _
    Optional ByVal lngOwnerHwnd As Long = 0, _
    Optional ByVal lngRoot As Long = CSIDL_DESKTOP, _
    Optional ByVal lngFlags As Long = BIF_RETURNONLYFSDIRS, _
    Optional ByRef strParam As String = vbNullString) As String


On Error GoTo ErrorHandler

    Dim typBinfo     As BROWSEINFO   'フォルダ情報構造体
    Dim lngpid        As Long
    Dim strPath     As String

    '親Windowが指定されていなければデスクトップを親Windowにする
    If lngOwnerHwnd = 0 Then
        lngOwnerHwnd = GetDesktopWindow()
    End If

    'バッファ設定
    strPath = String$(MAX_PATH, vbNullChar)

    'BROWSEINFO 構造体設定
    With typBinfo
        .hWndOwner = lngOwnerHwnd
        .pidlRoot = lngRoot
        .pszDisplayName = strPath
        .lpszTitle = strCaption & vbNullChar
        .ulFlags = 0    'この箇所を0にしないとMTPデバイスが選択できない

        'デフォルトフォルダが指定されていたらコールバック関数を使用する
        If Len(strParam) > 0 Then
            .lpfn = GetAddressOF(AddressOf BForFolderCallbackProc)
            .lParam = strParam & vbNullChar
        End If
    End With

    ' フォルダー選択ダイアログを表示
    lngpid = SHBrowseForFolder(typBinfo)

    'コンピュータ名のみ選択する場合
    If typBinfo.ulFlags And BIF_BROWSEFORCOMPUTER Then
        strPath = typBinfo.pszDisplayName
        '不要文字列を削除する
        strPath = Left$(strPath, InStr(strPath, vbNullChar) - 1)

    'フォルダ名やコンピュータ名取得
    Else
        'キャンセルが押された場合
        If lngpid = 0 Then
            strPath = vbNullString
        'OKが押された場合
        Else

            'pidよりパスを取得する
            If SHGetPathFromIDList(lngpid, strPath) = 0 Then
                strPath = vbNullString
            Else
                ' Null切捨て
                strPath = Left$(strPath, InStr(strPath, vbNullChar) - 1&)
            End If
        End If
    End If

    'ITEMIDLIST解放
    Call CoTaskMemFree(lngpid)

    '戻値
    selectFolder = strPath

    Exit Function
ErrorHandler:
    Call MsgBox(Err.Description, vbCritical)
End Function

' 長文になるためコールバック関数は省かせていただきます。
************************************************
Private Sub Command1_Click()
    MsgBox selectFolder("aaaaa", 0, CSIDL_DESKTOP, 1, "")
End Sub

よろしくおねがいいたします。

[ツリー表示へ]
タイトルRe^14: ポータブルデバイスのフォルダパス取得
記事No16004
投稿日: 2014/11/11(Tue) 14:37
投稿者魔界の仮面弁士
> MTPデバイス内のPIDよりパスを取得することは
> 出来ませんでした。(値は無し)

や、パス文字列に変換するのではなく、終始 PID のまま取り扱う、という意味です。

[ツリー表示へ]
タイトルRe^15: ポータブルデバイスのフォルダパス取得
記事No16006
投稿日: 2014/11/11(Tue) 15:27
投稿者NANA
魔界の仮面弁士 様


返信ありがとうございます。


> や、パス文字列に変換するのではなく、終始 PID のまま取り扱う、という意味です。

勘違いしておりました。すみません。

参考URLを拝見しましたが、内容が難しいです。
(自作関数を作成するのかな?)
知識不足ですみません。


こちらでも調べてみますが、APIダイアログから取得したPID(Long型)を
パス文字列に変換せずに、PIDを利用してフォルダコピーが出来る
VB6.0のサンプル的なコードを頂くことは出来ないでしょうか?


よろしくおねがいいたします。

[ツリー表示へ]
タイトルRe^16: ポータブルデバイスのフォルダパス取得
記事No16017
投稿日: 2014/11/14(Fri) 09:19
投稿者K.J.K.
# かなり久々に書き込み

> > や、パス文字列に変換するのではなく、終始 PID のまま取り扱う、という意味です。

フルパスに相当する Item ID List への Pointer だから、PIDL かな。

> こちらでも調べてみますが、APIダイアログから取得したPID(Long型)を
> パス文字列に変換せずに、PIDを利用してフォルダコピーが出来る
> VB6.0のサンプル的なコードを頂くことは出来ないでしょうか?

もし『文字列の長さの問題だけである』のならば、結構前に作ってけど本人が中身を
忘れていたサンプルですが、
http://www1.koalanet.ne.jp/akiya/vbtaste/vbp/FldrDlg.lzh
で、デスクトップフォルダを根(ルート)とした一意(ユニーク)なParse可能な名前の
取得を行っています。
# 今、Windows8.1環境で動かしてみたらラベルの文字化けがヒドいので
# いろいろと修正する必要はあるでしょうが。

ですが、ProgID:"Shell.Application" の BrowseForFolder メソッドが値を戻そうとする
段階でエラーが発生しているとなると、長さの問題ではないような気もします。

[ツリー表示へ]