2013-09-07 7 views
12

Раньше я мог использовать вызовы Windows API в Excel VBA для установки текста в буфер обмена. Но с момента обновления до 64-разрядного Office 2013 я не могу. Ниже приведен код, который не является ошибкой, но он также не устанавливает текст в буфере обмена. Может ли кто-нибудь помочь мне протестировать и устранить неполадки?Excel 2013 64-бит VBA: API буфера обмена не работает

После вставки кода, приведенного ниже, в модуль кода в VBA, вы можете протестировать его в непосредственных окнах, набрав Clipboard_SetData("Copy this to the clipboard."), и он должен установить этот текст в буфере обмена, и вы сможете вставить его в любое другое приложение.

(я использую Windows 8, поэтому я не могу использовать форму Microsoft или объект данных для управления буфером обмена Это не работает должным образом на Windows 8..)

UPDATE и EDIT: кода ниже, были исправлено и теперь корректно работает в 64-битном Excel, благодаря ответу Джейсона Курца ниже. Если вы найдете это полезным, проголосуйте за его ответ.

Option Explicit 

'Found 64-bit API declarations here: http://spreadsheet1.com/uploads/3/0/6/6/3066620/win32api_ptrsafe.txt 
Private Declare PtrSafe Function GlobalAlloc Lib "kernel32" (ByVal wFlags As Long, ByVal dwBytes As LongPtr) As LongPtr 
Private Declare PtrSafe Function GlobalFree Lib "kernel32" (ByVal hMem As LongPtr) As LongPtr 
Private Declare PtrSafe Function GlobalLock Lib "kernel32" (ByVal hMem As LongPtr) As LongPtr 
Private Declare PtrSafe Function GlobalSize 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 EmptyClipboard Lib "user32"() As Long 
Private Declare PtrSafe Function SetClipboardData Lib "user32" (ByVal wFormat As Long, ByVal hMem As LongPtr) As LongPtr 
Private Declare PtrSafe Function GetClipboardData Lib "user32" (ByVal wFormat As Long) As LongPtr 
Private Declare PtrSafe Function lstrcpy Lib "kernel32" (ByVal lpString1 As Any, ByVal lpString2 As Any) As LongPtr 

Private Const GMEM_MOVEABLE = &H2 
Private Const GMEM_ZEROINIT = &H40 
Private Const GHND = (GMEM_MOVEABLE Or GMEM_ZEROINIT) 

Public Const CF_TEXT = 1 
Public Const MAXSIZE = 4096 

Sub ClipBoard_SetData(MyString As String) 
'32-bit code by Microsoft: http://msdn.microsoft.com/en-us/library/office/ff192913.aspx 
    Dim hGlobalMemory As LongPtr, lpGlobalMemory As LongPtr 
    Dim hClipMemory As LongPtr, X As Long 

    ' Allocate moveable global memory. 
    hGlobalMemory = GlobalAlloc(GHND, Len(MyString) + 1) 

    ' Lock the block to get a far pointer to this memory. 
    lpGlobalMemory = GlobalLock(hGlobalMemory) 

    ' Copy the string to this global memory. 
    lpGlobalMemory = lstrcpy(lpGlobalMemory, MyString) 

    ' Unlock the memory. 
    If GlobalUnlock(hGlobalMemory) <> 0 Then 
     MsgBox "Could not unlock memory location. Copy aborted." 
     'Debug.Print "GlobalFree returned: " & CStr(GlobalFree(hGlobalMemory)) 
     GoTo OutOfHere 
    End If 

    ' Open the Clipboard to copy data to. 
    If OpenClipboard(0&) = 0 Then 
     MsgBox "Could not open the Clipboard. Copy aborted." 
     Exit Sub 
    End If 

    ' Clear the Clipboard. 
    X = EmptyClipboard() 

    ' Copy the data to the Clipboard. 
    hClipMemory = SetClipboardData(CF_TEXT, hGlobalMemory) 

OutOfHere: 
    If CloseClipboard() = 0 Then 
     MsgBox "Could not close Clipboard." 
    End If 
End Sub 
+2

ли 'SetClipboardData()' вызова успеха? Если нет, что сообщает 'GetLastError()'? –

+0

Просто попробовал. Clipboard_SetData ("fjdkla; JFD") \ отладочный вывод: \ hGlobalMemory является 287253201176 \ lpGlobalMemory является 287450358016 \ lpGlobalMemory является 287362598488 \ hClipMemory является 287253201176 \ LastDLLError 0 \ Интересно, почему lstrcopy возвращает другой адрес, чем GlobalLock. Я исследовал страницу [lstrcopy API] (http://msdn.microsoft.com/en-us/library/windows/desktop/ms647490 (v = vs.85) .aspx), и Microsoft предупреждает нас не использовать ее. Интересно, отключена ли она какой-то функцией безопасности Windows 8. Кто-нибудь знает, как использовать [StringCchCopy] (http://bit.ly/15N1jBR) в VBA? – Baodad

+1

Указанный файл 'win32api_ptrsafe.txt 'теперь можно загрузить из «файлов справки Office 2010: Win32API_PtrSafe с поддержкой 64-разрядных версий» (http://www.microsoft.com/en-us/download/details.aspx?id=9970) –

ответ

9

ОК, я получил его сейчас ...

Вы должны изменить эту строку в версии кода:

Private Declare PtrSafe Function lstrcpy Lib "kernel32" (ByVal lpString1 As String, ByVal lpString2 As String) As LongPtr 

Для этого:

Private Declare PtrSafe Function lstrcpy Lib "kernel32" (ByVal lpString1 As Any, ByVal lpString2 As Any) As LongPtr 

Если вы пройдете через код, как и у вас, вы увидите, что значение lpGlobalMemory изменяется при вызове lstrcopy. Когда типы изменены на Any, значение остается неизменным.

Работает для меня на окнах 7. Надеюсь, это сработает для вас!

+0

Спасибо, это сработало: и я отмечаю, что вы используете указатель как тип возвращаемого значения, а не длинное целое число - на других сайтах используется код Long или LongLong, который будет работать нормально, пока это не произойдет. –

0

Используйте код в точности так, как показано здесь:

http://msdn.microsoft.com/en-us/library/office/ff192913.aspx

за исключением вставки PtrSafe после Объявляет для всех деклараций API.

Код должен быть в модуле сам по себе.

Как это:

Option Explicit 

Declare PtrSafe Function GlobalUnlock Lib "kernel32" (ByVal hMem As Long) _ 
    As Long 
Declare PtrSafe Function GlobalLock Lib "kernel32" (ByVal hMem As Long) _ 
    As Long 
Declare PtrSafe Function GlobalAlloc Lib "kernel32" (ByVal wFlags As Long, _ 
    ByVal dwBytes As Long) As Long 
Declare PtrSafe Function CloseClipboard Lib "User32"() As Long 
Declare PtrSafe Function OpenClipboard Lib "User32" (ByVal hwnd As Long) _ 
    As Long 
Declare PtrSafe Function EmptyClipboard Lib "User32"() As Long 
Declare PtrSafe Function lstrcpy Lib "kernel32" (ByVal lpString1 As Any, _ 
    ByVal lpString2 As Any) As Long 
Declare PtrSafe Function SetClipboardData Lib "User32" (ByVal wFormat _ 
    As Long, ByVal hMem As Long) As Long 

Public Const GHND = &H42 
Public Const CF_TEXT = 1 
Public Const MAXSIZE = 4096 

Function ClipBoard_SetData(MyString As String) 
    Dim hGlobalMemory As Long, lpGlobalMemory As Long 
    Dim hClipMemory As Long, X As Long 

    ' Allocate moveable global memory. 
    '------------------------------------------- 
    hGlobalMemory = GlobalAlloc(GHND, Len(MyString) + 1) 

    ' Lock the block to get a far pointer 
    ' to this memory. 
    lpGlobalMemory = GlobalLock(hGlobalMemory) 

    ' Copy the string to this global memory. 
    lpGlobalMemory = lstrcpy(lpGlobalMemory, MyString) 

    ' Unlock the memory. 
    If GlobalUnlock(hGlobalMemory) <> 0 Then 
     MsgBox "Could not unlock memory location. Copy aborted." 
     GoTo OutOfHere2 
    End If 

    ' Open the Clipboard to copy data to. 
    If OpenClipboard(0&) = 0 Then 
     MsgBox "Could not open the Clipboard. Copy aborted." 
     Exit Function 
    End If 

    ' Clear the Clipboard. 
    X = EmptyClipboard() 

    ' Copy the data to the Clipboard. 
    hClipMemory = SetClipboardData(CF_TEXT, hGlobalMemory) 

OutOfHere2: 

    If CloseClipboard() = 0 Then 
     MsgBox "Could not close Clipboard." 
    End If 

    End Function 
+0

Этот код не работа в 64-разрядном Excel 2013. Объявления API ядра32 не являются LongPtr. Это ошибки в GlobalUnlock. Мой код в основной части вопроса не является ошибкой, и API-интерфейсы объявлены для 64-разрядных. Но спасибо за попытку. – Baodad

6

Проводка полного кода для других. Протестировано и работает на 32 битных версиях Excel 2007, 2010, 2013, 2016 и 64 Bit Excel 2013 Все работает на Windows 10

'http://stackoverflow.com/questions/14738330/office-2013-excel-putinclipboard-is-different 
Option Explicit 
#If VBA7 Then 
    Declare PtrSafe Function GlobalUnlock Lib "kernel32" (ByVal hMem As LongPtr) As LongPtr 
    Declare PtrSafe Function GlobalLock Lib "kernel32" (ByVal hMem As LongPtr) As LongPtr 
    Declare PtrSafe Function GlobalAlloc Lib "kernel32" (ByVal wFlags As Long, ByVal dwBytes As LongPtr) As LongPtr 
    Declare PtrSafe Function CloseClipboard Lib "User32"() As Long 
    Declare PtrSafe Function OpenClipboard Lib "User32" (ByVal hwnd As LongPtr) As LongPtr 
    Declare PtrSafe Function EmptyClipboard Lib "User32"() As Long 
    Declare PtrSafe Function lstrcpy Lib "kernel32" (ByVal lpString1 As Any, ByVal lpString2 As Any) As LongPtr 
    Declare PtrSafe Function SetClipboardData Lib "User32" (ByVal wFormat As Long, ByVal hMem As LongPtr) As LongPtr 
#Else 
    Declare Function GlobalUnlock Lib "kernel32" (ByVal hMem As Long) As Long 
    Declare Function GlobalLock Lib "kernel32" (ByVal hMem As Long) As Long 
    Declare Function GlobalAlloc Lib "kernel32" (ByVal wFlags As Long, ByVal dwBytes As Long) As Long 
    Declare Function CloseClipboard Lib "User32"() As Long 
    Declare Function OpenClipboard Lib "User32" (ByVal hwnd As Long) As Long 
    Declare Function EmptyClipboard Lib "User32"() As Long 
    Declare Function lstrcpy Lib "kernel32" (ByVal lpString1 As Any, ByVal lpString2 As Any) As Long 
    Declare Function SetClipboardData Lib "User32" (ByVal wFormat As Long, ByVal hMem As Long) As Long 
#End If 

Public Const GHND = &H42 
Public Const CF_TEXT = 1 
Public Const MAXSIZE = 4096 

Function ClipBoard_SetData(MyString As String) 
    #If VBA7 Then 
     Dim hGlobalMemory As LongPtr, lpGlobalMemory As LongPtr, hClipMemory As LongPtr 
    #Else 
     Dim hGlobalMemory As Long, lpGlobalMemory As Long, hClipMemory As Long 
    #End If 
    Dim x As Long 
    ' Allocate moveable global memory. 
    '------------------------------------------- 
    hGlobalMemory = GlobalAlloc(GHND, Len(MyString) + 1) 

    ' Lock the block to get a far pointer 
    ' to this memory. 
    lpGlobalMemory = GlobalLock(hGlobalMemory) 

    ' Copy the string to this global memory. 
    lpGlobalMemory = lstrcpy(lpGlobalMemory, MyString) 

    ' Unlock the memory. 
    If GlobalUnlock(hGlobalMemory) <> 0 Then 
     MsgBox "Could not unlock memory location. Copy aborted. Please contact 14Fathoms." 
     GoTo OutOfHere2 
    End If 

    ' Open the Clipboard to copy data to. 
    If OpenClipboard(0&) = 0 Then 
     MsgBox "Could not open the Clipboard. Copy aborted. Please contact 14Fathoms." 
     Exit Function 
    End If 

    ' Clear the Clipboard. 
    x = EmptyClipboard() 

    ' Copy the data to the Clipboard. 
    hClipMemory = SetClipboardData(CF_TEXT, hGlobalMemory) 

OutOfHere2: 

    If CloseClipboard() = 0 Then 
     MsgBox "Could not close Clipboard. Please contact 14Fathoms." 
    End If 

End Function 
Sub TestCOPYPASTE() 
    Call ClipBoard_SetData("Hello World " & now()) 
    'Open notepad or in the immediate window and hit control-v 
End Sub 
Смежные вопросы