【问题标题】:Is there an Open File dialog for Access 2010 64bit?Access 2010 64bit 是否有打开文件对话框?
【发布时间】:2011-06-12 10:16:32
【问题描述】:

如何获得 Access 2010 64bit 的“打开文件”对话框?通常我会使用通用对话框控件,但它是 32 位的,不能与 Access 2010 64 位一起使用。

【问题讨论】:

  • 我无法想象这不起作用。我在 64 位应用程序中多次使用打开文件对话框。您无法在 32 位版本的 Windows 上运行 64 位版本的 Office,因此您应该使用 64 位版本的 commdlg。
  • 每当我尝试添加通用对话框控件并拖动到 MS Access 表单中时,它都会给我一个“OleDb 错误”。这是带有 MS Access 64 位的 64 位 Windows 7 PC。这对我来说也很奇怪。
  • GetOpenFileName 有什么问题还是我遗漏了什么?
  • @Cody 我认为 Greg 指的是CreateObject("UserAccounts.CommonDialog")
  • 呃,将任何旧控件从已安装的 ActiveX 控件列表中拖出通常会失败,因为无法保证它们可以与 Access 一起使用。当然,正如 Tony 在下面所说,我从未使用过 FileOpen 控件——我总是使用 Windows API 调用,它适用于每个版本的 Windows。

标签: ms-access vba openfiledialog ms-access-2010


【解决方案1】:

您可以使用内置的文件对话框。自 2003 年访问以来一直存在。

Dim f    As FileDialog 
Set f = Application.FileDialog(msoFileDialogFilePicker) 
f.Show 
MsgBox "file choose was " & f.SelectedItems(1) 

如果您愿意,您可以后期绑定:

以上需求:Microsoft Office 14.0 对象库

如果删除对 14.0 对象库的引用,则以下内容 代码无需任何引用即可工作:

Dim f    As Object 
Set f = Application.FileDialog(3) 
f.AllowMultiSelect = True 
f.Show 

MsgBox "file choosen = " & f.SelectedItems.Count 

因此,从 2003 年开始,上述内容适用于运行时或普通版,也适用于 access 2010 的 32 位或 64 位版本。

【讨论】:

  • 我永远不会使用它,因为我担心他们会对 FileSearch 对象做同样的事情,并将其从未来的版本中删除。因为我已经有了直接的 API 代码,所以我不需要使用这样的包装器,尽管它肯定会避免 API 代码的 64 位代码转换问题。
  • FileSearch 不相信包含在运行时中,因此不能总是假设。 FileDialog 自 2003 年访问以来一直存在,始终与运行时一起工作,并且无需设置任何引用(后期绑定)即可工作。该对话框是所有办公室的一部分,并且在 64 位版本中工作(如您所述)。我确实同意它可以被删除,但到目前为止,从历史上看,这个选择自 2003 年以来就已经奏效,比 api 麻烦更少,这包括新的 64 位版本。这个我挺采纳的,如果我吃乌鸦的话,我会在公共场合这样做,但我认为这是现在最好的选择。 YMMV。
  • FileSearch 对象是 Access Application 对象的成员,因此不需要引用。我怀疑它在运行时可用,因为它是顶级 Application 对象的成员。据我所知,它的实现方式与 FileDialog 的实现方式相同,但它在 A2007 中被删除了。我认为那是因为 MS 想用基于新搜索基础架构的搜索技术替换他们的旧搜索技术,所以这比其他任何事情都更加政治化。我承认我很难想象删除 FileDialog 有类似的出于政治动机的理由。
  • 这不适用于 MS Access 2010 64 位。当我运行上面引用 Microsoft Object 14.0 的代码时,我收到“未定义用户定义类型”错误。
  • 我在“Dim f As FileDialog”行遇到了与 Greg 相同的错误。添加“Microsoft Office 15.0 对象库”作为参考修复了错误并允许我毫无问题地使用此代码。感谢您发布解决方案 Albert!
【解决方案2】:

我从未使用过打开文件对话框的控件,因为无论如何它只是 API 调用的包装器。 Call the standard Windows File Open/Save dialog box 此外,控件可能存在分发和版本控制问题,所以我尽量避免它们。

【讨论】:

  • 您发布的链接中的代码可能会起作用,但它太混乱了。而真正的 WTF 是使用 Variant 类型。当您绝对不必使用它时,没有任何借口。
  • 托尼引用的代码不起作用?我已经让它在 64 位 Win7 上运行,这从来都不是问题——它在第一次被调用时就可以正常工作。
  • Tony 引用的代码甚至无法在 Access 2010 64 位版本上编译。即使添加了 PtrSafe 属性,它也不起作用。它肯定适用于 Windows 7 64 位下的 Access 2010 32 位版本。
【解决方案3】:

我已经解决这个问题很长时间了......

您在上面所说的一切都有效,但还有最后一点要添加...在您需要更改的 WITH OFN 声明下

.lStructSize = Len(ofn)

.lStructSize = LenB(ofn)

然后一切正常。

【讨论】:

    【解决方案4】:

    这家伙有一个工具,可以生成与 64 位兼容的代码来打开文件。它是免费软件。

    http://www.avenius.de/en/index.php?Products:IDBE_Tools

    这是唯一有效的方法。

    【讨论】:

    • 大卫,我之前看到了上面的长指针文章,并试图让托尼的代码工作。在我让 Tony 的代码工作之前,我找到了 avenius 生成器。值得庆幸的是,它生成的代码适用于 Access 2000 到 Access 2010 64 位。现在在 AccessDiff 中使用:kellermansoftware.com/p-33-accessdiff.aspx 检测 Access 2010 64 位版本的关键是:#If Win64 = 1 And VBA7 = 1 Then
    【解决方案5】:

    首先,“CommonDialog 类”似乎无法在 32 位版本的 Office 上运行。它给出了相同的 OleDb 错误。正如其中一位评论者指出的那样,这不是您应该使用的控件。虽然您可能还可以使用另一个 ActiveX 控件,但实际上并不能保证它在您想要部署数据库的每台机器上都可用。我的开发箱上装有 Visual Studio 6、VS 2008 和 VS 2010,此外还有 Office 和其他程序,所有这些程序都提供了普通用户无法拥有的 ActiveX DLL。此外,这些库中有许多是不可再分发的,或者构成了可能根本不值得麻烦的独特安装障碍。

    到目前为止,最简单、最通用的解决方案是从 Windows API 调用“打开”对话框。它位于 comdlg32.dll 中,该文件适用于您可能针对的每个 Windows 版本, 并且不对 comdlg32.ocx 施加任何依赖。它还提供比使用 ActiveX 控件更好的性能,因为它不需要将额外的模块加载到内存中。

    所需的代码也不是很复杂。您需要为函数GetOpenFileName 提供声明,该函数会创建“打开”对话框。它采用单个参数,OPENFILENAME structure 的一个实例,其中包含用于初始化对话框的信息,以及接收用户选择的文件的路径。因此,您还需要提供此结构的声明。 VBA 中的代码如下所示:

    Private Type OPENFILENAME
        lStructSize As Long
        hwndOwner As Long
        hInstance As Long
        lpstrFilter As String
        lpstrCustomFilter As String
        nMaxCustFilter As Long
        nFilterIndex As Long
        lpstrFile As String
        nMaxFile As Long
        lpstrFileTitle As String
        nMaxFileTitle As Long
        lpstrInitialDir As String
        lpstrTitle As String
        flags As Long
        nFileOffset As Integer
        nFileExtension As Integer
        lpstrDefExt As String
        lCustData As Long
        lpfnHook As Long
        lpTemplateName As String
    End Type
    
    Private Declare Function GetOpenFileName Lib "comdlg32.dll" _
        Alias "GetOpenFileNameA" (ByRef lpofn As OPENFILENAME) As Long
    

    还有几个常量可以作为标志传递来自定义对话框的行为。为了完整起见,以下是完整列表:

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

    为了方便起见,我将整个混乱包裹在一个帮助函数中,您可以在 VBA 中调用该函数。它接受您最常需要为打开文件对话框设置的属性作为参数,处理调用 Windows API 本身,然后返回用户选择的文件的完整路径或空字符串 (vbNullString)如果用户单击取消按钮。您可以在调用代码中测试返回值以确定要采取的行动。

    'This function shows the Windows Open File dialog with the specified
    ' parameters, and either returns the full path to the selected file,
    ' or an empty string if the user cancels.
    Public Function OpenFile(ByVal Title As String, ByVal Filter As String, _
        ByVal FilterIndex As Integer, ByVal StartPath As String, _
        Optional OwnerForm As Form = Nothing) As String
    
        'Create and populate an OPENFILENAME structure
        'using the specified parameters
        Dim ofn As OPENFILENAME
        With ofn
            .lStructSize = Len(ofn)
            If OwnerForm Is Nothing Then
                .hwndOwner = 0
            Else
                .hwndOwner = OwnerForm.Hwnd
            End If
            .lpstrFilter = Filter
            .nFilterIndex = FilterIndex
            .lpstrFile = Space$(1024) & vbNullChar & vbNullChar
            .nMaxFile = Len(ofn.lpstrFile)
            .lpstrFileTitle = vbNullChar & Space$(512) & vbNullChar & vbNullChar
            .nMaxFileTitle = Len(.lpstrFileTitle)
            .lpstrInitialDir = StartPath & vbNullChar & vbNullChar
            .lpstrTitle = Title
            .flags = OFN_FILEMUSTEXIST
        End With
    
        'Call the Windows API function to show the dialog
        If GetOpenFileName(ofn) = 0 Then
            'The user pressed cancel, so return an empty string
            OpenFile = vbNullString
        Else
            'The user selected a file, so remove the null-terminators
            ' and return the full path
            OpenFile = Trim$(Left$(ofn.lpstrFile, Len(ofn.lpstrFile) - 2))
        End If
    End Function
    

    哇,结果很长。您需要将许多声明复制并粘贴到模块中,但您实际必须处理的界面非常简单。以下是您如何在代码中实际使用它来显示打开文件对话框并获取文件路径的示例:

    Public Sub DoWork()
        'Set the filter string (patterns) for the open file dialog
        Dim strFilter As String
        strFilter = "Text Files (*.txt)" & vbNullChar & "*.txt*" & vbNullChar & _
                    "All Files (*.*)" & vbNullChar & "*.*" & vbNullChar & vbNullChar
    
        'Show the open file dialog with the custom title, the filters specified
        ' above, and starting in the root directory of the C: drive.
        Dim strFileToOpen As String
        strFileToOpen = OpenFile("Choose a file to open", strFilter, 0, "C:\")
    
        'See if the user selected a file
        If strFileToOpen = vbNullString Then
            MsgBox "The user pressed the Cancel button."
        Else
            MsgBox "The user chose to open the following file: " & _
                   vbNewLine & strFileToOpen 
        End If
    End Sub
    

    编写和测试此解决方案最长的部分实际上是试图找到如何打开 VBA 编辑器并在 Access 中编写宏。对于使用主菜单进行“粘贴”和“保存”的人来说,功能区可能是一项伟大的发明,但真是太痛苦了。我整天都在使用软件,但我仍然找不到东西。 [/rant]

    【讨论】:

    • 此解决方案不适用于带有 Microsoft Access 64 位的 Windows 7 64 位。当我运行代码时,它立即返回“用户按下了取消按钮”。
    • 另外,函数声明也缺少 PtrSafe:
    【解决方案6】:

    我错过了 64 位访问详细信息。您不太可能运行它,但如果您这样做了,这里有一篇文章供您考虑,它解释了您必须如何更改 API 调用才能工作——您必须使用新的长指针数据类型:

    Compatibility Between the 32-bit and 64-bit Versions of Office 2010

    如果您相应地更改 API 代码,它应该可以在 64 位 Access 上正常工作。

    但是您真的应该问一下为什么要使用 64 位 Access。 MS 根本不建议任何人使用 64 位 Office,除非他们有特定的原因需要它(例如需要使用它提供的额外内存,特别是对于复杂的 Excel 电子表格模型之类的东西)。 Access 绝对不是从转换为 64 位中受益匪浅的应用之一。

    主题的详细讨论:

    简而言之,大多数人不应该运行 64 位 Office,这正是您遇到的原因 - 它会导致外部依赖于 32 位组件和 API 的旧代码失败。

    【讨论】:

      【解决方案7】:

      我一直在努力在 64 位版本的 Excel 2013 中解决这个问题。

      ...的组合

      1. 对传递给GetOpenFileNameAOPENFILENAME结构中的3个项目(hwndOwnerhInstancelpfnHook)使用LongPtr数据类型
      2. 在获取OPENFILENAME 结构的大小时将Len 函数替换为LenB 函数(如Max Albanese 所述)

      ...感谢此处记录的指导,成功了: https://gpgonaccess.blogspot.co.uk/2010/03/work-in-progress-and-64-bit-vba.html

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2010-12-11
        • 1970-01-01
        • 1970-01-01
        • 2010-11-01
        相关资源
        最近更新 更多