I am developing an application which opens and reads an XML document previously embedded in a PowerPoint presentation, or a Word document. In order to read this object (xmlFile as Object
) I have to do:
xmlFile.OLEFormat.DoVerb 1
This opens the package object, and I have another subroutine that gets the open instance of Notepad.exe, and reads its contents in to ADODB stream.
An example of this procedure is available on Google Docs:
During this process there is a few seconds window where the Notepad.exe gains focus, and an inadvertent keystroke may cause undesired results or error reading the XML data.
I am looking for one of two things:
- Either a method to prevent the user from inadvertently inputting (via keyboard/mouse/etc) while this operation is being performed. Preferably something that does not take control of the user's machine like
MouseKeyboardTest
subroutine, below. Or, - A better method of extracting the XML data into a string variable.
For #1: this is the function that I found, which I am leery of using. I am wary of taking this sort of control of the users system. ##Are there any other methods that I might use?##
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
For #2: Some background, but the issue seems to be the inability to extract the embedded object reliably using any method other than DoVerb 1
. Since I am dealing with an unsaved document in an application (Notepad) that is immune to my VBA skillz, this seems to be the only way to do this. Full background on that, here:
As you correctly guessed in the comment above that taking the focus away from notepad will solve your problem. The below code does exactly that.
LOGIC:
A. Loop through the shape and get it's name. In your scenario it would be something like
Chart Meta XML_fbc9775a-19ea-.txt
B. Use APIs like
FindWindow
,GetWindowTextLength
,GetWindow
etc to get the handle of the notepad window using partial caption.C. Use the
ShowWindow
API to minimize the windowCode (tested in VBA-Powerpoint)
Paste this code in a module in the above PPTM
I don't think that blocking the user is the right approach,
If you must use a content of a notepad window, I would suggest using the SendKeys method, in order to send this combination:
SendKeys("^A^C")
Which is the equivalent of "Select All" and "Copy",
And then you could continue working "offline" on the clipboard, without fear of interference by keystrokes.
My approach, per Sid's suggestion, was to find a way to minimize the Notepad.exe. Since I already found way to get that object and close it, I figured this should not be as hard.
I add these:
And then, in the
FindNotepad
function, right beforeExit Function
(so, after the Notepad has been found) I minimize the window with:My understanding is that you have control over how XML file gets embedded into PowerPoint presentation in the first place. Here I do not quite understand why you chose to keep the data you need as contents of an embedded object.
To be sure, the task of getting those contents back is not a piece of cake. Actually, as long as there is no (simple or even moderately difficult) way to call
QueryInterface
and useIPersist*
interfaces from VBA, there is just one way to get to contents of embedded object. The way involves following steps:OLEFormat.DoVerb 1
for that. A better way would be to callOLEFormat.Activate
, but this is irrelevant for your particular problem.Notepad.exe
exposes no such programming model, and you resorted toWinAPI
which is the best choice available.Unfortunately, your current approach has at least 2 flaws:
notepad.exe
leading to possibility of user's interference)..txt
files other thannotepad.exe
, your approach is doomed.If you do have control over how embedded object is created then better approach would be to store your XML data in some property of
Shape
object. I would useShape.AlternativeText
(very straightforward to use; shouldn't be used if you export your.pptm
to HTML or have some different scenario whereAlternativeText
matters) orShape.Tags
(this one is probably the most semantically correct for the task) for that.