如何在 MS Access VBA 中获取 MSForms.DataObject 内容的大小

How to get the size of the contents of MSForms.DataObject in MS Access VBA

我已将 BMP 图像复制到剪贴板,我会将其粘贴到 MS Access (2016) 中的表单对象框架控件中。

我需要知道的是图像在剪贴板上占用的内存大小(尽管如果有必要的话,如果有办法在对象框架控件中之后获取大小信息就可以了)。比如图片是76582字节还是652字节还是942002字节等等?

这是我用来将剪贴板中的图像粘贴到对象框架控件中的代码:

With Me.imgGrabbedFrame 'Bound Object Frame control
    .Class = "Paintbrush Picture"
    .OLETypeAllowed = acOLEEmbedded
    .Action = acOLEPaste
End With

有没有办法获取剪贴板上对象占用的内存?

您可以将此函数与图像控件的属性部分中的图像 url 路径的字符串值一起使用

FileLen("C:\Temp\test file.xls")

你可以只计算框架值属性的长度。这包括任何 OLE meta-information.

LenB(Me.imgGrabbedFrame.Value)

return 值是以字节为单位的长度。

在剪贴板上计算它是可能的,但要复杂得多。

为此,首先,让我们定义几个函数来处理剪贴板:

Public Declare PtrSafe Function GetClipboardFormatNameW Lib "User32" (ByVal format As Long, ByVal lpszFormatName As LongPtr, ByVal cchMaxCount As Long) As Long
Public Declare PtrSafe Function OpenClipboard Lib "User32" (Optional ByVal hWndNewOwner As LongPtr) As Boolean
Public Declare PtrSafe Function CloseClipboard Lib "User32" () As Boolean
Public Declare PtrSafe Function EnumClipboardFormats Lib "User32" (ByVal format As Long) As Long
Public Declare PtrSafe Function CountClipboardFormats Lib "User32" () As Long
Public Declare PtrSafe Function GlobalSize Lib "Kernel32" (ByVal hMem As LongPtr) As LongPtr
Public Declare PtrSafe Function GetClipboardData Lib "User32" (ByVal uFormat As Long) As LongPtr

然后,让我们定义一个函数来迭代剪贴板上的不同格式:

Public Sub ListClipboardFormats()
    Dim l As Long
    Dim format As Long
    Dim b As String
    OpenClipboard
    b = String(255, vbNullChar)
    For l = 1 To CountClipboardFormats
        format = EnumClipboardFormats(format)
        GetClipboardFormatNameW format, StrPtr(b), 255
        If Left(b, 1) = vbNullChar Then
            Debug.Print format
        Else
            Debug.Print b
        End If
        b = String(255, vbNullChar)
    Next
    CloseClipboard
End Sub

此函数会将所有可用的剪贴板格式打印到即时 window。如果它是 built-in 格式,它将打印一个数字。您可以找到数字列表 here。图像数据的常见数字是 8,对于 CF_DIB,device-independent 位图,或 17 对于 CF_DIBV5,同一事物的更现代变体。

如果我们想使用其中一种自定义格式,让我们定义一个函数来获取它的编号。如果出现错误或 non-existent 剪贴板格式,此函数将 return 0:

Public Function GetClipboardFormatByName(strName As String) As Long
    Dim format As Long
    Dim b As String
    Dim l As Long
    OpenClipboard
    For l = 1 To CountClipboardFormats
        b = String(255, vbNullChar) 'Initialize string buffer
        format = EnumClipboardFormats(format) 'Get next format
        GetClipboardFormatNameW format, StrPtr(b), 255 'Copy name to buffer
        If Left(b, Len(strName)) = strName Then
             GetClipboardFormatByName = format
             Exit Function
        End If
    Next
    CloseClipboard
End Function

然后,如果我们有其格式,则确定剪贴板上内容大小的最终函数:

Public Function GetClipboardLength(ClipboardFormat As Long) As Long
    OpenClipboard
    Dim hClipboardGlobal As LongPtr
    hClipboardGlobal = GetClipboardData(ClipboardFormat)
    If hClipboardGlobal <> 0 Then
        GetClipboardLength = GlobalSize(hClipboardGlobal)
    End If
    CloseClipboard
End Function

如果我们知道剪贴板上有一个 DIB,那么获取它的大小就像 GetClipboardLength(8) 一样简单。请注意,这是 DIB 的大小,并且在粘贴时可能实际上与数据的大小不相同,因为它被保存,因为可能会进行额外的处理。

关于剪贴板上大小的说明:剪贴板上的大小可能大于或小于您粘贴的大小,具体取决于实施方式。程序可以(而且经常会)将同一事物的多种表示形式(文本、富文本、图像、OLE 数据对象)放在剪贴板上,也可以以仅在访问时复制的方式将其放在那里。这就是为什么在复制大型对象后关闭 Office 程序时,系统经常会询问您是否要将该对象保留在剪贴板上。