VBA для предотвращения ввода с клавиатуры во время чтения объекта пакета (XML) в поток ADODB?

я разрабатываю приложение, которое открывает и читает XML-документ, ранее встроенный в презентацию PowerPoint, или документ Word. Чтобы прочитать этот объект (xmlFile as Object) Я должен сделать:

xmlFile.OLEFormat.DoVerb 1

это открывает объект пакета, и у меня есть другая подпрограмма, которая получает открытый экземпляр Notepad.exe и считывает его содержимое в поток ADODB.

пример этой процедуры доступен в Google Docs:

XML_Test.pptm.

во время этого процесса есть несколько секунд, где Блокнот.exe получает фокус, и непреднамеренное нажатие клавиши может привести к нежелательным результатам или ошибке чтения XML-данных.

Я ищу одну из двух вещей:

  1. либо метод для предотвращения непреднамеренного ввода пользователем (с помощью клавиатуры / мыши / etc) во время выполнения этой операции. Предпочтительно что-то, что делает не взять под контроль компьютер пользователя как MouseKeyboardTest подпрограмма, ниже. Или,
  2. лучший способ извлечения XML-данных в строковую переменную.

для #1: это функция, которую я нашел, которую я с подозрением использую. Я опасаюсь брать на себя такой контроль над системой пользователей. ##Есть ли другие методы, которые я мог бы использовать?##

Private Declare Function BlockInput Lib "USER32.dll" (ByVal fBlockIt As Long) As Long
Private Declare Sub Sleep Lib "kernel32" (ByVal dwMilliseconds As Long)

Sub MouseKeyboardTest() 'both keyboard and mouse blocked

    BlockInput True ' Turns off Keyboard and Mouse
'   Routine goes here
    Sleep 5000 ' Optional coding
    BlockInput False ' Turns on Keyboard and Mouse

End Sub

для #2: некоторый фон, но проблема, похоже, в неспособности чтобы надежно извлечь внедренный объект, используйте любой метод, кроме DoVerb 1. Поскольку я имею дело с несохраненным документом в приложении (блокноте), который невосприимчив к моему VBA skillz, это, похоже, единственный способ сделать это. Полный фон об этом, здесь:

извлечение OLEObject (XML-документ) из PowerPoint VBA

4 ответов


я понимаю, что у вас есть контроль над тем, как XML-файл внедряется в презентацию PowerPoint в первую очередь. Здесь я не совсем понимаю, почему вы решили сохранить необходимые вам данные как содержание встроенного объекта.

чтобы быть уверенным, задача получить это содержимое обратно не кусок пирога. На самом деле, пока нет (простого или даже умеренно сложного) способа вызова QueryInterface и использовать IPersist* интерфейсы от VBA, есть только один из способов добраться до содержимого встроенного объекта. Путь включает в себя следующие шаги:

  1. активация встроенного объекта. Вы использовали OLEFormat.DoVerb 1 для этого. Лучшим способом было бы позвонить OLEFormat.Activate, но это не имеет отношения к вашей конкретной проблеме.
  2. используйте модель программирования встроенного объекта для выполнения полезных операций, таких как получение содержимого, сохранение или что-либо еще. Notepad.exe не предоставляет такой модели программирования, и вы прибегли к WinAPI Это самый лучший выбор доступный.

к сожалению, Ваш текущий подход имеет по крайней мере 2 недостатка:

  1. тот, который вы определили в вопросе (активация notepad.exe водя к возможности взаимодействия потребителя).
  2. если у пользователя есть программа по умолчанию для открытия .txt файлы, кроме notepad.exe, ваш подход обречен.

если у вас есть контроль над тем, как создается внедренный объект, то лучшим подходом было бы хранить ваши XML-данные в каком-то свойстве


как вы правильно догадались, в комментарии выше, что принимая внимание от Блокнота решит вашу проблему. Приведенный ниже код делает именно это.

логика:

A. Петля через форму и получить его имя. В вашем случае это будет что-то вроде Chart Meta XML_fbc9775a-19ea-.txt

enter image description here

B. Используйте API, как FindWindow, GetWindowTextLength, GetWindow etc, чтобы получить ручку окна Блокнота, используя частичное надпись.

C. Используйте ShowWindow API для минимизации окна

код (протестирован в VBA-Powerpoint)

вставьте этот код в модуль в вышеуказанном PPTM

Private Declare Function FindWindow Lib "User32" Alias "FindWindowA" _
(ByVal lpClassName As String, ByVal lpWindowName As String) As Long

Private Declare Function GetWindowText Lib "User32" Alias "GetWindowTextA" _
(ByVal hWnd As Long, ByVal lpString As String, ByVal cch As Long) As Long

Private Declare Function GetWindowTextLength Lib "User32" Alias _
"GetWindowTextLengthA" (ByVal hWnd As Long) As Long

Private Declare Function GetWindow Lib "User32" (ByVal hWnd As Long, _
ByVal wCmd As Long) As Long

Private Declare Function ShowWindow Lib "User32" (ByVal hWnd As Long, _
ByVal nCmdShow As Long) As Long

Private Const GW_HWNDNEXT = 2
Private Const SW_SHOWMINIMIZED = 2

Sub Sample()
    Dim shp As Shape
    Dim winName As String
    Dim Ret As Long

    For Each shp In ActivePresentation.Slides(1).Shapes
        If shp.Type = msoEmbeddedOLEObject Then
            winName = shp.Name
            shp.OLEFormat.Activate
            Exit For
        End If
    Next

    If winName <> "" Then
        Wait 1

        If GetHwndFromCaption(Ret, Replace(winName, ".txt", "")) = True Then
           Call ShowWindow(Ret, SW_SHOWMINIMIZED)
        Else
            MsgBox "Window not found!", vbOKOnly + vbExclamation
        End If
    End If
End Sub

Private Function GetHwndFromCaption(ByRef lWnd As Long, ByVal sCaption As String) As Boolean
    Dim Ret As Long
    Dim sStr As String

    GetHwndFromCaption = False

    Ret = FindWindow(vbNullString, vbNullString)

    Do While Ret <> 0

        sStr = String(GetWindowTextLength(Ret) + 1, Chr$(0))
        GetWindowText Ret, sStr, Len(sStr)
        sStr = Left$(sStr, Len(sStr) - 1)
        If InStr(1, sStr, sCaption) > 0 Then
            GetHwndFromCaption = True
            lWnd = Ret
            Exit Do
        End If
        Ret = GetWindow(Ret, GW_HWNDNEXT)
    Loop
End Function

Private Sub Wait(ByVal nSec As Long)
    nSec = nSec + Timer
    While nSec > Timer
        DoEvents
    Wend
End Sub

Я не думаю, что блокировка пользователя является правильным подходом,

Если вы должны использовать содержимое окна блокнота, я бы предложил использовать метод sendkeys, чтобы отправить такую комбинацию:

SendKeys("^A^C")

что эквивалентно "выбрать все "и"копировать",

и затем вы можете продолжать работать "в автономном режиме" в буфере обмена, не опасаясь вмешательства нажатий клавиш.


Я добавляю:

Public Declare Function _
     ShowWindow& Lib "user32" (ByVal hwnd As Long, _
                        ByVal ncmdshow As Long)
Public Const SW_MINIMIZE = 6

и затем в