Forum > Windows

OpenOffice Automation with Win32 program

(1/4) > >>

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

Go to full version