SHBrowseForFolderのAPIを使って「フォルダ選択のダイアログ」を実現してます。このダイアログでコンピュータ名(ネットワーク上)を選択してもパス名(\\PC名)を取得することができません。「ulFlags」の定数を調べ、試してみましたがどれも該当しないようです。ご存知の方教えていただけますでしょうか。
必要なフラグとしては、
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文字があるので、これは除去してください)
ご回答ありがとうございます。
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
上記の同じような質問を見つけたのですが、解決には至りませんでした。上記コードのどの部分が間違っているのでしょうか?
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
当方では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
等の動きはどうでしょうか?
スレ主とは別に話して申し訳ないですが。
もとのソースでも
'バッファを確保
Path = String(MAX_PATH, vbNullChar)
With BI
.hwndOwner = nHwnd
.ulFlags = BIF_BROWSEFORCOMPUTER 'コメントアウト
.pszDisplayName = Path '<-------------これ
End With
確保した文字列を構造体に渡していればちゃんと動くみたいですね。
勉強になりました。
>確保した文字列を構造体に渡していればちゃんと動くみたいですね。
そうですね。
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殿が率先してその収穫を得られたということで良しとしますか
'宣言部
'「フォルダを参照」ダイアログ関数
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を指定しなくても取得はできるということです。
皆様ご迷惑をおかけしました。ありがとうございます。
BIF_BROWSEFORCOMPUTERは
ネットワーク上のコンピュータ以下の共有フォルダを展開するか否かのフラグなので、
コンピュータ名のみを取得するつもりなら付けといたほうがいいかというように
当方が意図を勘違いしていたようです。すみません。
| ツイート |
|