I'm using ExcelDocTypeUtils pkg for exporting Query data to EXCEL FILE.
When I run the procedure I'm getting a excel file, but when I try to open it this error pops out:
Program came up in the following areas during load: Style
The original line that I think that fails is:
-- Prepare Headers
owa_util.mime_header('application/vnd.ms-excel',FALSE);
I have already tried setting:
<?xml version="1.0" encoding="UTF-8"?>'
But when I do that, the error changes to the following:
Program came up in the following areas during load: 'Strict Parse Error'
Here is how I execute my procedure:
/* Starts */
execute employeereport;
CREATE OR REPLACE PROCEDURE employeeReport AS
v_sql_salary VARCHAR2(200) := 'SELECT last_name,first_name,salary FROM hr.employees ORDER BY last_name,first_name';
v_sql_contact VARCHAR2(200) := 'SELECT last_name,first_name,phone_number,email FROM hr.employees ORDER BY last_name,first_name';
v_sql_hiredate VARCHAR2(200) := 'SELECT last_name,first_name,to_char(hire_date,''MM/DD/YYYY'') hire_date FROM hr.employees ORDER BY last_name,first_name';
excelReport ExcelDocumentType := ExcelDocumentType();
v_worksheet_rec ExcelDocTypeUtils.T_WORKSHEET_DATA := NULL;
v_worksheet_array ExcelDocTypeUtils.WORKSHEET_TABLE := }
ExcelDocTypeUtils.WORKSHEET_TABLE();
documentArray ExcelDocumentLine := ExcelDocumentLine();
v_file UTL_FILE.FILE_TYPE;
BEGIN
-- Salary
v_worksheet_rec.query := v_sql_salary;
v_worksheet_rec.worksheet_name := 'Salaries';
v_worksheet_rec.col_count := 3;
v_worksheet_rec.col_width_list := '25,20,15';
v_worksheet_rec.col_header_list := 'Lastname,Firstname,Salary';
v_worksheet_array.EXTEND;
v_worksheet_array(v_worksheet_array.count) := v_worksheet_rec;
-- Contact
v_worksheet_rec.query := v_sql_contact;
v_worksheet_rec.worksheet_name := 'Contact_Info';
v_worksheet_rec.col_count := 4;
v_worksheet_rec.col_width_list := '25,20,20,25';
v_worksheet_rec.col_header_list := 'Lastname,Firstname,Phone,Email';
v_worksheet_array.EXTEND;
v_worksheet_array(v_worksheet_array.count) := v_worksheet_rec;
-- Contact
v_worksheet_rec.query := v_sql_hiredate;
v_worksheet_rec.worksheet_name := 'Hiredate';
v_worksheet_rec.col_count := 3;
v_worksheet_rec.col_width_list := '25,20,20';
v_worksheet_rec.col_header_list := 'Lastname,Firstname,Hiredate';
v_worksheet_array.EXTEND;
v_worksheet_array(v_worksheet_array.count) := v_worksheet_rec;
owa.num_cgi_vars := NVL(owa.num_cgi_vars, 0);
excelReport := ExcelDocTypeUtils.createExcelDocument(v_worksheet_array);
documentArray := excelReport.getDocumentData;
v_file := UTL_FILE.fopen('C:\','test.xml','W',4000);
FOR x IN 1 .. documentArray.COUNT LOOP
UTL_FILE.put_line(v_file,documentArray(x));
END LOOP;
UTL_FILE.fclose(v_file);
--excelReport.displayDocument;
END;
It's solved.
I don't know what did it, the only thing that I changed it's .xls extension instead of .xml
Thanks.
Related
function CreateLICStopServiceBatch(): boolean;
begin
Result := true;
fileName := ExpandConstant('{code:GetBasicDirectoryValue}\{code:GetInstance}\_Service\Stop_LIC_Service.bat');
SetArrayLength(lines, 3);
lines[0] := ExpandConstant('set wrapdir={code:GetBasicDirectoryValue}\{code:GetInstance}\_Service');
lines[1] := 'cd /d %wrapdir%';
lines[2] := ExpandConstant('commons-daemon\prunsrv.exe //SS//{code:GetLSDVBServiceNameTEdit}');
Result := SaveStringsToFile(filename,lines,false);
exit;
end;
CreateLICStopServiceBatch();
Right now I'm just writing the file in to the directory, doesn't matter if the file exist or not. But I want to check if the file exist (FileExists) and also have the opportunity to choose (in a dialog) overwrite or take the old file which already exist.
Use FileExists function to test for file existence.
See Inno Setup - Check if file exist in destination or else if doesn't abort the installation
Use MsgBox function for confirmation.
See Inno Setup: Conditionally delete non-empty directory in user's home folder
Side note: Do not use ExpandConstant('{code:Function}') is Pascal code. That makes no sense. Call Function directly. Not to mention that your functions probably do something trivial, which you can inline to your code anyway.
function CreateLICStopServiceBatch(): boolean;
var
FileName: string;
Lines: TArrayOfString;
begin
FileName := GetBasicDirectoryValue + '\' + GetInstance + '\_Service\Stop_LIC_Service.bat';
SetArrayLength(Lines, 3);
Lines[0] := 'set wrapdir=' + GetBasicDirectoryValue + '\' + GetInstance + '\_Service';
Lines[1] := 'cd /d %wrapdir%';
Lines[2] := 'commons-daemon\prunsrv.exe //SS//' + GetLSDVBServiceNameTEdit;
if (not FileExists(FileName)) or
(MsgBox('Overwrite?', mbConfirmation, MB_YESNO) = idYes) then
begin
Result := SaveStringsToFile(FileName, Lines, False);
end
else
begin
{ Not sure what you want to return when user does not confirm overwrite }
Result := False;
end;
end;
I want to load text from an external INI file to a TRichEditViewer, but I don't know how.
Here is my code so far (see CH_toolbar.RTFText):
{CH_toolbar}
CH_toolbar := TRichEditViewer.Create(SPPage);
CH_toolbar.Parent := SPPage.Surface;
CH_toolbar.Left := ScaleX(0);
CH_toolbar.Top := Title.Top + Title.Height + 10 ;
CH_toolbar.Width := ScaleX(480);
CH_toolbar.Height := ScaleY(80);
CH_toolbar.TabOrder := 1;
CH_toolbar.Font.Name := 'Verdana';
CH_toolbar.Color := -16777211;
CH_toolbar.ScrollBars := ssVertical;
CH_toolbar.RTFText := ExpandConstant(#ReadIni("setupPages", "setupValues", "SPEulatext", "")) ;
How do I insertSPEulatext value in CH_toolbar.RTFText?
#ReadIni is executed at compile time so it inserts a very long (unquoted) string literal.
If you want to load it at run time, use the GetIniString() function:
CH_toolbar.RTFText := GetIniString('setupValues', 'SPEulatext', '', 'setupPages');
(setupPages is the file name in both cases)
Note that Ini strings have a limited length and can't contain new line characters so an INI file is probably a bad choice for this.
Alternatively, you can load an RTF or text file directly:
ExtractTemporaryFile('lgpl-3.0.txt');
LoadStringFromFile(ExpandConstant('{tmp}/lgpl-3.0.txt'), LGPLText);
LGPLPage.RichEditViewer.RTFText := LGPLText;
I have a list of strings and the values they are to be replaced with. I'm trying to combine them in a list like 'O'='0',' .'='.', ... so it's easy for me to edit it and add more pairs of replacements to make.
Right now the best way I could think of it is:
var
ListaLimpeza : TStringList;
begin
ListaLimpeza := TStringList.Create;
ListaLimpeza.Delimiter := '|';
ListaLimpeza.QuoteChar := '"';
ListaLimpeza.DelimitedText := 'O=0 | " .=."';
ShowMessage('1o Valor = '+ListaLimpeza.Names[1]+' e 2o Valor = '+ListaLimpeza.ValueFromIndex[1]);
This works, but it's not good for visuals, since I can't code the before string (for ex ' .') like that (which is very visual for the SPACE character), only like (" .) so that the = works to assign a name and value in the TStringList.
The Names and Values by default have to be separated by =, in the style of Windows INI files. There's no way AFAICT to change that separator. As #SirRufo indicates in the comment (and which I had never noticed), you can change that using the TStringList.NameValueSeparator property.
This will give you an idea of what Delphi thinks is in your TStringList, which is not what you think it is:
procedure TForm1.FormCreate(Sender: TObject);
var
SL: TStringList;
Temp: string;
i: Integer;
begin
SL := TStringList.Create;
SL.Delimiter := '|';
SL.QuoteChar := '"';
SL.StrictDelimiter := True;
SL.DelimitedText := 'O=0 | ! .!=!.!';
Temp := 'Count: ' + IntToStr(SL.Count) + #13;
for i := 0 to SL.Count - 1 do
Temp := Temp + Format('Name: %s Value: %s'#13,
[SL.Names[i], SL.ValueFromIndex[i]]);
ShowMessage(Temp);
end;
This produces this output:
TStringList Names/Values probably isn't going to do what you need. It's not clear what your actual goal is, but it appears that a simple text file with a simple list of text|replacement and plain parsing of that file would work, and you can easily use TStringList to read/write from that file, but I don't see any way to do the parsing easily except to do it yourself. You could use an array to store the pairs when you parse them:
type
TReplacePair = record
TextValue: string;
ReplaceValue: string;
end;
TReplacePairs = array of TReplacePair;
function GetReplacementPairs: TReplacePairs;
var
ConfigInfo: TStringList;
i, Split: Integer;
begin
ConfigInfo := TStringList.Create;
try
ConfigInfo.LoadFromFile('ReplacementPairs.txt');
SetLength(Result, ConfigInfo.Count);
for i := 0 to ConfigInfo.Count - 1 do
begin
Split := Pos('|`, ConfigInfo[i];
Result[i].TextValue := Copy(ConfigInfo[i], 1, Split - 1);
Result[i].ReplaceValue := Copy(ConfigInfo[i], Split + 1, MaxInt);
end;
finally
ConfigInfo.Free;
end;
end;
You can then populate whatever controls you need to edit/add/delete the replacement pairs, and just reverse the read operation to write them back out to save.
I use cxGrid and I want import a excel file to cxgrid. I wrote this code a function.
But, its wrong, because cxGrid dont know RowCount and ColCount.
I would like know, what can I use, what is similar?
Help me!
Thank you!
function Xls_To_cxGrid(AGrid: TcxGrid; AXLSFile: string): Boolean;
const
xlCellTypeLastCell = $0000000B;
var
XLApp, Sheet: OLEVariant;
RangeMatrix: Variant;
x, y, k, r: Integer;
begin
Result := False;
XLApp := CreateOleObject('Excel.Application');
try
XLApp.Visible := False;
XLApp.Workbooks.Open(AXLSFile);
Sheet := XLApp.Workbooks[ExtractFileName(AXLSFile)].WorkSheets[1];
Sheet.Cells.SpecialCells(xlCellTypeLastCell, EmptyParam).Activate;
x := XLApp.ActiveCell.Row;
y := XLApp.ActiveCell.Column;
AGrid.RowCount := x;
AGrid.ColCount := y;
RangeMatrix := XLApp.Range['A1', XLApp.Cells.Item[X, Y]].Value;
k := 1;
repeat
for r := 1 to y do
AGrid.Cells[(r - 1), (k - 1)] := RangeMatrix[K, R];
Inc(k, 1);
AGrid.RowCount := k + 1;
until k > x;
RangeMatrix := Unassigned;
finally
if not VarIsEmpty(XLApp) then
begin
XLApp.Quit;
XLAPP := Unassigned;
Sheet := Unassigned;
Result := True;
end;
end;
end;
The cxGrid is just a container for ChartViews, TableViews, CardViews and BandedTableViews. Being a container, it does not know anything about rows and columns. Because you want to replace a StringGrid I suggest using a (non-DB) TableView.
To get a TableView...
...open the grid customization form (click on "Customize..." in the grid's "Structure Navigator" in the form designer).
Go to the "Views" tab and click "Add View...". Choose "Table" (not "DB Table"!).
On the "Structure" tab right-click on the cxGrid1Level1 symbol, choose "Select View" and the new TableView.
You can now go back to the "Views" tab and delete the DB TableView (cxGrid1DBTableView1).
(See also the DX help topic "Grid Levels" unter the heading "Specifying Associated Grid Views".)
Instead of "RowCount" you would then use YourView.DataController.RecordCount. "ColCount" would be YourView.ColumnCount. You can access cell values with YourView.DataController.Values[...]. To speed up the populating the view I'd surround it with
YourView.DataController.BeginUpdate;
try
YourView.DataController.RecordCount := x;
// ...
finally
YourView.DataController.EndUpdate;
end;
How to tell InnoSetup to not uninstall (text) files which had been changed by the user (== are different from those installed by InnoSetup)?
Or maybe more difficult: when installing a new version over an existing, InnoSetup should ask the user whether to overwrite the changed file, but on a pure uninstall, it should uninstall it without asking.
I recently had a similar problem. This was my solution to detect if a text file (profile) has been changed from the one installed during the last installation run:
Use ISPP (Inno Setup Pre-Processor) to create the list of text files and their hashes at compile time:
[Files]
; ...
#define FindHandle
#define FindResult
#define Mask "Profiles\*.ini"
#sub ProcessFoundFile
#define FileName "Profiles\" + FindGetFileName(FindHandle)
#define FileMd5 GetMd5OfFile(FileName)
Source: {#FileName}; DestDir: {app}\Profiles; Components: profiles; \
Check: ProfileCheck('{#FileMd5}'); AfterInstall: ProfileAfterInstall('{#FileMd5}');
#endsub
#for {FindHandle = FindResult = FindFirst(Mask, 0); FindResult; FindResult = FindNext(FindHandle)} ProcessFoundFile
At the top of the "Code" section I define some useful things:
[Code]
var
PreviousDataCache : tStringList;
function InitializeSetup() : boolean;
begin
// Initialize global variable
PreviousDataCache := tStringList.Create();
result := TRUE;
end;
function BoolToStr( Value : boolean ) : string;
begin
if ( not Value ) then
result := 'false'
else
result := 'true';
end;
In the "Check" event handler I compare the hashes of previous install and current file:
function ProfileCheck( FileMd5 : string ) : boolean;
var
TargetFileName, TargetFileMd5, PreviousFileMd5 : string;
r : integer;
begin
result := FALSE;
TargetFileName := ExpandConstant(CurrentFileName());
Log('Running check procedure for file: ' + TargetFileName);
if not FileExists(TargetFileName) then
begin
Log('Check result: Target file does not exist yet.');
result := TRUE;
exit;
end;
try
TargetFileMd5 := GetMd5OfFile(TargetFileName);
except
TargetFileMd5 := '(error)';
end;
if ( CompareText(TargetFileMd5, FileMd5) = 0 ) then
begin
Log('Check result: Target matches file from setup.');
result := TRUE;
exit;
end;
PreviousFileMd5 := GetPreviousData(ExtractFileName(TargetFileName), '');
if ( PreviousFileMd5 = '' ) then
begin
r := MsgBox(TargetFileName + #10#10 +
'The existing file is different from the one Setup is trying to install. ' +
'It is recommended that you keep the existing file.' + #10#10 +
'Do you want to keep the existing file?', mbConfirmation, MB_YESNO);
result := (r = idNo);
Log('Check result: ' + BoolToStr(result));
end
else if ( CompareText(PreviousFileMd5, TargetFileMd5) <> 0 ) then
begin
r := MsgBox(TargetFileName + #10#10 +
'The existing file has been modified since the last run of Setup. ' +
'It is recommended that you keep the existing file.' + #10#10 +
'Do you want to keep the existing file?', mbConfirmation, MB_YESNO);
result := (r = idNo);
Log('Check result: ' + BoolToStr(result));
end
else
begin
Log('Check result: Existing target has no local modifications.');
result := TRUE;
end;
end;
In the "AfterInstall" event handler I mark the file hash to be stored in
Registry later. Because in my tests the event was triggered even if the file move failed (target file is read-only) I compare the hash again to find out if the file move was successful:
procedure ProfileAfterInstall( FileMd5 : string );
var
TargetFileName, TargetFileMd5 : string;
begin
TargetFileName := ExpandConstant(CurrentFileName());
try
TargetFileMd5 := GetMd5OfFile(TargetFileName);
except
TargetFileMd5 := '(error)';
end;
if ( CompareText(TargetFileMd5, FileMd5) = 0 ) then
begin
Log('Storing hash of installed file: ' + TargetFileName);
PreviousDataCache.Add(ExtractFileName(TargetFileName) + '=' + FileMd5);
end;
end;
procedure RegisterPreviousData( PreviousDataKey : integer );
var
Name, Value : string;
i, n : integer;
begin
for i := 0 to PreviousDataCache.Count-1 do
begin
Value := PreviousDataCache.Strings[i];
n := Pos('=', Value);
if ( n > 0 ) then
begin
Name := Copy(Value, 1, n-1);
Value := Copy(Value, n+1, MaxInt);
SetPreviousData(PreviousDataKey, Name, Value);
end;
end;
end;
Inno can't do this check natively.
To not replace changed files during install, you'll need to use custom [Code] to do a checksum and compare against a known good value that is precomputed or saved from the previous install.
To avoid removing them during uninstall, you'll need to disable Inno's own uninstall for that file and check against the same checksum before removing them, again in [Code].
Note that it's better to keep any files the user can edit outside of the setup to handle this situation better and to correctly adhere to the application guidelines.