ダイアログからコンピュータ名のみを取得するには?

解決


ハイライト  2005-12-01 14:15:42  No: 93027

SHBrowseForFolderのAPIを使って「フォルダ選択のダイアログ」を実現してます。このダイアログでコンピュータ名(ネットワーク上)を選択してもパス名(\\PC名)を取得することができません。「ulFlags」の定数を調べ、試してみましたがどれも該当しないようです。ご存知の方教えていただけますでしょうか。


もげ  2005-12-01 14:38:27  No: 93028

必要なフラグとしては、
Public Const BIF_BROWSEFORCOMPUTER = &H1000 'ネットワークコンピュータのみ選択可能
です。

また、
SHGetPathFromIDList()をお使いであれば、これはファイルシステム上にあるファイルじゃないと失敗すると思われます。
コンピュータ名は、
Type BROWSEINFO
    hwndOwner As Long '呼び出し元ウィンドウハンドル
    pidlRoot As Long 'ルートフォルダのID
    pszDisplayName As String '選択したフォルダの表示名(c:\msdev\bin なら bin)
    lpszTitle As String '表示するメッセージ
    ulFlags As Integer 'フラグ
    lpfn As Long 'CallbackProcを指定する。0でデフォルトを使う
    lParam As Long 'Callback関数に引数を渡すときに使用する
    iImage As Integer '選択されたフォルダのアイコンイメージ番号
End Type
の、pszDisplayName から直接値を取得してみてください。
(文字列の後ろにNull文字があるので、これは除去してください)


ハイライト  2005-12-01 16:22:15  No: 93029

ご回答ありがとうございます。

Public Function FolderDlg(nHwnd As Long) As String

Dim BI As BROWSEINFO
Dim Path As String
Dim Ret As Long
Dim Temp As String

   With BI
     .hwndOwner = nHwnd
     '.ulFlags = BIF_BROWSEFORCOMPUTER  'コメントアウト
   End With
    
   'バッファを確保
   Path = String(MAX_PATH, vbNullChar)
   '「フォルダを参照」ダイアログを表示
   Ret = SHBrowseForFolder(BI)

   '「pszDisplayName」の調査
   'Temp = BI.pszDisplayName
   'Form1.Caption = Temp

   Call SHGetPathFromIDList(Ret, Path)
   'パスを格納  ※「\\PCName\FolderName」
   FolderDlg = Path
 
 End Function

のようになり、「BIF_BROWSEFORCOMPUTER」を指定しないで、ネットワークコンピュータのリソースを選択した場合はLeft関数などで取得することはできましたが、「BIF_BROWSEFORCOMPUTER」を指定した場合、パスは空白でした。

そして、教えていただいた「pszDisplayName」を上記の場所で調べてみましたが、いずれの場合も空白でした。

http://forums.belution.com/ja/vc/000/018/88.shtml
上記の同じような質問を見つけたのですが、解決には至りませんでした。上記コードのどの部分が間違っているのでしょうか?


030  2005-12-01 17:34:20  No: 93030

http://forums.belution.com/ja/vc/000/018/88.shtml
上記リンク先に「pszDisplayNameに領域を与えたら」と書いてありますね。
あなたのコードではそれがされていません。
コンピュータ名だけ欲しいのであれば
>  Call SHGetPathFromIDList(Ret, Path)
>   'パスを格納  ※「\\PCName\FolderName」
>   FolderDlg = Path
の処理はなくてもいいです。

参考までに例を書いときます。
Public Type BROWSEINFO
   hwndOwner As Long
  pidlRoot As Long
  pszDisplayName As Long '<---アドレスを与えるためLongに変更しています
  lpszTitle As String
  ulFlags As Long
  lpfn As Long
  lParam As Long
  iImage As Long
End Type

以下、定数、APIの宣言は省略しています

  Dim BI As BROWSEINFO
  Dim Ret As Long
  Dim bytName(MAX_COMPUTERNAME_LENGTH-1) As Byte
  
  BI.pszDisplayName = GlobalAlloc(GPTR, MAX_COMPUTERNAME_LENGTH)  'コンピュータ名を入れる領域を確保
 
  BI.ulFlags = BIF_BROWSEFORCOMPUTER
  Ret = SHBrowseForFolder(BI)

  If Ret <> 0 Then
    CopyMemory bytName(0), ByVal BI.pszDisplayName,MAX_COMPUTERNAME_LENGTH
    Debug.Print StrConv(bytName, vbUnicode)
  End If
  
  GlobalFree BI.pszDisplayName


もげ  2005-12-01 17:47:35  No: 93031

当方ではBIF_BROWSEFORCOMPUTERの有無にかかわらず、
pszDisplayNameには何かしらの値が入ってきます。
(VB6.0SP6+Win2000SP4)

>Ret = SHBrowseForFolder(BI)
のところでブレークポイントを設定してステップ実行し、
コンピュータ名を指定した直後に、
ウォッチウィンドウでBI.pszDisplayNameを確認してみてください。
見えますか?

もしくは、
>Ret = SHBrowseForFolder(BI)
の次の行に
    Debug.Print BI.pszDisplayName
を追加してみてください。
これで表示できないでしょうか?

または、貴殿の環境で、
ネット上のSHBrowseForFolderのサンプル...例えば、
http://homepage2.nifty.com/Dee/
  →サンプル集
    →フォルダ選択ダイアログ表示2
http://homepage2.nifty.com/Dee/vb/soft/browsefolder2.lzh
等の動きはどうでしょうか?


030  2005-12-01 17:56:32  No: 93032

スレ主とは別に話して申し訳ないですが。

もとのソースでも

   'バッファを確保
   Path = String(MAX_PATH, vbNullChar)
   With BI
     .hwndOwner = nHwnd
     .ulFlags = BIF_BROWSEFORCOMPUTER  'コメントアウト
     .pszDisplayName = Path   '<-------------これ
   End With
    
確保した文字列を構造体に渡していればちゃんと動くみたいですね。
勉強になりました。


もげ  2005-12-02 09:47:43  No: 93033

>確保した文字列を構造体に渡していればちゃんと動くみたいですね。

そうですね。
SHGetPathFromIDList のパスを受け取るために
>'バッファを確保
>Path = String(MAX_PATH, vbNullChar)
>Call SHGetPathFromIDList(Ret, Path)
とやっているのと同じことなんです。

Declare Function SHGetPathFromIDList Lib "shell32" (ByVal pidl As Long, ByVal pszPath As String) As Long
ですね。

今回たまたま使用したサンプルでそうなっていなかったというのが悲劇だったのでしょう。
SHBrowseForFolderのサンプルはネット上にはいくつも見つかりますが、
たまにそういうのもありますからね。

#本当は元質問者殿にそれをデバッグして確かめていただけたらべストだったのですが
#今回は030殿が率先してその収穫を得られたということで良しとしますか


ハイライト  2005-12-02 16:10:24  No: 93034

'宣言部
'「フォルダを参照」ダイアログ関数
Public Function BrowseForFolder(nHwnd As Long) As String

Dim lpBrowseInfo As BROWSEINFO  'BROWSEINFOユーザー定義
Dim pszPath As String           'パス
Dim pidl As Long                'ID
Dim intStart As Integer         '文字列の位置

    'バッファ設定
    pszPath = String$(BUFF, vbNullChar)
    'BROWSEINFOユーザー定義の設定
    With lpBrowseInfo
        .hwndOwner = nHwnd          'ウインドウハンドルの設定
        .pszDisplayName = pszPath   'バッファの設定
    End With
    '「フォルダを参照」ダイアログの表示
    pidl = SHBrowseForFolder(lpBrowseInfo)
    'キャンセルの場合
    If pidl = 0 Then
        Exit Function
    'OKの場合
    Else
        'パスを取得
        Call SHGetPathFromIDList(pidl, pszPath)
        'コンピュータ名を選択した場合
        If SHGetPathFromIDList(pidl, pszPath) = 0 Then
            '選択したアイテムの表示名の格納
            pszPath = lpBrowseInfo.pszDisplayName
            '不要な文字列の削除
            pszPath = Left$(pszPath, InStr(pszPath, vbNullChar) - 1)
            'バックスラッシュの付加
            pszPath = "\\" & pszPath
            'パスの格納
            BrowseForFolder = pszPath
        'フォルダを選択した場合
        Else
            'パスの格納
            BrowseForFolder = pszPath
        End If
    End If

 End Function

'フォーム部
Private Sub Command1_Click()

Dim strPath As String   'パス

    'パスの取得
    strPath = BrowseForFolder(Form1.hWnd)
    'パスの表示
    Text1.Text = strPath

End Sub

上記のコードにて解決しました。
030さんにいただいた「.pszDisplayName = Path」がヒントとなりました。反省点は、
①pszDisplayNameにフルパスが格納されているものと思い込んでいたこと
②SHGetPathFromIDListの返り値を見逃していたこと
③「.pszDisplayName = pszPath」についてのバッファを与えるという意味を理解していなかったこと
だと思います。
気づいた点はBIF_BROWSEFORCOMPUTERを指定しなくても取得はできるということです。
皆様ご迷惑をおかけしました。ありがとうございます。


もげ  2005-12-02 17:21:10  No: 93035

BIF_BROWSEFORCOMPUTERは
ネットワーク上のコンピュータ以下の共有フォルダを展開するか否かのフラグなので、
コンピュータ名のみを取得するつもりなら付けといたほうがいいかというように
当方が意図を勘違いしていたようです。すみません。


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

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







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