Forum > Windows
OpenOffice Automation with Win32 program
aAccord:
We have a program that sends a paste command to an already opened document in OpenOffice's Writer program to paste in some clipboard text. The core functionality is here:
--- Code: --- PROCEDURE PasteIntoWordProcessor ();
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;
--- End code ---
If we build a simple Forms-based application, this code works great to paste in text already in the Windows clipboard. Here is a sample app that works with a form with a single button on a form wired up to Button1Click:
--- Code: ---unit Unit1;
//{$mode objfpc}{$H+}
{$mode macpas}
interface
uses
Classes, SysUtils, FileUtil, Forms, Controls, Graphics, Dialogs, StdCtrls,
Comobj, Variants;
type
{ TForm1 }
TForm1 = class(TForm)
Button1: TButton;
procedure Button1Click(Sender: TObject);
private
{ private declarations }
public
{ public declarations }
end;
var
Form1: TForm1;
implementation
{$R *.lfm}
{ TForm1 }
procedure TForm1.Button1Click(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;
end.
--- End code ---
This code pastes and does not crash.
But our app is a Win32 app. So we build a pretty bare-bones Win32 app with the same calls in PasteIntoWordProcessor:
--- Code: ---program try2;
{$APPTYPE GUI}
USES
Interfaces, // this includes the LCL widgetset
Variants, ComObj, windows;
CONST
AppName = 'WinHello';
IDC_FILE_NEW = 3001;
IDC_FILE_EXIT = 3003;
VAR
mainMenu, fileMenu: HMENU;
m_Instance : HANDLE;
{$R mytry2.res}
PROCEDURE PasteIntoWordProcessor ();
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;
FUNCTION WindowProc(Window: HWnd; AMessage: UINT; WParam : WPARAM; theLParam: LPARAM): LRESULT; stdcall; export;
VAR
ps : PAINTSTRUCT;
wmId : integer;
BEGIN
CASE AMessage OF
WM_COMMAND:
BEGIN
wmId := LOWORD(wParam);
IF wmId = IDC_FILE_NEW THEN
BEGIN
PasteIntoWordProcessor; // FAILS HERE, AFTER SUCCESSFUL PASTE!!!
END
ELSE
WindowProc := DefWindowProc(Window, AMessage, WParam, theLParam);
END;
WM_PAINT:
BEGIN
BeginPaint(Window, @ps);
EndPaint(Window, @ps);
END;
WM_DESTROY:
BEGIN
PostQuitMessage(0);
Exit;
END;
END;
WindowProc := DefWindowProc(Window, AMessage, WParam, theLParam);
END;
FUNCTION WinRegister(className: LPSTR): Boolean;
VAR
WindowClass: WndClass;
BEGIN
WindowClass.Style := cs_hRedraw OR cs_vRedraw;
WindowClass.lpfnWndProc := WndProc(@WindowProc);
WindowClass.cbClsExtra := 0;
WindowClass.cbWndExtra := 0;
WindowClass.hInstance := m_Instance;
WindowClass.hIcon := 0;
WindowClass.hCursor := WINDOWS.LoadCursor(0, MAKEINTRESOURCE(32512));
WindowClass.hbrBackground := GetStockObject(WHITE_BRUSH);
WindowClass.lpszMenuName := NIL;
WindowClass.lpszClassName := className;
IF RegisterClass(@WindowClass) = 0 THEN
WinRegister:= false;
WinRegister:= TRUE;
END;
PROCEDURE updateMenu();
VAR
mi: MENUINFO;
mii: MENUITEMINFO;
BEGIN
mainMenu := CreateMenu();
mi.cbSize:= sizeof(MENUINFO);
mi.fMask:= MIM_STYLE;
fileMenu := CreatePopupMenu();
AppendMenu(fileMenu, MF_STRING, IDC_FILE_NEW, '&New'+#9+'Shift+N');
AppendMenu(fileMenu, MF_STRING, IDC_FILE_EXIT, 'Exit');
mii.cbSize:= sizeof(MENUITEMINFO);
mii.fMask:= MIIM_STRING or MIIM_ID or MIIM_SUBMENU;
mii.fType:= MFT_STRING;
mii.wID:= 0;
SetMenuInfo(mainMenu, @mi);
mii.hSubMenu:= fileMenu;
mii.dwTypeData:= LPSTR('&File');
WINDOWS.InsertMenuItem(mainMenu, 0, FALSE, mii);
END;
FUNCTION InitInstance(hInstance: HANDLE; nCmdShow: Integer): BOOLEAN;
VAR
myHwnd: HWND;
BEGIN
myHwnd := CreateWindow(AppName, AppName, WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, 0, mainMenu, hInstance, NIL);
IF myHwnd = 0 THEN
return FALSE;
ShowWindow(myHwnd, nCmdShow);
UpdateWindow(myHwnd);
return TRUE;
END;
VAR
AMessage: Msg;
BEGIN
m_Instance := HINSTANCE();
IF NOT WinRegister(AppName) THEN
BEGIN
MessageBox(0, 'Register App Name failed', nil, mb_Ok);
Exit;
END;
updateMenu();
IF NOT InitInstance(m_Instance, SW_SHOWNORMAL) THEN
Exit;
WHILE GetMessage(@AMessage, 0, 0, 0) DO
BEGIN
IF (NOT TranslateMDISysAccel(AMessage.hwnd, AMessage)) THEN
BEGIN
TranslateMessage(AMessage);
DispatchMessage(AMessage);
END;
END;
Halt(AMessage.wParam);
END.
--- End code ---
A bit more house-keeping, but the core function is the same. (Pick 'New' off the File menu to invoke the core call.)
With this Win32 code, the paste will actually occur, but then the Win32 app will crash.
Oddly, the automation we have set up for MS-Word works fine in our main Win32 program. Just OpenOffice Writer gives us this issue.
Can anyone explain why it would work so well with a Forms based app and not Win32? Or what we can do to make it work with Win32?
I hope I've provided enough code so that others can test these scenarios. It is a long post already, let me know if you need more details.
rvk:
I'm not sure if this is valid pascal:
--- Code: --- IF myHwnd = 0 THEN
return FALSE;
--- End code ---
But when changing it to "result := true/false" your example-program works correctly for me.
Lazarus 1.3 r46441 FPC 2.7.1 i386-win32
Windows 7 Ultimate with LibreOffice 4.2.5.2
Aaaah... just noticed the "{$mode macpas}" (which is NOT in your barebone app).
which provides the validation of your return true/false.
(You learn something new everyday ;))
Are you using the latest version of OpenOffice? (Did you try LibreOffice too?)
You say your app is a Win32 app... This could also be a Forms-based application. Is your Win32 app not form based??
Did you try that forms-based as 32bit ?
(What is your Lazarus/Fpc version and development OS ?)
aAccord:
Thanks for the reply! Yes, in Project, Options, the Parsing is set for Mac Pascal. As is our Win32 program.
We have not yet tried it with LibreOffice. The OpenOffice version is 4.1.1, which I believe is the most recent.
We have tried this with Laz 1.2.6 / FPC 2.6.4 (latest) an as old as Laz 1.1 / FPC 2.6.1 and the behaviors appear the same.
Our Win32 app is not forms based.
The first forms example is (2nd code example) is, unless I misnunderstand, a Win32 forms application, which does not crash for us. Only the pure Win32 non-forms app crashes. After pasting quite nicely. [Bang head on wall emoticon goes here.]
Development OS is Windows 8.1. (Two different machines for the newer / older Laz/FPC setups.)
I hope that helps answer the questions you were asking. Thanks again. Let me know if further info or clarification is needed.
Timewarp:
Cannot reproduce (I use fpc2.7.1)
But are these lines really needed / have you tested without?
--- Code: --- dispatcher:= unassigned;
desktop:= unassigned;
Server:= unassigned;
--- End code ---
aAccord:
Thanks for the reply.
--- Quote from: Timewarp on December 05, 2014, 06:22:36 pm ---Cannot reproduce (I use fpc2.7.1)
But are these lines really needed / have you tested without?
--- Code: --- dispatcher:= unassigned;
desktop:= unassigned;
Server:= unassigned;
--- End code ---
--- End quote ---
Interesting. This is the third code sample that is the pure Win32 app that you could not reproduce the crash?
Those lines are supposedly nice house-keeping. If anyone is interested, the corresponding OpenOffice thread on this (back when we thought it was purely an OpenOffice problem) is here:
https://forum.openoffice.org/en/forum/viewtopic.php?f=47&t=73866&sid=22be8c5b4a36214a658ca2059f0662da
and this is the post within that thread with the error and call stack info:
https://forum.openoffice.org/en/forum/viewtopic.php?f=47&t=73866&sid=22be8c5b4a36214a658ca2059f0662da#p333746
if that helps.
And we have tested without those unassigned lines with the same results.
Navigation
[0] Message Index
[#] Next page