Recent

Author Topic: OpenOffice Automation with Win32 program  (Read 13841 times)

aAccord

  • New Member
  • *
  • Posts: 10
OpenOffice Automation with Win32 program
« on: December 04, 2014, 11:32:03 pm »
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: [Select]
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;
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: [Select]
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.
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: [Select]
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.
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

  • Hero Member
  • *****
  • Posts: 4227
Re: OpenOffice Automation with Win32 program
« Reply #1 on: December 05, 2014, 10:43:20 am »
I'm not sure if this is valid pascal:
Code: [Select]
IF myHwnd = 0 THEN
     return FALSE;
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 ?)
« Last Edit: December 05, 2014, 10:45:00 am by rvk »

aAccord

  • New Member
  • *
  • Posts: 10
Re: OpenOffice Automation with Win32 program
« Reply #2 on: December 05, 2014, 05:34:36 pm »
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

  • Full Member
  • ***
  • Posts: 144
Re: OpenOffice Automation with Win32 program
« Reply #3 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: [Select]
  dispatcher:= unassigned;
  desktop:= unassigned;
  Server:= unassigned;

aAccord

  • New Member
  • *
  • Posts: 10
Re: OpenOffice Automation with Win32 program
« Reply #4 on: December 05, 2014, 06:43:45 pm »
Thanks for the reply.
Cannot reproduce (I use fpc2.7.1)

But are these lines really needed / have you tested without?
Code: [Select]
  dispatcher:= unassigned;
  desktop:= unassigned;
  Server:= unassigned;
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.

rvk

  • Hero Member
  • *****
  • Posts: 4227
Re: OpenOffice Automation with Win32 program
« Reply #5 on: December 05, 2014, 08:10:51 pm »
Did you test this with debugging on in the ide or stand alone app? (I tested it in the ide) If debugging is on which debugger do you use? Maybe a zip of your complete sample with settings could help us test this.

aAccord

  • New Member
  • *
  • Posts: 10
Re: OpenOffice Automation with Win32 program
« Reply #6 on: December 05, 2014, 08:24:27 pm »
Debugging within Lazarus and also outside the ide crashes for us. The debugger is whatever comes integrated with Lazarus, I think? (Not smart enough to know if there is a better answer to that.)

I tried attaching a zip here, but it didn't go through. Maybe too big? 3.84MB.

Thanks again.

rvk

  • Hero Member
  • *****
  • Posts: 4227
Re: OpenOffice Automation with Win32 program
« Reply #7 on: December 05, 2014, 11:37:35 pm »
I'm not sure why you have included a resource in your "bare-bone" win32 app. But since I don't have that resource I commented it out.
Code: [Select]
//{$R mytry2.res}
That's probably also the reason your zip is 3,84MB.

I can't reproduce your crash on either my work-machine or home-machine. Both Windows 7 Ultimate 64bit with Lazarus 1.3 FPC 2.7.1 i386-win32 and LibreOffice 4.2.5.2 and 4.1.0.4.

I even tried a very bare-bone version of a console app myself without any problems:
Code: [Select]
program try3;
uses
  Variants,
  ComObj,
  Windows;

  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;

begin
  PasteIntoWordProcessor();
end.
(no menus, gui's etc, just run it when a document open and something on the clipboard)

When this simple program also crashes we could try initializing the thread-system. You can do this with a dummy-thread which you wouldn't have to use. It's the only thing I can think of where your win32 bare-bone is different from a form-gui app.

Edit: Also no problems with OpenOffice 4.1.1 here. (needed to update my LibreOffice so I thought I'd give OpenOffice a try before re-installing the latest LibreOffice)
« Last Edit: December 05, 2014, 11:50:40 pm by rvk »

rvk

  • Hero Member
  • *****
  • Posts: 4227
Re: OpenOffice Automation with Win32 program
« Reply #8 on: December 06, 2014, 09:37:53 am »
Another thought that just popped into my head:
Shouldn't there be a CoInitialize (or CoInitializeEx) in there somewhere (and a corresponding CoUninitialize)?
(Or is that standard done in comobj initialization part?)
You could try adding then just to test and be sure.

aAccord

  • New Member
  • *
  • Posts: 10
Re: OpenOffice Automation with Win32 program
« Reply #9 on: December 08, 2014, 05:54:43 pm »
Thanks for the reply and help.

OK, I had a huge unit included before that was ballooning the project.  :-[

So a much smaller one is attached. I also had to delete the generated .res file to get it small enough to attach. Anyway, it has two different 'main()' branches, the fuller one is commented out:

Code: [Select]
BEGIN
CoInitialize(NIL);
PasteIntoWordProcessor;
CoUninitialize();
END.

//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.
All versions still crash for me. I haven't tried a console app yet, but I'll try that next. But the uncommented version is pretty close to what you had as your console app, I think.

I also added the CoInitialize stuff, which didn't help or hurt, as best I can tell. I did have to add ActiveX to the USES section to get CoInitialize to be recognized.

I'll go try a console app, but hopefully this attachment will help a bit.

aAccord

  • New Member
  • *
  • Posts: 10
Re: OpenOffice Automation with Win32 program
« Reply #10 on: December 08, 2014, 06:21:55 pm »
Console version worked. [Bang head on wall emoticon goes here.]

Code (more skeleton than required, but it worked) is attached.


rvk

  • Hero Member
  • *****
  • Posts: 4227
Re: OpenOffice Automation with Win32 program
« Reply #11 on: December 08, 2014, 06:30:20 pm »
Your try2 (project1.exe) gives an error here too.
Code: [Select]
Runtime error 217 at $004096D0
  $004096D0
  $00409929
  $00401A44  main,  line 125 of try2.lpr
  $0040E711

You say that the console app works but i see you used TCustomApplication (which would be essentially the same as Application). That's probably why it works. But it should also work in you other example (try2).

If i compile try2 it works correctly here (while your .exe version crashed). That leads me to believe it is a problem in your Lazarus version (or installation). (I use laz1.3/fpc 2.7.1)

Could you try 1 more thing... adding SysUtils to your uses in try2 project? It installs an exception handler.

Quote
217 Unhandled exception occurred
An exception occurred, and there was no exception handler present. The sysutils unit installs a default exception handler which catches all exceptions and exits gracefully.
« Last Edit: December 08, 2014, 06:32:00 pm by rvk »

aAccord

  • New Member
  • *
  • Posts: 10
Re: OpenOffice Automation with Win32 program
« Reply #12 on: December 08, 2014, 06:38:54 pm »
Yes with SysUtils and the fuller core code, I get 'RunError(217)' as you note.

I'll try it on my other Laz/FPC setup that is a bit newer than I have on this machine.

aAccord

  • New Member
  • *
  • Posts: 10
Re: OpenOffice Automation with Win32 program
« Reply #13 on: December 08, 2014, 06:46:32 pm »
I get the same failure on my 'other' machine. That one is Laz 1.2.6 / FPC 2.6.4. My main machine is Laz 1.1 / FPC 2.6.1.

I thought the Laz 1.2.6 / FPC 2.6.4 combo was the latest?!? Or it was a week or two ago when I put it on the 'other' machine.

Both of my machines are Win 8.1, if that matters.

Timewarp

  • Full Member
  • ***
  • Posts: 144
Re: OpenOffice Automation with Win32 program
« Reply #14 on: December 08, 2014, 07:01:06 pm »
Tested using same computer. It crashes 1.26/2.6.4, but works 1.3/2.7.1 -> Update.

 

TinyPortal © 2005-2018