I'm struggling with the following:
The goal is to parametrize an automation server for openoffice and I'm programming in Delphi.
The piece of basic code I want to translate into Delphi code is:
Dim aProps(1) As New com.sun.star.beans.PropertyValue
aProps(0).Name = "FilterName"
aProps(0).Value = "Text - txt - csv (StarCalc)"
aProps(1).Name = "FilterOptions"
aProps(1).Value = sFilterOptions
My attempt in Delphi looks like
type TPrmRecord = packed Record
Name : String;
Value : String;
End;
Var
ooParams:Variant;
MyData : TPrmRecord;
Begin
ooParams:= VarArrayCreate([0, 1], varVariant);
MyData.Name := 'FilterName';
MyData.Value := 'Text - txt - csv (StarCalc)';
ooParams[0] := MyData;
MyData.Name := 'FilterOptions';
MyData.Value := '59/44,34,ANSI,1,';
ooParams[1] := MyData;
End;
This is not working does anyone have a suggestion how to tackle this?
Your TPrmRecord type is not what OO.org expects. You should not try to write your own types, but use those that OO.org exposes.
There is an LPGL-licensed toolbox for Delphi: Delphi OOo. In it you will find a unit OOoTools.pas, which exports a function CreateUnoStruct(). Use this and pass 'com.sun.star.beans.PropertyValue' as the name of the struct. You will get a Variant (or an array of those, depending on the other parameter value) back that you can use instead of TPrmRecord (something like the following, untested):
var
Params: Variant;
begin
Params := CreateUnoStruct('com.sun.star.beans.PropertyValue', 1);
Params[0].Name := 'FilterName';
Params[0].Value := 'Text - txt - csv (StarCalc)';
Params[1].Name := 'FilterOptions';
Params[1].Value := '59/44,34,ANSI,1,';
end;
It looks as though you're missing the creation of the COM class, which would be the equivalent of the New com.sun.star.beans.PropertyValue line in your code.
I suspect you need to import the type library into Delphi which would give you the objects, properties and methods you need to emulate the Basic behaviour.
Here is straight Delphi code without using Delphi OOo:
uses comobj;
var
OO_ServiceManager: OleVariant;
FileParams: OleVariant;
begin
OO_ServiceManager := CreateOleObject ('com.sun.star.ServiceManager');
FileParams := VarArrayCreate([0, 1], varVariant);
FileParams[0] := OO_ServiceManager.Bridge_GetStruct('com.sun.star.beans.PropertyValue');
FileParams[0].Name := 'FilterName';
FileParams[0].Value := 'Text - txt - csv (StarCalc)';
FileParams[1] := OO_ServiceManager.Bridge_GetStruct('com.sun.star.beans.PropertyValue');
FileParams[1].Name := 'FilterOptions';
FileParams[1].Value := '59/44,34,ANSI,1,';
end;
Have a look at this Thread in the german Delphi-PRAXiS forums. There is a whole delphi Unit posted doing some OOo automation.
use
var
ooParams:array[0..1] of TPrmRecord;
delphi uses strict type-casting, so this is causing an assignment error.
Related
With many thanks to f.i. TLama I could set up a workaround for opening a file, replacing some fields and store the result to pdf using Delphi 2007. I have a document opened in OpenOffice like this:
FileParams := VarArrayCreate([0, 0], varVariant);
FileProperty := StarOffice.Bridge_GetStruct ('com.sun.star.beans.PropertyValue');
FileProperty.Name := 'Hidden';
FileProperty.Value := true;
FileParams[0] := FileProperty;
StarDocument := StarDesktop.LoadComponentFromURL(AFileURL, '_blank', 0, FileParams);
Where AFileURL is the full pathname starting with 'file:///'
Later I replace the fields in this document with the option I discovered elsewhere on this site:
FileReplace := StarDocument.CreateReplaceDescriptor;
FileReplace.SearchCaseSensitive := False;
FileReplace.SetSearchString(zoekstring);
FileReplace.SetReplaceString(vervang);
StarDocument.ReplaceAll(FileReplace);
And then store the document to pdf.
Actually the file is a doc-file simply copied to a file with extension odt.
Everything is working fine if I first load the document in OpenOffice and save as Openoffice odt-document, but I want to do that programmaticly.
So, before being able to replace the WORD-fields (like «11») I want to store the odt-file as a proper OpenOffice document, because like this Open Office does not recognize the fields to replace.
I tried:
if StarDocument.hasLocation then
try
StarDocument.Store();
except
showmessage('unable to save');
end;
Reading OpenOffice documentation gave me the idea that this might work, but it does not.
I also tried:
function CreateProperty(const AName: AnsiString; AValue: Variant): Variant;
begin
Result := StarOffice.Bridge_GetStruct('com.sun.star.beans.PropertyValue');
Result.Name := AName;
Result.Value := AValue;
end;
FilterParams := VarArrayCreate([0, 0], varVariant);
FilterParams[0] := CreateProperty('FilterName', 'Text');
StarDocument.StoreAsURL(AFileURL,FilterParams);
Does not work either. I get a Fatal Error from Open Office. Who knows what I am missing?
I am using OpenOffice Writer, and I wish to Print under Program control. However, I do not wish to print to the default printer, but rather direct certain documents to certain printers, according to the type of document I generate.
Using Bernard Marcelly's OOoTools library, for Delphi, to do OLE Automation, talking to OpenOffice, 4.0, the following code works to Print to the current printer,
procedure TMyOODocClass.Print;
var
docObj : variant; // Current OOo Document, implements IXPrintable
printProps : variant;
begin
docObj := GetMyActiveDocument; // method not shown, pretty standard stuff.
try
// empty array, I think this is where I would fill in PrinterName?
printProps := VarArrayCreate([0, -1], varVariant);
docObj.print(printProps);
except
on E:EOleException do
begin
raise Exception.Create('OpenOffice Document Print failed. '+E.Message);
end;
end;
end;
I am not able to locate the documentation for OpenOffice Writer Document Print method or the properties it supports, I think I am supposed to define some properties, something like this:
printProps := VarArrayCreate([0, 1], varVariant);
printProps[0] := MakePropertyValue('PrinterName', 'PrinterNameHere') ;
Question Part A, is there a thorough HTML online reference for all the properties that Print, and all other similar Document methods accept? And Part B, is what is the property or technique to set the above. I do believe that the Document objects in OO implement
an interface called IXPrintable, and so what I am wondering how to find is all the methods of IXPrintable, and what parameters or properties the Print method within that method, accepts.
Update Following the comment suggestion, I tried using a property named 'Name', like this:
procedure TMyOODocClass.PrintTo(PrinterName:String);
var
docObj : variant; // Current OOo Document, implements IXPrintable
printProps : variant;
begin
docObj := GetMyActiveDocument; // method not shown, pretty standard stuff.
try
if PrinterName='' then
printProps := dummyArray
else
begin
printProps := VarArrayCreate([0, 1], varVariant);
printProps[0] := MakePropertyValue('Name',PrinterName);
end;
docObj.print(printProps);
except
on E:EOleException do
begin
raise EOOoError.Create('OpenOffice Document Print failed. '+E.Message);
end;
end;
end;
The above does not work, so there must be something missing or wrong. I tried calling docObj.SetPrinter as well, but I get a parameter type mismatch error.
Okay I got it to work, the problem was I wasn't creating the Property values properly. Also I stupidly assumed that you pass the parameters to Print when what you do is call SetPrinter, with property Name set to printer name, then call Print, still with no parameters. The url linked by TLama clearly stated this, but I missed it initially, I think I need more coffee.
Also it seems that the Unicode VarType 258 (varUString) values are not particularly OLE Automation friendly, so I am explicitly using AnsiString in the code below.
uses
ComObj,
Classes,
SysUtils,
Dialogs,
Controls,
Windows,
oOoConstants,
OOoTools,
DB,
Variants,
StdCtrls,
Forms;
procedure TMyOODocClass.PrintTo(PrinterName:AnsiString);
var
docObj : variant; // Current OOo Document, implements IXPrintable
emptyProps, printProps: variant;
propName:AnsiString;
begin
docObj := GetMyActiveDocument; // method not shown, pretty standard stuff.
try
emptyProps := dummyArray;
if PrinterName <> '' then
begin
propName := 'Name';
printProps := createProperties( [propName,PrinterName] ); // OOTools helper
docObj.SetPrinter( printProps );
end;
docObj.print(emptyProps);
except
on E:EOleException do
begin
raise EOOoError.Create('OpenOffice Document Print failed. '+E.Message);
end;
end;
end;
A complete demo that compiles and runs is on bitbucket here as delphi_openoffice_demo01
1st off I am Still a little green to Delphi so this might be a "mundane detail" that's being over looked. [sorry in advance]
I have a need to create a TSQLDataset or TClientDataSet from an Oracle 11g cursor contained in a package. I am using Delphi XE2 and DBExpress to connect to the DB and DataSnap to send the data back to the client.
I'm having problems executing the stored procedure from the Delphi code.
Package Head:
create or replace
PACKAGE KP_DATASNAPTEST AS
procedure GetFaxData(abbr varchar2, Res out SYS_REFCURSOR);
END KP_DATASNAPTEST;
Package Body:
create or replace
PACKAGE body KP_DATASNAPTEST AS
procedure GetFaxData(abbr varchar2, Res out SYS_REFCURSOR)is
Begin
open Res for
SELECT Name,
Address1,
City,
fax_nbr
FROM name
JOIN phone on name.Abrv = phone.abrv
WHERE phone.fax_nbr is not null and name.abrv = abbr;
end;
END KP_DATASNAPTEST;
I have no problem executing this procedure in SQL Developer the problem resides in this code on the DataSnap server:
function TKPSnapMethods.getCDS_Data2(): OleVariant;
var
cds: TClientDataSet;
dsp: TDataSetProvider;
strProc: TSQLStoredProc;
begin
strProc := TSQLStoredProc.Create(self);
try
strProc.MaxBlobSize := -1;
strProc.SQLConnection:= SQLCon;//TSQLConnection
dsp := TDataSetProvider.Create(self);
try
dsp.ResolveToDataSet := True;
dsp.Exported := False;
dsp.DataSet := strProc;
cds := TClientDataSet.Create(self);
try
cds.DisableStringTrim := True;
cds.ReadOnly := True;
cds.SetProvider(dsp);
strProc.Close;
strProc.StoredProcName:= 'KP_DATASNAPTEST.GetFaxData';
strProc.ParamCheck:= true;
strProc.ParamByName('abbr').AsString:= 'ZZZTOP';
strProc.Open; //<--Error: Parameter 'Abbr' not found.
cds.Open;
Result := cds.Data;
finally
FreeAndNil(cds);
end;
finally
FreeAndNil(dsp);
end;
finally
FreeAndNil(strProc);
self.SQLCon.Close;
end;
end;
I have also tried assigning the param value through the ClientDataSet without any luck.
I would not be apposed to returning a TDataSet from the function if its easier or produces results. The data is used to populate custom object attributes.
As paulsm4 mentioned in this answer, Delphi doesn't care about getting stored procedure parameter descriptors, and so that you have to it by yourself. To get params of the Oracle stored procedure from a package, you can try to use the GetProcedureParams method to fill the list with parameter descriptors and with the LoadParamListItems procedure fill with that list Params collection. In code it might look like follows.
Please note, that following code was written just in browser according to documentation, so it's untested. And yes, about freeing ProcParams variable, this is done by the FreeProcParams procedure:
var
ProcParams: TList;
StoredProc: TSQLStoredProc;
...
begin
...
StoredProc.PackageName := 'KP_DATASNAPTEST';
StoredProc.StoredProcName := 'GetFaxData';
ProcParams := TList.Create;
try
GetProcedureParams('GetFaxData', 'KP_DATASNAPTEST', ProcParams);
LoadParamListItems(StoredProc.Params, ProcParams);
StoredProc.ParamByName('abbr').AsString := 'ZZZTOP';
StoredProc.Open;
finally
FreeProcParams(ProcParams);
end;
...
end;
I don't think Delphi will automagically recognize Oracle parameter names and fill them in for you. I think you need to add the parameters. For example:
with strProc.Params.Add do
begin
Name := 'abbr';
ParamType := ptInput;
Value := ZZZTOP';
...
end;
What is a new way to get current file that is being worked on in Experts for Delphi XE
Previously in Delphi 5-7 we used ToolServices.getCurrentFile
Perhaps the deprecated units ToolIntf, ExptIntf etc. are no longer working. You can use IOTAModuleServices.CurrentModule instead. Here's a quick example:
function GetCurrentEditorFileName: string;
var
Module: IOTAModule;
Editor: IOTAEditor;
begin
Result := '';
Module := (BorlandIDEServices as IOTAModuleServices).CurrentModule;
if Assigned(Module) then
begin
Editor := Module.CurrentEditor;
if Assigned(Editor) then
Result := Editor.FileName;
end;
end;
An alternate method is to pass the "name of file in the editor" to your tool as a parameter. $EDNAME
I use OLE method like this:
var
xlApp, xlWorkBook, xlWorkSheet, arr: Variant;
begin
xlApp := CreateOLEObject('Excel.Application');
xlApp.Visible := True;
end;
How to add a button to Excel?
And how to assign a exist marco on this button?
Where can I find Delphi-OLE-Office document?
Thx.
I worked this out by recording a VBA macro and then pasting it into your Delphi routine:
xlApp := CreateOLEObject('Excel.Application');
xlApp.Visible := True;
xlWorkBook := xlApp.Workbooks.Add;
xlWorkBook.ActiveSheet.Buttons.Add(10, 10, 80, 30).Select;
xlWorkBook.Selection.OnAction := 'Macro1';
There is no Delphi documentation of Office COM automation. You have to use the MSDN documentation and translate it into Delphi yourself.