1

是否可以通过 C# 在 Powerpoint 插件中检测撤消/重做事件?或者是否可以访问已发生的事情或操纵撤消/重做列表?

我问是因为我没有看到任何允许这样做的东西,这让我感到惊讶,我期待它是可能的,所以我问主要是希望我错过了什么。

任何帮助将非常感激!

4

2 回答 2

3

遗憾的是,PPT 没有公开撤消列表,并且没有可以捕获的事件来让您知道撤消/重做何时发生。

我想可以实现自己的撤消堆栈,但这似乎是斯蒂芬金写小说的那种东西。;-)

于 2012-11-16T20:52:20.477 回答
0

我也在寻找 Ctrl+Z/Undo 的事件。Undo 功能的 idMso 控件是一个库,因此就通过 customUI 中的 a 重新调整用途而言,这是一个死胡同。没有内置的 Application.OnUndo 事件,我唯一能想到的另一件事是使用 WinAPI 连接到 PowerPoint 的 WindowProc 过程以检测 Ctrl+Z。我简单地尝试了一下,可以检测到该组合键,但我鄙视这种事情导致的不稳定性,导致 PowerPoint 在某些系统上可能崩溃,并且无法解决 macOS。如果有人想要改进它,这里是该技术的基础:

Option Explicit

Private Declare PtrSafe Function FindWindow Lib "user32" Alias "FindWindowA" (ByVal lpClassName As Any, ByVal lpWindowName As Any) As LongPtr
Private Declare PtrSafe Function GetActiveWindow Lib "user32" () As LongPtr
Private Declare PtrSafe Function RegisterHotKey Lib "user32" (ByVal hwnd As LongPtr, ByVal ID As Long, ByVal fsModifiers As Long, ByVal vk As Long) As Long
Private Declare PtrSafe Function UnregisterHotKey Lib "user32" (ByVal hwnd As LongPtr, ByVal ID As Long) As Long

Private Declare PtrSafe Function CallWindowProc Lib "user32" Alias "CallWindowProcA" ( _
                                        ByVal lpPrevWndFunc As LongPtr, _
                                        ByVal hwnd As LongPtr, _
                                        ByVal MSG As Long, _
                                        ByVal wParam As LongPtr, _
                                        ByVal lParam As LongPtr) As LongPtr
Public hWndPPT As LongPtr

Public Type POINTAPI
  x As Long
  y As Long
End Type

Public Type MSG
    hwnd As LongPtr
    Message As Long
    wParam As LongPtr
    lParam As LongPtr
    time As Long
    PT As POINTAPI
End Type

#If Win64 Then
   Private Declare PtrSafe Function SetWindowLongPtr Lib "user32" Alias "SetWindowLongPtrA" (ByVal hwnd As LongPtr, ByVal nIndex As Long, ByVal dwNewLong As LongPtr) As LongPtr
#Else
   Private Declare PtrSafe Function SetWindowLongPtr Lib "user32" Alias "SetWindowLongA" (ByVal hwnd As LongPtr, ByVal nIndex As Long, ByVal dwNewLong As LongPtr) As LongPtr
#End If

Private Const GWL_WNDPROC As Long = -4& ' Sets a new address for the window procedure

Private PrevWndFunc As LongPtr          ' Pointer to the initial window proc

Private Const WM_HOTKEY = &H312&        ' HotKey message

Private Const MOD_Control = 2           ' Either CTRL key

Public Sub RegisterCtrlZ()
    
    Dim returnedVal
    
    hWndPPT = GetPPThWnd
    
    returnedVal = RegisterHotKey(hwnd:=hWndPPT, ID:=1, fsModifiers:=MOD_Control, vk:=vbKeyZ)
    Debug.Print "RegisterHotKey returned " & returnedVal

    ' Set the window callback procedure
    PrevWndFunc = SetWindowLongPtr(hWndPPT, GWL_WNDPROC, AddressOf WindowProc)

End Sub

Public Sub UnregisterCtrlZ()
    
    Dim returnedVal

    hWndPPT = GetPPThWnd
    
    returnedVal = UnregisterHotKey(hwnd:=hWndPPT, ID:=1)
    Debug.Print "UnregisterHotKey returned " & returnedVal
    
    PrevWndFunc = SetWindowLongPtr(hWndPPT, GWL_WNDPROC, PrevWndFunc)
    
End Sub

Public Function WindowProc(ByVal hwnd As LongPtr, ByVal uMsg As Long, ByVal wParam As LongPtr, ByVal lParam As LongPtr) As LongPtr

    ' Check if a hotkey and the main PPT window is the active window
    If uMsg = WM_HOTKEY And GetActiveWindow = hWndPPT Then
        Debug.Print "Hotkey " & wParam & " event (Ctrl+Z)"
    End If
    
    ' Call the next window proc
    WindowProc = CallWindowProc(PrevWndFunc, hwnd, uMsg, wParam, lParam)
    
End Function

' Get the handle for the PowerPoint window
Public Function GetPPThWnd() As LongPtr

    Select Case Val(Application.Version)
        Case 8
            GetPPThWnd = FindWindow("PP97FrameClass", 0&)
        Case 9 To 12
            GetPPThWnd = FindWindow("PP" & Val(Application.Version) & "FrameClass", 0&)
        Case Else
            GetPPThWnd = FindWindow("PPTFrameClass", vbNullString)
    End Select
    
End Function
于 2021-12-21T20:40:44.360 回答