Please help with SHBrowseForFolder API in .Net

M

Martin K

I have been struggling with this all day and I know I am doing
something wrong. This API code works in VB 6..and I am having a
difficult time migrating it to .Net. Basically I need to do a call
back procedure within my SHBrowseForFolder API code (setting an
initial DIR). My code continues to die on the lpIDList =
SHBrowseForFolder(tBrowseInfo) line. I get the same error each time:

"Object reference not set to an instance of an object"

Now, I have noticed that unlike the VB 6 version, my AddressOf Call
back procedure never runs..this is probably why I am getting the
error. I know that i need to use a Delegate function, but my attempts
to do this have failed. I have attached my current code..this runs in
VB 6 with a slight modification (adding a function to get the pointer
to the AddressOf function, something .Net does not take). I have read
on-line that all I need to do is assign the delegate type to my
lpfnCallback variable..but nothings seems to work :(. Please help if
you can.

Code**********************************************************************

Option Explicit On
Imports System
Imports System.Runtime.InteropServices


Module SetDir

Private Declare Function SHBrowseForFolder Lib "shell32" _
(ByVal lpbi As BROWSEINFO) As Long


Private Declare Function SHGetPathFromIDList Lib "shell32" _
(ByVal pidList As Long, ByVal lpBuffer As String) As Long

Private Declare Sub CoTaskMemFree Lib "ole32.dll" (ByVal pv As
Long)

Private Declare Function SendMessage Lib "user32" _
Alias "SendMessageA" _
(ByVal hWnd As Long, _
ByVal wMsg As Long, _
ByVal wParam As Long, _
ByVal lParam As Long) As Long

Private Declare Function SHSimpleIDListFromPath Lib "shell32"
Alias "#162" _
(ByVal szPath As String) As
String

Private Const BIF_BROWSEFORPRINTER As Long = &H2000
Private Const BIF_RETURNONLYFSDIRS As Long = 1
Private Const BIF_BROWSEINCLUDEFILES = &H4000
Private Const BIF_DONTGOBELOWDOMAIN As Long = 2
Private Const BFFM_INITIALIZED As Long = 1
Private Const MAX_PATH As Long = 260
Private Const WM_USER As Long = &H400
Private Const BFFM_SETSTATUSTEXTA As Long = (WM_USER + 100)
Private Const BFFM_SETSELECTIONA As Long = (WM_USER + 102)
Private Const BFFM_SETSELECTIONW As Long = (WM_USER + 103)
Private Const BFFM_SETSTATUSTEXTW As Long = (WM_USER + 104)

Public Function BrowseCallBackProc(ByVal hWnd As Long, _
ByVal uMsg As Long, _
ByVal lParam As Long, _
ByVal lpData As Long) As Long

Select Case uMsg
Case BFFM_INITIALIZED
Call SendMessage(hWnd, BFFM_SETSELECTIONA, False,
lpData)
Case Else
End Select
End Function
Delegate Function CallBack(ByVal hwnd As Long, ByVal uMsg As Long,
_
ByVal lParam As Long, ByVal lpData As Long) As Long

Private Structure BROWSEINFO
Public hWndOwner As Long
Public pIDLRoot As Long
Public pszDisplayName As Long
Public lpszTitle As String
Public ulFlags As Long
Public lpfnCallback As CallBack '***-trying to assign
callback type
Public lParam As Long
Public iImage As Long
End Structure

Private Function GetPIDLFromPath(ByVal sPath As String) As String

GetPIDLFromPath = SHSimpleIDListFromPath(StrConv(sPath,
VbStrConv.LowerCase))

End Function

Public Function BrowseDirectory(ByVal InitialDir As String, ByVal
hWnd As Long) As String
Dim lpIDList As Long
Dim sBuffer As String
Dim szTitle As String
Dim tBrowseInfo As BROWSEINFO = New BROWSEINFO

szTitle = "Select a file to load"
With tBrowseInfo
.hWndOwner = hWnd
.pIDLRoot = 0
.lpszTitle = szTitle
.ulFlags = BIF_BROWSEINCLUDEFILES + BIF_DONTGOBELOWDOMAIN
.lpfnCallback = AddressOf BrowseCallBackProc '**DOESN'T
WORK!
.lParam = GetPIDLFromPath(InitialDir)
End With

lpIDList = SHBrowseForFolder(tBrowseInfo) '***-AND I DIE
HERE!

If (lpIDList) Then
sBuffer = Space(MAX_PATH)
SHGetPathFromIDList(lpIDList, sBuffer)
sBuffer = Left(sBuffer, InStr(sBuffer, vbNullChar) - 1)
BrowseDirectory = sBuffer
CoTaskMemFree(lpIDList)
Else
BrowseDirectory = InitialDir
End If

CoTaskMemFree(tBrowseInfo.lParam)
End Function

End Module

*******************************************************************

If I am missing something obvious, I apologize, I am new to .Net.

Martin
 
G

Gary Milton

What version of VS.NET are you running? VS.NET 2003 has a built-in
FolderBrowserDialog control which is far easier to use than trying to
p/invoke the Win32 API's (it is available from the toolbox). Unfortunately
though VS.NET 2002 does not have this control but there are some code
examples to help you invoke one...

http://www.vbaccelerator.com/home/NET/Code/Libraries/Shell_Projects/Folder_Browser/article.asp
http://www.codeproject.com/cs/miscctrl/folderbrowser.asp
http://www.netomatix.com/FolderBrowser.aspx

(you may need to port the code from C# to VB.NET where applicable)

HTH,
Gary
 
C

Cor

Hi Martin,

Why not try it this way

Open a new windows application project
In the toolbox rightclick and select add/Remove items
In the customize toolbox select Com and in that the Microsoft Webbrowser

When that is in the toolbox drag it to your form
Drag also a button to your form.
Then this code and you have a mini Webbrowser.
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As
System.EventArgs) Handles Button1.Click
Me.AxWebBrowser1.Navigate2("www.google.com")
End Sub
///
I hope this helps?

Cor
 
B

Bill McCarthy

hi Martin,

A couple of things you need to fix first : Long in .NET is 64 bit, not 32 bit.
So I'd say that everywhere you have Long you need to change that to Integer, or
as I do, declare it as Int32 instead. I use Int32 so as I know that it is
correctly updated code ;)

Also, handles, such as HWnd, are probably best to declare as IntPtr.

A thing on delegates is that you should also be aware of, is you need to keep a
reference to the actual delegate instance, otherwise it may be Garbage
Collected, even though the unmanaged code has a reference to it. So store it in
a field, or similar, before passing it out to a windows API call.


Bill.
 
M

Martin K

Thanks for everyone's input. I can't use the built in browseForFolder
control in .Net..it does not provide the flexibility that I need. I
was able to get my code working..thanks. I had to restructure it
within a Public call, but all is well :).
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top