Page 1 of 1

[Solved] Paste into current document .uno:Paste

Posted: Mon Dec 01, 2014 11:25 pm
by sAccord
We are trying to do what we thought was a simple thing from a 3rd party app written in FreePascal using automation. Steps:
  • 1. We verify that OpenOffice SWriter is open.
    2. We load a bit of text into the Windows clipboard.
    3. Now we simply wish to execute a paste command into the current document.
The core of the current 'paste command' code looks like this:

Code: Select all

Server := CreateOleObject('com.sun.star.ServiceManager');
desktop := Server.createInstance('com.sun.star.frame.Desktop');
dispatcher := Server.createInstance('com.sun.star.frame.DispatchHelper');
dispatcher.executeDispatch(desktop.CurrentFrame, '.uno:Paste', '', 0, variantArray());
but our app crashes most of the time after the text is successfully pasted.

I have searched about and seen a thread that seems to warn against using dispatcher from a 3rd party app. Is this the problem?

What are the possible solutions?

Thanks in advance.

Re: Paste into current document .uno:Paste

Posted: Tue Dec 02, 2014 1:17 am
by kingfisher
If I understand you correctly, you can use paste in Writer to paste whatever is on the clipboard.

Re: Paste into current document .uno:Paste

Posted: Tue Dec 02, 2014 2:02 am
by sAccord
Yes, but we want to automate that paste from outside Writer.

Re: Paste into current document .uno:Paste

Posted: Tue Dec 02, 2014 8:48 am
by B Marcelly
From what you show it is impossible to find a possible error.
It is not clear that the crash is related to the paste or to something else in your code after the paste action.
We don't know if the same data can be pasted manually without error.
The document must be displayed (do not load it Hidden), and its window at front.

Re: Paste into current document .uno:Paste

Posted: Tue Dec 02, 2014 5:35 pm
by sAccord
The major question seems to revolve around using dispatcher from an outside application. See this post:

viewtopic.php?f=20&t=72229&p=324928&hil ... 27#p324928

that has the quote:
What you experience with .uno:PasteSpecial is normal. Dispatcher commands are intended for user interface, not for programming.
We are also running the same surrounding code and paste content with MS-Word with zero crashing problems. The data can be pasted without error. So it is unique to this small code section, and probably has to do with using (or how we are trying to use) dispatcher. If you want a larger section of code, here is the code in the procedure that also includes (in the first section) the code that is working just fine now with MS-Word.

Code: Select all

	BEGIN
		IF GetWordProcessorRunning(aName) THEN
		BEGIN
			IF (0 <> POS(aName, kWordDisplayName)) THEN
			BEGIN
				TRY
					Server := GetActiveOleObject('Word.Application');
					IF pasteMatchStyle THEN
						Server.ActiveDocument.Application.Selection.PasteSpecial(FALSE, FALSE, 0, FALSE, 2)
					ELSE
						Server.ActiveDocument.Application.Selection.Paste;
				EXCEPT
					return;
				END;
			END
			ELSE
			BEGIN
				IF (0 <> POS(aName, kSWriter)) THEN
				BEGIN
					TRY
						Server := CreateOleObject('com.sun.star.ServiceManager');
						desktop := Server.createInstance('com.sun.star.frame.Desktop');
						dispatcher := Server.createInstance('com.sun.star.frame.DispatchHelper');
						dispatcher.executeDispatch(desktop.CurrentFrame, '.uno:Paste', '', 0, variantArray());
					EXCEPT
						return;
					END;
				END
				ELSE

				BEGIN
					aWnd:= GetWordProcessorHandle;
					IF aWnd <> 0 THEN
						Send_CtrlV_ToAppHwnd(aWnd);
				END;
			END;
		END;
	END;
We are not loading the document. We are setting a Windows keyboard hook, so that the user can press a key combination in side Writer (or MS-Word, or Wordpad, or Notepad, or anything else) and our dialog pops up for the specialized text content we can serve up. We put their selection into the clipboard, and offer an option to press a button on the dialog that dismisses the dialog and automatically paste the content from the clipboard into the application.

This is very simple and has been working with MS-Word for some time now. We want to add support for Writer. Thus the question.

I should note that I also tried .uno:PageDialog as an alternative to paste and had problems. We also do not crash if I do not execute the dispatcher related calls. So I am given to think it is related to our use of dispatcher. Either in its use altogether, or in a blunder in how we used it. Which is why in the OP I asked:
I have searched about and seen a thread that seems to warn against using dispatcher from a 3rd party app. Is this the problem?

What are the possible solutions?
Is there another way to send a paste command into Writer?

Re: Paste into current document .uno:Paste

Posted: Tue Dec 02, 2014 7:10 pm
by B Marcelly
In the thread you cite, my remark on the Dispatcher is not about its reliability.
The problem was .uno:PasteSpecial, not .uno:Paste.
.uno:PasteSpecial always opens a dialog window that is supposed to be answered by the user. And the programmer did not want this.

The thread author said that .uno:Paste is not reliable. This is his opinion, not mine.

As a precaution, you may explicitly release your variables after paste, especially desktop and Server.

Code: Select all

dispatcher:= unassigned; desktop:= unassigned; Server:= unassigned;
I have done a VBScript code equivalent to your pasting code, and tested it on an opened Writer document.
I have copied a formatted text and even an image from elsewhere, then run the script. Absolutely no problem, paste works.

Re: Paste into current document .uno:Paste

Posted: Tue Dec 02, 2014 7:34 pm
by sAccord
Thank you for the reply and clarifications. I've implemented those releases:

Code: Select all

	IF (0 <> POS(aName, kSWriter)) THEN
				BEGIN
					TRY
						Server := CreateOleObject('com.sun.star.ServiceManager');
						desktop := Server.createInstance('com.sun.star.frame.Desktop');
						dispatcher := Server.createInstance('com.sun.star.frame.DispatchHelper');
						// dispatcher.executeDispatch(desktop.CurrentFrame, '.uno:Paste', '', 0, variantArray());
						dispatcher:= unassigned;
						desktop:= unassigned;
						Server:= unassigned;
					EXCEPT
						return;
					END;
				END
and with the commented out line above, it runs and does not crash. A manual paste in Writer pastes the material fine with no crash.

But if I uncomment the executeDispatch line, I get:
Project XYZ raised exception class 'External: SIGSEGV'.
At address 40DFC3
The call stack:

Code: Select all

fpc_reraise 
0040DF80 83ec04                   sub    $0x4,%esp
0040DF83 891c24                   mov    %ebx,(%esp)
0040DF86 8b1570a0b100             mov    0xb1a070,%edx
0040DF8C 85d2                     test   %edx,%edx
0040DF8E 7409                     je     0x40df99 <fpc_reraise+25>
0040DF90 a180aeb100               mov    0xb1ae80,%eax
0040DF95 ffd2                     call   *%edx
0040DF97 eb05                     jmp    0x40df9e <fpc_reraise+30>
0040DF99 b884aeb100               mov    $0xb1ae84,%eax
0040DF9E 8b18                     mov    (%eax),%ebx
0040DFA0 85db                     test   %ebx,%ebx
0040DFA2 7505                     jne    0x40dfa9 <fpc_reraise+41>
0040DFA4 e847fdffff               call   0x40dcf0 <SYSTEM_DOUNHANDLEDEXCEPTION>
0040DFA9 8b1570a0b100             mov    0xb1a070,%edx
0040DFAF 85d2                     test   %edx,%edx
0040DFB1 7409                     je     0x40dfbc <fpc_reraise+60>
0040DFB3 a190aeb100               mov    0xb1ae90,%eax
0040DFB8 ffd2                     call   *%edx
0040DFBA eb05                     jmp    0x40dfc1 <fpc_reraise+65>
0040DFBC b894aeb100               mov    $0xb1ae94,%eax
0040DFC1 8b00                     mov    (%eax),%eax
******0040DFC3 c7400c00000000           movl   $0x0,0xc(%eax)******
0040DFCA 8b03                     mov    (%ebx),%eax
0040DFCC ba01000000               mov    $0x1,%edx
0040DFD1 e86a1c0000               call   0x40fc40 <fpc_longjmp>
0040DFD6 8b1c24                   mov    (%esp),%ebx
0040DFD9 83c404                   add    $0x4,%esp
0040DFDC c3                       ret    
0040DFDD 0000                     add    %al,(%eax)
0040DFDF 00                       add    %al,0x1c8908ec(%ebx)
With the line in question decorated with asterisks, which sure does look a bit like a NULL pointer problem that happens somehow when FreePascal tries to reraise an exception.

I suppose I can try another Win32 development environment to keep as close to our FreePascal base. I'm open to other suggestions to get this to behave in FreePascal. Is the dispatcher + .uno:Paste the only way to initiate a paste outside of Writer?

Re: Paste into current document .uno:Paste

Posted: Tue Dec 02, 2014 10:14 pm
by B Marcelly
Are you sure that your variables are not used elsewhere ?

Otherwise, it looks like release of the variables happens before the dispatch action has finished. Wait some 200ms after the dispatch command ?
Is the dispatcher + .uno:Paste the only way to initiate a paste outside of Writer?
I don't know other solution.

Re: Paste into current document .uno:Paste

Posted: Tue Dec 02, 2014 10:29 pm
by sAccord
B Marcelly wrote:Are you sure that your variables are not used elsewhere ?
Yes, that is the whole function. The very top is that I clipped out is:

Code: Select all

	PROCEDURE PasteIntoWordProcessor (pasteMatchStyle: BOOLEAN);
		VAR
			Server, desktop, dispatcher: variant;
			aName: Str;
			aWnd: HWND;

	    FUNCTION variantArray(): Variant;
	    BEGIN
	      variantArray:= VarArrayCreate([0, -1], varVariant);
	    END;
B Marcelly wrote:Otherwise, it looks like release of the variables happens before the dispatch action has finished. Wait some 200ms after the dispatch command ?
Interesting. I tried this:

Code: Select all

IF (0 <> POS(aName, kSWriter)) THEN
				BEGIN
					TRY
						Server := CreateOleObject('com.sun.star.ServiceManager');
						desktop := Server.createInstance('com.sun.star.frame.Desktop');
						dispatcher := Server.createInstance('com.sun.star.frame.DispatchHelper');
						Sleep(300);
						dispatcher.executeDispatch(desktop.CurrentFrame, '.uno:Paste', '', 0, variantArray());
						Sleep(300);
						dispatcher:= unassigned;
						desktop:= unassigned;
						Server:= unassigned;
					EXCEPT
						return;
					END;
				END
and it still crashed in the same place. Unless I put them in the wrong places.
B Marcelly wrote:
Is the dispatcher + .uno:Paste the only way to initiate a paste outside of Writer?
I don't know other solution.

Re: Paste into current document .uno:Paste

Posted: Wed Dec 03, 2014 9:09 am
by B Marcelly
Works for me without a hitch.

Code: Select all

uses Variants;

procedure TForm1.Button2Click(Sender: TObject);
var
  Server, desktop, dispatcher: variant;

  FUNCTION variantArray(): Variant;
  BEGIN
    variantArray:= VarArrayCreate([0, -1], varVariant);
  END;

begin
  Server := CreateOleObject('com.sun.star.ServiceManager');
  desktop := Server.createInstance('com.sun.star.frame.Desktop');
  dispatcher := Server.createInstance('com.sun.star.frame.DispatchHelper');
  dispatcher.executeDispatch(desktop.CurrentFrame, '.uno:Paste', '', 0, variantArray());
  dispatcher:= unassigned;
  desktop:= unassigned;
  Server:= unassigned;
end;
Tested on Lazarus 32bits, version 1.2.6 containing FPC 2.6.4
MS-Windows 7 64bits Home SP1

Re: Paste into current document .uno:Paste

Posted: Wed Dec 03, 2014 6:35 pm
by sAccord
B Marcelly wrote:Works for me without a hitch.

Tested on Lazarus 32bits, version 1.2.6 containing FPC 2.6.4
MS-Windows 7 64bits Home SP1
Fascinating. We just built one outside our app doing this and it still fails every time. :crazy:

We thought compiling with MacPas might matter, but we crash with or without that compile option. I don't suppose you used any special compile options there?

We'll fiddle some more. I appreciate your help on this and after some more poking around, I'll post back.

Re: Paste into current document .uno:Paste

Posted: Mon Dec 08, 2014 10:31 pm
by sAccord
Update. Turns out there was a problem with the macpas compiler option in Laz/FPC that has already been fixed in a future release and there is a work-around. Thank you for the help trying to sort this out, and we'll be happily supporting OpenOffice with our app now. :D