Hàm API getopenfilename ! (3 người xem)

Liên hệ QC

Người dùng đang xem chủ đề này

hungpecc1

Thành viên gắn bó
Tham gia
24/8/12
Bài viết
1,709
Được thích
2,304
Giới tính
Nam
Do một số ứng dụng khác không có hàm getopenfilename ---> em dùng hàm Api để tạo hộp thoại open file !

Tuy nhiên kết quả tên file lại khác với tên file khi sử dụng gàm getopenfilename của excel ( chênh nhau 1 ký tự)---> em tìm hiểu mãi mà chưa ra được nguyên nhân, mong các anh chị trên diễn đàn giải thích đoạn code của em sai chỗ nào !!

code của em như sau:
anh (chị) paste code sau vào 1 module --> chạy sub main, ??? không hiểu sao cùng 1 file mà strcomp lại ra kết quả -1
Mã:
Private Declare Function GetOpenFileName Lib "comdlg32.dll" Alias _
                        "GetOpenFileNameA" (pOpenfilename As OPENFILENAME) As Long
Private Type OPENFILENAME
    lStructSize As Long          'The size of this struct (Use the Len function)
    hwndOwner As Long            'The hWnd of the owner window. The dialog will be modal to this window
    hInstance As Long            'The instance of the calling thread. You can use the App.hInstance here.
    lpstrFilter As String        'Use this to filter what files are showen in the dialog. Separate each filter with Chr$(0). The string also has to end with a Chr(0).
    lpstrCustomFilter As String  'The pattern the user has choosed is saved here if you pass a non empty string. I never use this one
    nMaxCustFilter As Long       'The maximum saved custom filters. Since I never use the lpstrCustomFilter I always pass 0 to this.
    nFilterIndex As Long         'What filter (of lpstrFilter) is showed when the user opens the dialog.
    lpstrFile As String          'The path and name of the file the user has chosed. This must be at least MAX_PATH (260) character long.
    nMaxFile As Long             'The length of lpstrFile + 1
    lpstrFileTitle As String     'The name of the file. Should be MAX_PATH character long
    nMaxFileTitle As Long        'The length of lpstrFileTitle + 1
    lpstrInitialDir As String    'The path to the initial path :) If you pass an empty string the initial path is the current path.
    lpstrTitle As String         'The caption of the dialog.
    flags As Long                'Flags. See the values in MSDN Library (you can look at the flags property of the common dialog control)
    nFileOffset As Integer       'Points to the what character in lpstrFile where the actual filename begins (zero based)
    nFileExtension As Integer    'Same as nFileOffset except that it points to the file extention.
    lpstrDefExt As String        'Can contain the extention Windows should add to a file if the user doesn't provide one (used with the GetSaveFileName API function)
    lCustData As Long            'Only used if you provide a Hook procedure (Making a Hook procedure is pretty messy in VB.
    lpfnHook As Long             'Pointer to the hook procedure.
    lpTemplateName As String     'A string that contains a dialog template resource name. Only used with the hook procedure.
End Type
'=========================================================================    
Public Function ShowOpen(Filter As String, InitialDir As String, DialogTitle As String) As String
Dim OFName As OPENFILENAME
    OFName.lStructSize = Len(OFName)
    OFName.hwndOwner = 0
    OFName.lpstrFilter = Filter
    OFName.nMaxFile = 255
    OFName.lpstrFile = Space$(254)
    OFName.lpstrFileTitle = Space$(254)
    OFName.nMaxFileTitle = 255
    OFName.lpstrInitialDir = InitialDir
    OFName.lpstrTitle = DialogTitle
    OFName.flags = 0
    If GetOpenFileName(OFName) Then
        ShowOpen = Trim(OFName.lpstrFile)
    Else
        ShowOpen = ""
    End If
End Function
'================================================================
[B]Sub Main()[/B]
    Dim s1$, s2$
        s1 = Application.GetOpenFileName()
        s2 = ShowOpen("All File(*.*)" + Chr(0) + "*.*" + Chr(0), "C:\", "Test")
        [I][B]MsgBox StrComp(s1, s2[/B][/I])
[B]End Sub[/B]

Thanks!
 
Lần chỉnh sửa cuối:
Do một số ứng dụng khác không có hàm getopenfilename ---> em dùng hàm Api để tạo hộp thoại open file !

Em đọc chủ đề này mà không thể hiểu nổi một từ nào cả...hihi!
Anh có thể up một file kèm mới hoàn thiện nhất lên để em hình dung được không ạ?
Cảm ơn Anh!
 
Upvote 0
Em đọc chủ đề này mà không thể hiểu nổi một từ nào cả...hihi!
Anh có thể up một file kèm mới hoàn thiện nhất lên để em hình dung được không ạ?
Cảm ơn Anh!
bạn copy code của anh Tuân hoặc anh Switom vào một moudle nào đó, rồi chạy sub test single File hoặc multifile thôi!
đây là code của hội thoại getopenfilename thôi mà bạn ! nó gần giống với application.getopenfilename () trong vba excel
 
Upvote 0
bạn copy code của anh Tuân hoặc anh Switom vào một moudle nào đó, rồi chạy sub test single File hoặc multifile thôi!
đây là code của hội thoại getopenfilename thôi mà bạn ! nó gần giống với application.getopenfilename () trong vba excel
Mình thấy mọi người nói về cái API này rất nhiều. Cũng muốn tìm hiểu về nó nhưng không có tài liệu và không biết bắt đầu từ đấu. Mong mọi người chỉ dẫn và cho tài liệu
 
Upvote 0
Lần chỉnh sửa cuối:
Upvote 0
Lần chỉnh sửa cuối:
Upvote 0
Mình thấy mọi người nói về cái API này rất nhiều. Cũng muốn tìm hiểu về nó nhưng không có tài liệu và không biết bắt đầu từ đấu. Mong mọi người chỉ dẫn và cho tài liệu

API là lĩnh vực rất rộng và trừu tượng, sức mạnh của nó là can thiệp sâu vào HĐH. Có kiến thức khá về lập trình, HĐH học nó cũng không dễ và mất nhiều time. Nên cân nhắc học tốt cái nào trước: VBA; API
 
Upvote 0
Câu nói khiến mọi người suy nghĩ về bạn!!!
Có thông báo lỗi thiếu file khi cài bạn àh. nhưng quên không ghi lại được file đó. Cài xong không chạy được mất rồi bạn àh
Àh báo thiếu file : MSVBVM50.DLL
Sao bạn không tìm cách giải quyết cái thiếu đấy nhỉ? Nếu giải quyết xong thì bạn sẽ có tham khảo của gần 1000 API gồm cú pháp, minh họa và cả cách dùng trên .NET.

Thay vì ngồi yên nghi hoặc thì tự hành động sẽ có hy vọng hơn.
 
Upvote 0
Không hiểu sao 64bits không chạy được hàm getopenfilename

cho mình hỏi có bạn nào dùng win 64bits , code của a Tuân hoặc anh Switom có hoạt động không ??
Sao mình chạy code mà không thấy hiện tượng gì, không thấy hộp thoại open file hiện ra --> kết quả : msgbox ra kết quả là ""

vọc google thì được bài này :
http://stackoverflow.com/questions/4982680/getopenfilename-fails-in-64-bit-but-works-in-32bit

và trong đó có nói :

in my Project Settings, Under Code Generation the "Struct Member Alignment" is set to 4 Bytes(/Zp4). I changed this to default and it magically worked. Look for the answers and their comments below for more information.

Em không hiểu
"Struct Member Alignment " trong VBA tuỳ chỉnh ở đâu ?? google thì toàn thấy viết bằng ngôn ngữ C++
--> các anh chị có thể chỉ bảo thêm cho em được không ??
Cảm ơn diễn đàn!
 
Lần chỉnh sửa cuối:
Upvote 0
Đã tìm ra nguyên nhân !! ^^

Nếu các bạn dùng code của a Tuân hoặc a Switom cho phiên bản 64 bits : thì sửa như sau :
Mã:
    OFName.lStructSize = LenB(OFName)
    OFName.lpstrFile = String(size, vbNullChar)     ' khong dung  Space$(...)
    OFName.nMaxFile = [COLOR=#ff0000][B]LenB(OFName.lpstrFile) - 1[/B][/COLOR]

mình đã test và thành công trên máy mình !<--- các bạn kiểm tra lại các trường hợp khác ^^
 
Upvote 0
Để thỏa mãn kiến nghị của dân Excel quen dùng Application.GetOpenFilename tôi nghĩ ta nên sửa code (thuộc loại trang điểm thôi) như sau. Nhất là khi code của ta không phục vụ mọi loại giá trị của các thông số của hàm API.
1. Hàm OpenFile chỉ có các thông số: FileFilter, FilterIndex, DialogTitle, InitialDir, MultiSelect
Không có Flag vì nếu có thì để thiết lập thì user phải biết các giá trị OFN_* và ý nghĩa của chúng. Ngoài ra ta cố ý sẽ dùng OFN_EXPLORER, không để user tự quyết, vì dùng old-style dialog boxes thì kết quả trả về sẽ không được ngăn cách bởi chr(0) và do vậy việc lọc kết quả trả về sẽ không còn đúng nếu dùng code hiện hành.

2. Tôi bỏ
Mã:
    OFName.hwndOwner = GetActiveWindow
    OFName.lpstrFileTitle = Space$(MAX_PATH)
    OFName.nMaxFileTitle = MAX_PATH

3. Trường hợp MultiSelect thì ta dùng buffer "đủ lớn" thôi. Tôi nghĩ quãng 65535 là đủ. Giá trị có thể sửa tăng lên.
----------
Trong code của Tuân mà tôi thử sửa thì Filter không kết thúc bởi "|", tức ta sẽ dùng vd. "Text Files (*.txt)|*.txt" chứ không dùng "Text Files (*.txt)|*.txt|". Code sẽ tự "lo liệu" sao cho Filter kết thúc bởi 2 vbNullChar trước khi gọi hàm API.
-----------
Tôi đề nghị sửa code của Tuân như sau (phần khai báo để nguyên):
Mã:
Option Explicit

Const MAX_PATH = 255
Public Const OFN_ALLOWMULTISELECT = &H200
Public Const OFN_CREATEPROMPT = &H2000
Public Const OFN_ENABLEHOOK = &H20
Public Const OFN_ENABLETEMPLATE = &H40
Public Const OFN_ENABLETEMPLATEHANDLE = &H80
Public Const OFN_EXPLORER = &H80000                         '  new look commdlg
Public Const OFN_EXTENSIONDIFFERENT = &H400
Public Const OFN_FILEMUSTEXIST = &H1000
Public Const OFN_HIDEREADONLY = &H4
Public Const OFN_LONGNAMES = &H200000                       '  force long names for 3.x modules
Public Const OFN_NOCHANGEDIR = &H8
Public Const OFN_NODEREFERENCELINKS = &H100000
Public Const OFN_NOLONGNAMES = &H40000                      '  force no long names for 4.x modules
Public Const OFN_NONETWORKBUTTON = &H20000
Public Const OFN_NOREADONLYRETURN = &H8000
Public Const OFN_NOTESTFILECREATE = &H10000
Public Const OFN_NOVALIDATE = &H100
Public Const OFN_OVERWRITEPROMPT = &H2
Public Const OFN_PATHMUSTEXIST = &H800
Public Const OFN_READONLY = &H1
Public Const OFN_SHAREAWARE = &H4000
Public Const OFN_SHAREFALLTHROUGH = 2
Public Const OFN_SHARENOWARN = 1
Public Const OFN_SHAREWARN = 0
Public Const OFN_SHOWHELP = &H10

#If VBA7 Then
Private Declare PtrSafe Function GetOpenFileName Lib "comdlg32.dll" Alias _
                        "GetOpenFileNameW" (pOpenfilename As OPENFILENAME) As Long
Private Type OPENFILENAME
    lStructSize As Long          'The size of this struct (Use the Len function)
    hwndOwner As LongPtr         'The hWnd of the owner window. The dialog will be modal to this window
    hInstance As LongPtr         'The instance of the calling thread. You can use the App.hInstance here.
    lpstrFilter As String        'Use this to filter what files are showen in the dialog. Separate each filter with Chr$(0). The string also has to end with a Chr(0).
    lpstrCustomFilter As String  'The pattern the user has choosed is saved here if you pass a non empty string. I never use this one
    nMaxCustFilter As Long       'The maximum saved custom filters. Since I never use the lpstrCustomFilter I always pass 0 to this.
    nFilterIndex As Long         'What filter (of lpstrFilter) is showed when the user opens the dialog.
    lpstrFile As String          'The path and name of the file the user has chosed. This must be at least MAX_PATH (260) character long.
    nMaxFile As Long             'The length of lpstrFile + 1
    lpstrFileTitle As String     'The name of the file. Should be MAX_PATH character long
    nMaxFileTitle As Long        'The length of lpstrFileTitle + 1
    lpstrInitialDir As String    'The path to the initial path :) If you pass an empty string the initial path is the current path.
    lpstrTitle As String         'The caption of the dialog.
    flags As Long                'Flags. See the values in MSDN Library (you can look at the flags property of the common dialog control)
    nFileOffset As Integer       'Points to the what character in lpstrFile where the actual filename begins (zero based)
    nFileExtension As Integer    'Same as nFileOffset except that it points to the file extention.
    lpstrDefExt As String        'Can contain the extention Windows should add to a file if the user doesn't provide one (used with the GetSaveFileName API function)
    lCustData As Long            'Only used if you provide a Hook procedure (Making a Hook procedure is pretty messy in VB.
    lpfnHook As Long             'Pointer to the hook procedure.
    lpTemplateName As String     'A string that contains a dialog template resource name. Only used with the hook procedure.
    pvReserved As Long
    dwReserved As Long
    FlagsEx As Long
End Type
Private Declare PtrSafe Function GetActiveWindow Lib "user32" () As LongPtr
#Else
Private Declare Function GetOpenFileName Lib "comdlg32.dll" Alias _
                        "GetOpenFileNameW" (pOpenfilename As OPENFILENAME) As Long
Private Type OPENFILENAME
    lStructSize As Long          'The size of this struct (Use the Len function)
    hwndOwner As Long            'The hWnd of the owner window. The dialog will be modal to this window
    hInstance As Long            'The instance of the calling thread. You can use the App.hInstance here.
    lpstrFilter As String        'Use this to filter what files are showen in the dialog. Separate each filter with Chr$(0). The string also has to end with a Chr(0).
    lpstrCustomFilter As String  'The pattern the user has choosed is saved here if you pass a non empty string. I never use this one
    nMaxCustFilter As Long       'The maximum saved custom filters. Since I never use the lpstrCustomFilter I always pass 0 to this.
    nFilterIndex As Long         'What filter (of lpstrFilter) is showed when the user opens the dialog.
    lpstrFile As String          'The path and name of the file the user has chosed. This must be at least MAX_PATH (260) character long.
    nMaxFile As Long             'The length of lpstrFile + 1
    lpstrFileTitle As String     'The name of the file. Should be MAX_PATH character long
    nMaxFileTitle As Long        'The length of lpstrFileTitle + 1
    lpstrInitialDir As String    'The path to the initial path :) If you pass an empty string the initial path is the current path.
    lpstrTitle As String         'The caption of the dialog.
    flags As Long                'Flags. See the values in MSDN Library (you can look at the flags property of the common dialog control)
    nFileOffset As Integer       'Points to the what character in lpstrFile where the actual filename begins (zero based)
    nFileExtension As Integer    'Same as nFileOffset except that it points to the file extention.
    lpstrDefExt As String        'Can contain the extention Windows should add to a file if the user doesn't provide one (used with the GetSaveFileName API function)
    lCustData As Long            'Only used if you provide a Hook procedure (Making a Hook procedure is pretty messy in VB.
    lpfnHook As Long             'Pointer to the hook procedure.
    lpTemplateName As String     'A string that contains a dialog template resource name. Only used with the hook procedure.
    pvReserved As Long
    dwReserved As Long
    FlagsEx As Long
End Type
Private Declare Function GetActiveWindow Lib "user32" () As Long
#End If

Public Function OpenFile(Optional Filter As String = vbNullString, _
                        Optional FilterIndex As Long = 1, _
                        Optional InitialDir As String = vbNullString, _
                        Optional DialogTitle As String = vbNullString, _
                        Optional MultiSelect As Boolean = False) As Variant
Dim OFName As OPENFILENAME, size As Long
    OFName.lStructSize = Len(OFName)
    If Len(Filter) = 0 Then
        Filter = "All Files(*.*)|*.*" & vbNullChar
    Else
        Filter = Filter & vbNullChar
    End If
    Filter = Replace(Filter, "|", vbNullChar)
    OFName.lpstrFilter = StrConv(Filter, vbUnicode)
    OFName.nFilterIndex = FilterIndex
    If MultiSelect Then
        size = 65535
    Else
        size = MAX_PATH
    End If
    OFName.lpstrFile = String(size, vbNullChar)     ' [COLOR=#ff0000]khong dung  Space$(...)[/COLOR]
    OFName.nMaxFile = size
    OFName.lpstrInitialDir = StrConv(InitialDir, vbUnicode)
    OFName.lpstrTitle = StrConv(DialogTitle, vbUnicode)
    If MultiSelect Then OFName.flags = OFN_EXPLORER Or OFN_ALLOWMULTISELECT
   
    If GetOpenFileName(OFName) Then
        If MultiSelect Then
            OpenFile = StrConv(GetAPIstr(OFName.lpstrFile, vbNullChar & vbNullChar & vbNullChar & vbNullChar), vbFromUnicode)
            OpenFile = Split(OpenFile, vbNullChar) 'convert to 1D array
        Else
            OpenFile = StrConv(GetAPIstr(OFName.lpstrFile), vbFromUnicode)
        End If
    Else
        OpenFile = ""
    End If
End Function

Function GetAPIstr(ByVal sAPIString As String, Optional ByVal sTerminatedText As String = vbNullChar & vbNullChar) As String
    GetAPIstr = Left(sAPIString, InStr(sAPIString, sTerminatedText))
End Function

'TEST---------------------------------------------------------------
Sub TestGetSingleFile()
    Dim FullName
    Cells.Clear
    FullName = OpenFile("All Files(*.*)|*.*|" & _
                        "Excel File|*.xl*")
    Cells(1, 1) = FullName
    MsgBox FullName
End Sub
'-------------------------------------------------------------------
Sub TestGetMultiFile()
    Dim FullName
    Dim I&
    Cells.Clear
    FullName = OpenFile("All Files(*.*)|*.*|" & _
                        "Excel File|*.xl*", , , , True)
    If Not VarType(FullName) = (vbArray Or vbString) Then Exit Sub
    For I = LBound(FullName) To UBound(FullName)
        Cells(I + 1, 1) = FullName(I)
    Next I
    MsgBox "So file la: " & UBound(FullName) - LBound(FullName) + 1
End Sub

Kính chào bác Siwtom và các bạn
Bác ơi trong trường hợp Oanh Thơ muốn sử dụng code sau:
Mã:
Sub TestGetSingleFile()
    Dim FullName
    FullName = OpenFile("All Files(*.*)|*.*|" & _
                        "Excel File|*.xl*")
    MsgBox FullName
End Sub
Và chỉ lấy đường dẫn của thư mục chứa tập tin (không bao gồm tên tập tin) kiểu như ThisWorkbook.Path.
Vì dụ: chạy code trên lựa chọn tập tin testhumuc.xlsx trong đường dẫn C:\Users\Nguyen Hoang Oanh Tho\Documents
thì kết quả là:
C:\Users\Nguyen Hoang Oanh Tho\Documents\testhumuc.xlsx
Mong muốn kết quả đổi:
C:\Users\Nguyen Hoang Oanh Tho\Documents
Thì code trên sẽ viết như thế nào ạ?
 
Upvote 0
Kính chào bác Siwtom và các bạn
Bác ơi trong trường hợp Oanh Thơ muốn sử dụng code sau:
Mã:
Sub TestGetSingleFile()
    Dim FullName
    FullName = OpenFile("All Files(*.*)|*.*|" & _
                        "Excel File|*.xl*")
    MsgBox FullName
End Sub
Và chỉ lấy đường dẫn của thư mục chứa tập tin (không bao gồm tên tập tin) kiểu như ThisWorkbook.Path.
Vì dụ: chạy code trên lựa chọn tập tin testhumuc.xlsx trong đường dẫn C:\Users\Nguyen Hoang Oanh Tho\Documents
thì kết quả là:
C:\Users\Nguyen Hoang Oanh Tho\Documents\testhumuc.xlsx
Mong muốn kết quả đổi:
C:\Users\Nguyen Hoang Oanh Tho\Documents
Thì code trên sẽ viết như thế nào ạ?
Nếu có tên tập tin (lấy từ đâu đó, không nhất thiết là do hàm nào đó trả về, vd. ai đó nhập trên Sheet) và nó chắc chắn tồn tại thì có thể tìm ký tự "\" cuối cùng (InStrRev) rồi lấy từ đầu tới trước ký tự đó thôi (Left, Mid).
Hoặc dùng FileSystemObject
Mã:
Function DirectoryFromFilename(ByVal filename As String) As String
    With CreateObject("Scripting.FileSystemObject")
        If .FileExists(filename) Then DirectoryFromFilename = .GetParentFolderName(filename)
    End With
End Function

Sub test()
    MsgBox DirectoryFromFilename("D:\Moje dane\record\dictionary\ho.jpg")
End Sub
 
Upvote 0
Nếu có tên tập tin (lấy từ đâu đó, không nhất thiết là do hàm nào đó trả về, vd. ai đó nhập trên Sheet) và nó chắc chắn tồn tại thì có thể tìm ký tự "\" cuối cùng (InStrRev) rồi lấy từ đầu tới trước ký tự đó thôi (Left, Mid).
Hoặc dùng FileSystemObject
Mã:
Function DirectoryFromFilename(ByVal filename As String) As String
    With CreateObject("Scripting.FileSystemObject")
        If .FileExists(filename) Then DirectoryFromFilename = .GetParentFolderName(filename)
    End With
End Function

Sub test()
    MsgBox DirectoryFromFilename("D:\Moje dane\record\dictionary\ho.jpg")
End Sub

Dạ, cảm ơn Bác đã gợi ý.Oanh Thơ làm như sau:
Mã:
 MsgBox Left(FullName, InStrRev(FullName, "\"))
Kết quả đã Ok rồi Bác ạ.
Chúc Bác nhiều sức khỏe.
 
Upvote 0
Nếu có tên tập tin (lấy từ đâu đó, không nhất thiết là do hàm nào đó trả về, vd. ai đó nhập trên Sheet) và nó chắc chắn tồn tại thì có thể tìm ký tự "\" cuối cùng (InStrRev) rồi lấy từ đầu tới trước ký tự đó thôi (Left, Mid).
Hoặc dùng FileSystemObject
Mã:
Function DirectoryFromFilename(ByVal filename As String) As String
    With CreateObject("Scripting.FileSystemObject")
        If .FileExists(filename) Then DirectoryFromFilename = .GetParentFolderName(filename)
    End With
End Function

Sub test()
    MsgBox DirectoryFromFilename("D:\Moje dane\record\dictionary\ho.jpg")
End Sub

Bác ơi, Oanh Thơ sử dụng code sau để lấy tên tập tin:
Mã:
Mid(FullName, InStrRev(FullName, "\") + 1)
Thì được kết quả: testhumuc.xlsx
Nếu chỉ lấy phần tên tập tin: testhumuc (không lấy đuôi của tập tin ".xlsx") ,thì dùng hàm gì để xử lý ạ Bác?
Cảm ơn Bác ạ
 
Upvote 0
Bác ơi, Oanh Thơ sử dụng code sau để lấy tên tập tin:
Mã:
Mid(FullName, InStrRev(FullName, "\") + 1)
Thì được kết quả: testhumuc.xlsx
Nếu chỉ lấy phần tên tập tin: testhumuc (không lấy đuôi của tập tin ".xlsx") ,thì dùng hàm gì để xử lý ạ Bác?
Cảm ơn Bác ạ
Thế bạn không biết tìm dấu chấm "." à? Tìm xuôi: Instr (không được khi tập tin có nhiều dấu chấm, vd. hichic.txt.jpg.xlsx) hoặc ngược: InstrRev.
 
Upvote 0
Thế bạn không biết tìm dấu chấm "." à? Tìm xuôi: Instr (không được khi tập tin có nhiều dấu chấm, vd. hichic.txt.jpg.xlsx) hoặc ngược: InstrRev.

Dạ ok rồi Bác ạ, cảm ơn Bác nhiều T_T
Mã:
sFileName = Mid(FullName, InStrRev(FullName, "\") + 1)
MsgBox Left(sFileName, (InStr(sFileName, ".") - 1))
 
Lần chỉnh sửa cuối:
Upvote 0
Web KT

Bài viết mới nhất

Back
Top Bottom