GetOpenFilename in VB.Net

LianaEnt

Member
Joined
Sep 15, 2003
Messages
12
Does anyone have the GetOpenFilename API code for opening custom dialog boxes (in particular with the ability to save the Views - Thumbnails, Tiles, Icons) in VB.Net, that actually works?

Ive found code in C++ that I dont understand, in CE.Net that doesnt translate, Ive found VB6 code and Access code that works but I have not been able to translate successfully yet. MSDN doesnt seem to have any examples in VB.Net, Ive searched Google, this forum, and others. Occasionally I see someone who cant get multiple file selection or some aspect of it to work, but theres never any code along with it.

Please help! VB.Net!!!

Thanks,
Larry
 
I got the dialogbox to open...

But I keep getting a null reference when I try to use the OFNHookProc. Without the hook procedure, this is really no better than the standard OpenFileDialog box.

Im using for the delegate:
Delegate Function OFNHookProc(ByVal hwnd As IntPtr, ByVal uMsg As Integer, ByVal wParam As Long, ByVal lParam As Long) As Integer

and setting the OpenFileName hook paramter to:
ofn.hook = New OFNHookProc(AddressOf OFNHookProcSub)

Ive tried different variations of the parameter types such as Long, etc. In every case, when the OFNHookProcSub function fires, the handle and message being fed to it are meaningless - the message is none of the standard hook messages such as WM_NOTIFY (78) or WM_INITDIALOG (272). Its integer value is 48.

Again, Ive seen hook examples in other languages, but nothing in VB.Net!

If anyone wants to see the code to get the dialogbox to just open, let me know!

Thanks,
Larry
 
Update - would you believe Im "this" close?

Heres all the code for the entire class that I have so far (in 2 posts)...

Imports System
Imports System.Text
Imports Microsoft.VisualBasic
Imports System.Runtime.InteropServices

Public Class OpenFilename
Inherits CommonDialog

Declare a bunch of APIs, hoping some will work...
Declare Auto Function GetOpenFileName Lib "Comdlg32.dll" (<[In](), Out()> ByVal ofn As OpenFileName) As Boolean
Declare Function GetParent Lib "user32" (ByVal hwnd As IntPtr) As IntPtr
Declare Function SendMessage Lib "user32" Alias "SendMessageA" (ByVal hwnd As IntPtr, ByVal wMsg As Long, ByVal wParam As Long, ByRef lParam As String) As Long
Declare Function SendMessage Lib "user32" Alias "SendMessageA" (ByVal hwnd As IntPtr, ByVal wMsg As Long, ByVal wParam As Long, ByVal lParam As Long) As Long
Declare Function SendMessage Lib "user32" Alias "SendMessageA" (ByVal hwnd As IntPtr, ByVal wMsg As Long, ByVal wParam As Long, ByVal lParam As IntPtr) As Long
Declare Function FindWindowEx Lib "user32" Alias "FindWindowExA" (ByVal hWndParent As IntPtr, ByVal hWndChildAfter As IntPtr, ByVal lpClassName As String, ByVal lpWindowName As String) As IntPtr
Declare Function SetWindowText Lib "user32" Alias "SetWindowTextA" (ByVal hwnd As IntPtr, ByVal lpString As String) As Long
Declare Auto Function SetDlgItemText Lib "user32" (ByVal hDlg As IntPtr, ByVal nIDDlgItem As Long, ByVal lpString As String) As Long

Declare the Hook delegate so we can "hook" to it later.
Delegate Function OFNHookProc(ByVal hwnd As IntPtr, ByVal msg As Integer, ByVal wParam As IntPtr, ByVal lParam As IntPtr) As IntPtr
If you dont persist the hook procedure, it will be GCd before the call gets to it.
Private HookProcSub As OFNHookProc = AddressOf HookProc
Set the initial view - Thumbnail, Icons, Details, etc. (yeah, right!)
Private lngInitialView As Long

Set all possible constants Ive found so far.
Hook constants
Const WM_SETFOCUS = &H7
Const WM_INITDIALOG = &H110
Const WM_LBUTTONDOWN = &H201
Const WM_RBUTTONDOWN = &H204
Const WM_MOVE = &H3
Const WM_COMMAND = &H111
Const WM_NOTIFY As Long = &H4E&

Flags for OpenFileName
Const OFN_ALLOWMULTISELECT As Long = &H200
Const OFN_CREATEPROMPT As Long = &H2000
Const OFN_ENABLEHOOK As Long = &H20
Const OFN_ENABLETEMPLATE As Long = &H40
Const OFN_ENABLETEMPLATEHANDLE As Long = &H80
Const OFN_EXPLORER As Long = &H80000
Const OFN_EXTENSIONDIFFERENT As Long = &H400
Const OFN_FILEMUSTEXIST As Long = &H1000
Const OFN_HIDEREADONLY As Long = &H4
Const OFN_LONGNAMES As Long = &H200000
Const OFN_NOCHANGEDIR As Long = &H8
Const OFN_NODEREFERENCELINKS As Long = &H100000
Const OFN_NOLONGNAMES As Long = &H40000
Const OFN_NONETWORKBUTTON As Long = &H20000
Const OFN_NOREADONLYRETURN As Long = &H8000&
Const OFN_NOTESTFILECREATE As Long = &H10000
Const OFN_NOVALIDATE As Long = &H100
Const OFN_OVERWRITEPROMPT As Long = &H2
Const OFN_PATHMUSTEXIST As Long = &H800
Const OFN_READONLY As Long = &H1
Const OFN_SHAREAWARE As Long = &H4000
Const OFN_SHAREFALLTHROUGH As Long = 2
Const OFN_SHAREWARN As Long = 0
Const OFN_SHARENOWARN As Long = 1
Const OFN_SHOWHELP As Long = &H10
Const OFS_MAXPATHNAME As Long = 260

ToolbarWindow32 buttons. Ive actually only found the first two, and Im guessing at the FileView button.
Const TB_BTN_UPONELEVEL = 40961
Const TB_BTN_NEWFOLDER = 40962
Const TB_BTN_FILEVIEW = 40963
Const BM_SETSTATE = &HF3

Constants on the dialog window.
Const IDOK As Long = 1
Const IDCANCEL As Long = 2
Const IDFILEOFTYPETEXT As Long = &H441
Const IDFILENAMETEXT As Long = &H442
Const IDLOOKINTEXT As Long = &H443
Const WM_USER = &H400
Const CDM_FIRST = (WM_USER + 100)
Const CDM_SETCONTROLTEXT As Long = CDM_FIRST + &H4
Const CDM_HIDECONTROL As Long = (CDM_FIRST + &H5)
Const EM_GETTEXTRANGE = (WM_USER + 75)
Const TB_GETBUTTON = (WM_USER + 23)

View constants.
Public Const SHVIEW_ICON As Long = &H7029
Public Const SHVIEW_LIST As Long = &H702B
Public Const SHVIEW_REPORT As Long = &H702C
Public Const SHVIEW_THUMBNAIL As Long = &H702D
Public Const SHVIEW_TILE As Long = &H702E

Dont know what this is for, but it looked good
Public Structure TBBUTTON
Dim iBitmap As Integer
Dim idCommand As Integer
Dim fsState As Byte
Dim fsStyle As Byte
Dim bReserved1 As Byte
Dim bReserved2 As Byte
Dim dwData As Integer
Dim iString As Integer
End Structure

Dont know what this is for, but it looked good
Public Structure LHDR
Public hwndFrom As IntPtr
Public idFrom As Integer
Public code As Integer
End Structure

Dont know what this is for, but it looked good
Private Structure TEXTRANGE
Dim cpMin As Long
Dim cpMax As Long
Dim lpstrText As Long
End Structure

(rest of code to follow)
 
Update - continued

Public Property SetInitialView() As Long
Get
Return lngInitialView
End Get
Set(ByVal Value As Long)
lngInitialView = Value
End Set
End Property

Hook procedure - uh huh...
<System.Security.Permissions.PermissionSetAttribute(System.Security.Permissions.SecurityAction.Demand, Name:="FullTrust")> _
Protected Overrides Function HookProc(ByVal hWnd As IntPtr, ByVal msg As Integer, ByVal wParam As IntPtr, ByVal lParam As IntPtr) As IntPtr
Dim hWndParent As IntPtr
Dim hwndLv As IntPtr
Dim hwndButton As IntPtr
Static bLvSetupDone As Boolean
Dim lngRetVal As Long

Evaluates the message parameter to determine the user action.

Select Case msg

Case WM_INITDIALOG
bLvSetupDone = False
MessageBox.Show("The WM_INITDIALOG message was received.")
Case WM_SETFOCUS
MessageBox.Show("The WM_SETFOCUS message was received.")
Case WM_LBUTTONDOWN
MessageBox.Show("The WM_LBUTTONDOWN message was received.")
Case WM_RBUTTONDOWN
MessageBox.Show("The WM_RBUTTONDOWN message was received.")
Case WM_MOVE
MessageBox.Show("The WM_MOVE message was received.")
Case WM_NOTIFY
If Not bLvSetupDone Then
MessageBox.Show("The WM_NOTIFY message was received.")
hWndParent = GetParent(hWnd)

SetWindowText(hWndParent, "Were ALL bozos on this bus!")
This actually works, so I know at least Im pointing at the main dialog form.

hwndLv = FindWindowEx(hWndParent, hwndLv, "ToolbarWindow32", vbNullChar)
This returns a handle, but not sure what to do with it. I dont know how to access the buttons in ToolbarWindow32.

Dim lhdr As LHDR = CType(Marshal.PtrToStructure(lParam, GetType(LHDR)), LHDR)
This returns something, but not sure what to do with it.
lngRetVal = SendMessage(hwndLv, CDM_HIDECONTROL, TB_BTN_UPONELEVEL, 0)
This certainly doesnt work - trying to hide the UpOneLevel button.

Dim strLookIn As String = "Find it in:" & ChrW(0)
lngRetVal = SendMessage(hWndParent, CDM_SETCONTROLTEXT, IDLOOKINTEXT, strLookIn)
Attempt to change the text "Look In:" to "Find it in:" doesnt work.
bLvSetupDone = True
End If
End Select

Always call the base class hook procedure.
Return MyBase.HookProc(hWnd, msg, wParam, lParam)

End Function

Public Overrides Sub Reset()

End Sub

This is whats called from the front end button click -
Dim OpenFile As New OpenFilename
OpenFile.ShowDialog()

Protected Overrides Function RunDialog(ByVal hwndOwner As System.IntPtr) As Boolean
Dim ofn As New OpenFilename

With ofn
.nStructSize = Marshal.SizeOf(ofn)
.ptrOwner = hwndOwner
.sFilter = "Picture Files" & ChrW(0) & "*.jpg" & ChrW(0) & "All files" & ChrW(0) & "*.*" & ChrW(0)
.sFile = New String(New Char(256) {})
.nMaxFile = .sFile.Length
.sFileTitle = New String(New Char(64) {})
.nMaxFileTitle = .sFileTitle.Length
.sTitle = "Open file..."
.sDefExt = "jpg"
.nFlags = OFN_EXPLORER Or _
OFN_ENABLEHOOK Or _
OFN_LONGNAMES Or _
OFN_NODEREFERENCELINKS Or _
OFN_CREATEPROMPT Or _
OFN_ALLOWMULTISELECT
.ofnHook = HookProcSub
End With

If GetOpenFileName(ofn) Then
MessageBox.Show(ofn.sFile)
End If

End Function

Even with persisting the hook, I still got a null reference unless I set up the OpenFileName like this:
<StructLayout(LayoutKind.Sequential, CharSet:=CharSet.Auto)> _
Public Class OpenFileName
Public nStructSize As Integer = 0
Public ptrOwner As IntPtr = IntPtr.Zero
Public hInstance As Integer = 0
<MarshalAs(UnmanagedType.LPTStr)> Public sFilter As String = Nothing
<MarshalAs(UnmanagedType.LPTStr)> Public sCustomFilter As String = Nothing
Public nMaxCustFilter As Integer = 0
Public nFilterIndex As Integer = 0
<MarshalAs(UnmanagedType.LPTStr)> Public sFile As String = Nothing
Public nMaxFile As Integer = 0
<MarshalAs(UnmanagedType.LPTStr)> Public sFileTitle As String = Nothing
Public nMaxFileTitle As Integer = 0
<MarshalAs(UnmanagedType.LPTStr)> Public sInitialDir As String = Nothing
<MarshalAs(UnmanagedType.LPTStr)> Public sTitle As String = Nothing
Public nFlags As Integer = 0
Public nFileOffset As Short = 0
Public nFileExt As Short = 0
Public sDefExt As String = Nothing
Public ptrCustData As IntPtr = IntPtr.Zero
Public ofnHook As OFNHookProc IntPtr = IntPtr.Zero
<MarshalAs(UnmanagedType.LPTStr)> Public sTemplateName As String = Nothing
Public ptrReserved As IntPtr = IntPtr.Zero
Public nReserved As Integer = 0
Public nFlagsEx As Integer = 0
End Class OpenFileName

End Class
 
Have you tried changing the As Long bits in the API declarations to As Integer? Under .Net Integers are now 32bits and Longs 64bits; if these declares have come from a VB6 sample then that could be a source of potential problems.
 
Well, that does help a little...

Now at least I can "sorta" set the text in the buttons and main window, however, the text always looks like a little black square box with two white vertical lines in it. I tried null terminating the text strings. Maybe the text strings have to be put in a buffer or something.

I still cant access the buttons in the ToolbarWindow32.

Thanks so far PlausiblyDamp! And yes, almost everything Ive found is non-VB.Net, so its up for interpretation.

:)
 
Back
Top