6

如果剪贴板包含 Excel 工作表范围,您可以使用 DataObject 对象访问该范围的数据

您还可以找到该数据的实际源范围(即工作表、行和列)吗?

或者,您能找到最后复制的范围,它用虚线轮廓边框(不是所选范围)表示吗?

最好使用 Excel 2003 VBA

4

2 回答 2

3

此代码在 Excel 2019 64 位中用于获取剪贴板上的单元格范围,而不是单元格的内容。

fGetClipRange 返回 Excel 范围的范围对象,该范围对象被剪切或复制到剪贴板上,包括书籍和工作表。它使用“链接”格式直接从剪贴板中读取它,并且需要此格式的 ID 号。与注册格式关联的 ID 可以更改,因此 fGetFormatId 从格式名称中查找当前格式 ID。使用 Application.CutCopyMode 确定单元格是否被剪切或复制。

该站点对于在 VBA 中使用剪贴板很有用:https ://social.msdn.microsoft.com/Forums/office/en-US/ee9e0d28-0f1e-467f-8d1d-1a86b2db2878/a-clipboard-object-for- vba-包括-microsoft-word?forum=worddev

Private Declare PtrSafe Function lstrcpy Lib "kernel32" (ByVal lpString1 As Any, ByVal lpString2 As Any) As LongPtr
Private Declare PtrSafe Function GlobalLock Lib "kernel32" (ByVal hMem As LongPtr) As LongPtr
Private Declare PtrSafe Function GlobalUnlock Lib "kernel32" (ByVal hMem As LongPtr) As Long
Private Declare PtrSafe Function OpenClipboard Lib "user32" (ByVal hwnd As LongPtr) As Long
Private Declare PtrSafe Function CloseClipboard Lib "user32" () As Long
Private Declare PtrSafe Function GetClipboardData Lib "user32" (ByVal lngFormat As Long) As LongPtr
Private Declare PtrSafe Function EnumClipboardFormats Lib "user32" (ByVal wFormat As Long) As Long
Private Declare PtrSafe Function GetClipboardFormatNameA Lib "user32" (ByVal wFormat As Long, ByVal lpString As String, ByVal nMaxCount As Long) As Long

'2020-02-11 get excel copy or cut range from clipboard
Function fGetClipRange() As Range
Dim strGetClipRange As String    'return range
Dim lptClipData As LongPtr  'pointer to clipboard data
Dim strClipData As String   'clipboard data
Dim intOffset As Integer    'for parsing clipboard data
Dim lngRangeLink As Long  'clipboard format
Const intMaxSize As Integer = 256   'limit for r1c1 to a1 conversion
    lngRangeLink = fGetFormatId("Link") 'we need the id number for link format
    If OpenClipboard(0&) = 0 Then GoTo conDone  'could not open clipboard
    lptClipData = GetClipboardData(lngRangeLink)    'pointer to clipboard data
    If IsNull(lptClipData) Then GoTo conDone    'could not allocate memory
    lptClipData = GlobalLock(lptClipData)   'lock clipboard memory so we can reference
    If IsNull(lptClipData) Then GoTo conDone    'could not lock clipboard memory
    intOffset = 0   'start parsing data
    strClipData = Space$(intMaxSize)    'initialize string
    Call lstrcpy(strClipData, lptClipData + intOffset)  'copy pointer to string
    If strClipData = Space$(intMaxSize) Then GoTo conDone   'not excel range on clipboard
    strClipData = Mid(strClipData, 1, InStr(1, strClipData, Chr$(0), 0) - 1)    'trim null character
    If strClipData <> "Excel" Then GoTo conDone     'not excel range on clipboard
    intOffset = intOffset + 1 + Len(strClipData)    'can't retrieve string past null character
    strClipData = Space$(intMaxSize)    'reset string
    Call lstrcpy(strClipData, lptClipData + intOffset)  'book and sheet next
    strClipData = Mid(strClipData, 1, InStr(1, strClipData, Chr$(0), 0) - 1)
    strGetClipRange = "'" & strClipData & "'!"  'get book and sheet
    intOffset = intOffset + 1 + Len(strClipData)    'next offset
    strClipData = Space$(intMaxSize)    'initialize string
    Call lstrcpy(strClipData, lptClipData + intOffset)  'range next
    strClipData = Mid(strClipData, 1, InStr(1, strClipData, Chr$(0), 0) - 1)
    strGetClipRange = strGetClipRange & strClipData 'add range
    strGetClipRange = Application.ConvertFormula(strGetClipRange, xlR1C1, xlA1)
    Set fGetClipRange = Range(strGetClipRange)  'range needs a1 style
conDone:
    Call GlobalUnlock(lptClipData)
    Call CloseClipboard
End Function

'2020-02-11 clipboard format id number changes so get it from format name
Function fGetFormatId(strFormatName As String) As Long
Dim lngFormatId As Long
Dim strFormatRet As String
Dim intLength As Integer
    If OpenClipboard(0&) = 0 Then Exit Function   'could not open clipboard
    intLength = Len(strFormatName) + 3  'we only need a couple extra to make sure there isn't more
    lngFormatId = 0 'start at zero
    Do
        strFormatRet = Space(intLength) 'initialize string
        GetClipboardFormatNameA lngFormatId, strFormatRet, intLength    'get the name for the id
        strFormatRet = Trim(strFormatRet)   'trim spaces
        If strFormatRet <> "" Then  'if something is left
            strFormatRet = Left(strFormatRet, Len(strFormatRet) - 1)    'get rid of terminal character
            If strFormatRet = strFormatName Then    'if it matches our name
                fGetFormatId = lngFormatId  'this is the id number
                Exit Do 'done
            End If
        End If
        lngFormatId = EnumClipboardFormats(lngFormatId) 'get the next used id number
    Loop Until lngFormatId = 0  'back at zero after last id number
    Call CloseClipboard 'close clipboard
End Function
于 2020-02-03T05:29:41.403 回答
2

不直接,不 - 剪贴板对象似乎只包含单元格的值(尽管 Excel 显然以某种方式记住了边框):

Sub testClipborard()

    Dim test As String
    Dim clipboard As MSForms.DataObject
    Set clipboard = New MSForms.DataObject

    clipboard.GetFromClipboard
    test = clipboard.GetText

    MsgBox (test)

End Sub

请注意,您需要参考 Microsoft Forms 2.0 库才能运行它(如果单元格中没有值,它也会失败)。


话虽如此,您可以尝试以下操作 - 将其添加到 VBA 编辑器中的模块中。

Public NewRange As String 
Public OldRange As String 
Public SaveRange As String 
Public ChangeRange As Boolean 

并在工作表对象中使用以下内容

Private Sub Worksheet_SelectionChange(ByVal Target As Excel.Range) 

     'save previous selection
    OldRange = NewRange 

     'get current selection
    NewRange = Selection.Address 

     'check if copy mode has been turned off
    If Application.CutCopyMode = False Then 
        ChangeRange = False 
    End If 

     'if copy mode has been turned on, save Old Range
    If Application.CutCopyMode = 1 And ChangeRange = False Then 
         'boolean to hold "SaveRange" address til next copy/paste operation
        ChangeRange = True 
         'Save last clipboard contents range address
        SaveRange = OldRange 
    End If 

End Sub 

它似乎有效,但是,它也可能相当容易出现不同的错误,因为它试图解决剪贴板的问题。 http://www.ozgrid.com/forum/showthread.php?t=66773

于 2012-08-24T22:31:43.160 回答