I want to retrieve the name of the file opened by the user knowing that the Excel file was not opened by my Delphi application.
I tried :
EXCEL := TEXCELApplication.Create(Self);
Edit2.Text := EXCEL.ActiveWorkbook.FullName[lcid];
But this does not retrieve the file name with its path (File Path).
Do you have any idea how to do this?
Thank you
Microsoft documentation says that “Workbook.FullName property Returns the name of the object, including its path on disk”. I checked it on current version of excel – all works fine, maybe problem in older version? Anyway, there is other property to get filePath, you can combine it.
var EXCEL := TEXCELApplication.Create(Self);
try
EXCEL.Connect;
var FilePath := EXCEL.ActiveWorkbook.Path[0]; //C:\Users\user\Documents
var FileFullName := EXCEL.ActiveWorkbook.FullName[0]; //C:\Users\user\Documents\Auto.xlsx
ShowMessage(FilePath + sLineBreak + FileFullName);
EXCEL.Disconnect;
finally
excel.free;
end;
If FilePath is empty string – then file is not saved yet.
Related
Suppose to use the example CodeDownloadFiles.iss and I would like to move downloaded files from the Temporary Download folder. Well, I tried to use the function OnDownloadProgress but it seems that this code is performed before the download file effectively appears in the temp path:
procedure MoveTempFileDownloaded(FileName: String);
begin
FileCopy(ExpandConstant('{tmp}\' + FileName), ExpandConstant('{src}\storage\' + FileName), false);
DeleteFile(ExpandConstant('{tmp}\' + FileName));
end;
the upper procedure is that one should move the files (I have some heavy files) but when the following event will run, the current file will be the next one, so the file will be not copied.
function OnDownloadProgress(const Url, FileName: String; const Progress, ProgressMax: Int64): Boolean;
begin
if Progress = ProgressMax then
begin
MoveTempFileDownloaded(FileName);
end;
Result := True;
end;
In effect what I want to do is to store a list of Components files because if the user would reinstall the package will not need to re-download any files.
This is a sample of component that installer check before to run download:
FileName := 'MyDB1.sqlite';
ComponentIsSelected := CheckFileToDownload('https://example.com/MyFiles/'+FileName, FileName, 'Database\ABC');
if ComponentIsSelected = True then begin
DownloadPage.Add('https://example.com/MyFiles/'+FileName, FileName, '');
end;
at the beginning of the Inno file there is this function:
function CheckFileToDownload(const Url, FileName, ComponentName: String): Boolean;
begin
ComponentIsSelected := False;
if WizardIsComponentSelected(ComponentName) then begin
if FileExists(ExpandConstant('{src}\storage\'+FileName)) = False then begin
Inc(DownloadCount);
ComponentIsSelected := True;
end;
end;
end;
It will be easy in the [Files] to copy temporary files but my files are heavy I would not to get disk space problems. How could I copy a single downloaded file while they are perfectly downloaded?
By the way, I should perform the selection of Components with ExtraDiskSpaceRequired and get the size from the internet using DownloadTemporaryFileSize to increase the Disk Required, but I still have to do it, before I would solve this issue.
By the way, do you think is more simple to find a way to change the temporary temp folder location of downloaded files or to try to move files as I'm doing?
Thanks in advance for any suggestions
I read excel files using ADO and functions like below
procedure TForm1.ConnectToExcel;
var strConn : widestring;
begin
strConn:='Provider=Microsoft.Jet.OLEDB.4.0;' +
'Data Source=' + Edit1.Text + ';' +
'Extended Properties=Excel 8.0;';
AdoConnection1.Connected:=False;
AdoConnection1.ConnectionString:=strConn;
try
AdoConnection1.Open;
AdoConnection1.GetTableNames(ComboBox1.Items,True);
except
ShowMessage('Unable to connect to Excel, make sure the workbook ' + Edit1.Text + ' exist!');
raise;
end;
end;(*ConnectToExcel*)
procedure TForm1.FetchData;
begin
StatusBar1.SimpleText:='';
if not AdoConnection1.Connected then ConnectToExcel;
AdoQuery1.Close;
AdoQuery1.SQL.Text:='select * from' + SheetName;
try
AdoQuery1.Open;
except
ShowMessage('Unable to read data from Excel, make sure the query ' + SheetName + ' is meaningful!');
raise;
end;
end;
for several excel files this code worked quite well but now I try to open a new one with a strange error.
Inside the excel file the worksheet name is MYLIST, if i retrieve the list of Worksheet names i get the name MYLIST$ back. I can not open this worksheet even with MYLIST or MYLIST$. What might be the problem .
Microsoft Jet Engine does not allow "$" symbols in identifiers, only in built-in functions. If you use this symbol in your names, these identifiers should be quoted.
So try this:
select * from [MYLIST$]
I'm trying to make use of the TOpenDialog in order to pass the path to selected file to the AdoConection and load the content of the Excel file to the table. I'm currently attempting the code below but the last part of the code does not connect to the Excel returning an error:
[dcc32 Error] sample_map.pas(80): E2010 Incompatible types: 'string' and 'TOpenDialog'
procedure TForm1.Button1Click(Sender: TObject);
var
openDialog : TOpenDialog; // Open dialog variable
strConn : WideString; // Declare wide string for the connection
begin
// Create the open dialog object - assign to our open dialog variable
openDialog := TOpenDialog.Create(self);
// Set up the starting directory to be the current one
openDialog.InitialDir := GetCurrentDir;
// Only allow existing files to be selected
openDialog.Options := [ofFileMustExist];
// Allow only .dpr and .pas files to be selected
openDialog.Filter :=
'Excel 2003 and older|*.xls|Excel 2007 and older|*.xlsx';
// Select pascal files as the starting filter type
openDialog.FilterIndex := 2;
// Display the open file dialog
if openDialog.Execute
then ShowMessage('File : '+openDialog.FileName)
else ShowMessage('Open file was cancelled');
// Free up the dialog
openDialog.Free;
// Connect the Excel file
strConn:='Provider=Microsoft.Jet.OLEDB.4.0;' +
'Data Source=' + openDialog + ';' +
'Extended Properties=Excel 8.0;';
AdoConnection1.Connected:=False;
AdoConnection1.ConnectionString:=strConn;
end;
openDialog is an instance of a file dialog. It is not a string. You need to read the FileName property of the file dialog object like this:
openDialog.FileName
In fact you already use that in one of your ShowMessage calls.
Do make sure that you read this property before calling Free, a mistake present in the code in the question.
In fact you do need to get in to the habit of using try/finally to protect resources. Any time you create an instance of a class you need to make sure that it will be destroyed even in the face of an exception. In your code you need to write it like this:
openDialog := TOpenDialog.Create(self);
try
.... // use openDialog to let user choose file:
strConn := 'Provider=Microsoft.Jet.OLEDB.4.0;' +
'Data Source=' + openDialog.FileName + ';' +
'Extended Properties=Excel 8.0;';
finally
openDialog.Free; // executes no matter what, even if exception raised, etc.
end;
I also don't think you need to use WideString here. If you use a Unicode Delphi then you can use the native string type which is an alias for UnicodeString. If your Delphi is pre-Unicode, then you can also safely use string, an alias for AnsiString in that case. The literals you use are ASCII. The file dialog is an ANSI control and so openDialog.FileName is also ANSI. Nothing to be gained using WideString.
Finally, you are mixing up, all in one function, code to select a filename, and code to work on a database connection. It is better to separate concerns. Create a method that simply returns a filename, obtained by letting the user choose through a dialog. And add a method to work on the database connection, that is passed a filename as a parameter.
You need to get the OpenDialog.FileName prior to freeing the dialog:
OpenDialog := TOpenDialog.Create(nil);
try
// Set up the OpenDialog as before
// Display the open file dialog
if openDialog.Execute then
begin
strConn := 'Provider=Microsoft.Jet.OLEDB.4.0;' +
'Data Source=' + openDialog.FileName + ';' +
'Extended Properties=Excel 8.0;';
// Connect the Excel file
AdoConnection1.Connected:=False;
AdoConnection1.ConnectionString:=strConn;
else
ShowMessage('Open file was cancelled');
finally
// Free up the dialog
openDialog.Free;
end;
Of course, you're working much too hard. The Dialogs unit has a much easier way to do this using the PromptForFilename function, which eliminates the need to create and free the dialog entirely:
var
FileName: string;
begin
FileName := '';
if PromptForFileName(FileName, // Chosen filename holder
'Excel 2003 and older|*.xls|Excel 2007 and older|*.xlsx'; // Filter(s) (optional)
'.xlsx', // Default extension (opt)
'Choose file', // Dialog title (opt)
GetCurrentDir, // Initial dir (opt)
False) then // Is it a save dlg? (opt)
begin
strConn := 'Provider=Microsoft.Jet.OLEDB.4.0;' +
'Data Source=' + FileName + ';' +
'Extended Properties=Excel 8.0;';
// Connect the Excel file
AdoConnection1.Connected:=False;
AdoConnection1.ConnectionString:=strConn;
end
else
ShowMessage('Dialog cancelled.');
end;
As a side note, in case you don't know: You can select all Excel files (both .xls and .xlsx) with a single filter if you enter it as .xls*, as in Excel Files|*.xls*.
And, as David says, the best way would be to separate out the code that gets the filename and the code that does the connection as separate functions. Call the first to get the filename, and then pass that filename to the second to actually do the connecting if a filename is selected.
I am using Delphi 7 to generate CSV file from data acquired from COM port. Now, this seems to work OK since any other spreadsheet software reads generated file properly (Open Office and Libre Office spreadshhet software, for instance). Excel 2007 does the following. Instead of these two column values:
1.976139e-2<TAB>22.98027
i got these two column values:
1.98E+04<TAB>2.298.027
Note that generated file opened in any text editor (Notepad++ for instance) has proper values.
What could be the problem here ?
Thanks,
Josip
If the setting in Delphi do not fit your needs you could change them before loading the CSV. But you should make sure to reset them afterwards.
var
Excel, WorkBook: Variant;
KeepDecimalSeparator, KeepThousandsSeparator: String;
KeepUseSystem: Boolean;
begin
Excel := CreateOleObject('Excel.Application');
Excel.Visible := true;
try
KeepDecimalSeparator := Excel.DecimalSeparator;
KeepThousandsSeparator := Excel.ThousandsSeparator;
KeepUseSystem := Excel.UseSystemSeparators;
Excel.DecimalSeparator := '.';
Excel.ThousandsSeparator := ',';
Excel.UseSystemSeparators := false;
WorkBook := Excel.WorkBooks.Open('C:\Temp\1.csv');
finally
Excel.DecimalSeparator := KeepDecimalSeparator;
Excel.ThousandsSeparator := KeepThousandsSeparator;
Excel.UseSystemSeparators := KeepUseSystem;
end;
end;
Try to use quotes.
"1.976139e-2"<TAB>"22.98027"
System setup:
3-Tier environment
Client Machine - doesn't matter
Web-Tier - Not sure. Probably Windows Server 2008 64 bit
-Jdk 7u3
App Server - Windows Server 2008 64 bit
-Weblogic Server 10.3.6
-Excel 2010
-Jdk 7u3
Database Server - Not sure. Probably Windows Server 2008 64 bit.
-Oracle Database 11g
Programming using Oracle Forms 11.1.1.6
Now, my problem is that when we had designed they system, everything but the database was on one PC. I was able to read and write Excel documents no problem at all. Then we moved everything to a tiered setup where we had the client, app server and database server. Everything still worked great. Finally they set up the 3-tiered system and that's where I ran into my problems.
When I have Oracle Forms write to the Excel document the code appears to execute without any errors until I try to copy the file from the App Server using Webutil.
PROCEDURE Export_to_Excel IS
-- Declare the OLE objects
application OLE2.OBJ_TYPE;
workbooks OLE2.OBJ_TYPE;
workbook OLE2.OBJ_TYPE;
worksheets OLE2.OBJ_TYPE;
worksheet OLE2.OBJ_TYPE;
--cell OLE2.OBJ_TYPE;
range OLE2.OBJ_TYPE;
range_col OLE2.OBJ_TYPE;
-- Declare handles to OLE argument lists
args OLE2.LIST_TYPE;
p_filename VARCHAR(255);
--p_file TOOL_RES.RFHANDLE;
p_file Text_IO.File_Type;
p_filename_client VARCHAR2(500);
v_filename VARCHAR2(500);
v_error VARCHAR2(500);
passed_filename VARCHAR2(500);
BEGIN
-- Retrieve user specific directory to create new file in
p_filename := Webutil_file_transfer.get_work_area;
-- Start Excel
application:=OLE2.CREATE_OBJ('Excel.Application');
-- Return object handle to the Workbooks collection
workbooks:=OLE2.GET_OBJ_PROPERTY(application, 'Workbooks');
-- Add a new Workbook object to the Workbooks collection
workbook:=OLE2.GET_OBJ_PROPERTY(workbooks,'Add');
-- Return object handle to the Worksheets collection for the Workbook
worksheets:=OLE2.GET_OBJ_PROPERTY(workbook, 'Worksheets');
-- Set up the Header worksheet
args:=OLE2.CREATE_ARGLIST;
OLE2.ADD_ARG(args, 1);
worksheet:=OLE2.GET_OBJ_PROPERTY(worksheets,'Item',args);
OLE2.DESTROY_ARGLIST(args);
OLE2.set_property(worksheet,'Name','Header');
-- Build header form
populate_header(worksheet);
-- Autofit columns
range := OLE2.GET_OBJ_PROPERTY( worksheet,'UsedRange');
range_col := OLE2.GET_OBJ_PROPERTY( range,'Columns');
OLE2.INVOKE( range_col,'AutoFit' );
OLE2.RELEASE_OBJ( range );
OLE2.RELEASE_OBJ( range_col );
-- Set up the Item worksheet
args:=OLE2.CREATE_ARGLIST;
OLE2.ADD_ARG(args, 2);
worksheet:=OLE2.GET_OBJ_PROPERTY(worksheets,'Item',args);
OLE2.DESTROY_ARGLIST(args);
OLE2.set_property(worksheet,'Name','Item List');
-- Build Item sheet
populate_item_sheet(worksheet);
-- Delete the last worksheet that excel automatically creates
args:=OLE2.CREATE_ARGLIST;
OLE2.ADD_ARG(args, 3);
worksheet:=OLE2.GET_OBJ_PROPERTY(worksheets,'Item',args);
OLE2.DESTROY_ARGLIST(args);
OLE2.invoke(worksheet, 'Delete');
-- Save as worksheet
OLE2.SET_PROPERTY(application,'DisplayAlerts',FALSE);
IF p_filename is not null THEN
args := OLE2.CREATE_ARGLIST;
OLE2.ADD_ARG( args, p_filename || :PARAMETER_B1.FILENAME || '.xlsx');
OLE2.ADD_ARG( args, 56 );
OLE2.INVOKE( workbook,'SaveAs',args );
OLE2.DESTROY_ARGLIST( args );
END IF;
-- Close workbook
OLE2.INVOKE( workbook ,'Close');
-- Release the OLE objects
OLE2.RELEASE_OBJ(worksheet);
OLE2.RELEASE_OBJ(worksheets);
OLE2.RELEASE_OBJ(workbook);
OLE2.RELEASE_OBJ(workbooks);
OLE2.INVOKE(application, 'Quit');
OLE2.RELEASE_OBJ(application);
--Check if file was writen correctly
p_file := text_io.fopen(p_filename || :PARAMETER_B1.FILENAME || '.xlsx','r');
Text_IO.Fclose(p_file);
--Added the following code
passed_filename := :PARAMETER_B1.FILENAME || '.xlsx';
v_filename := p_filename || passed_filename;
-- Popup a dialog box to allow user to select the location to save the file
p_filename_client := CLIENT_GET_FILE_NAME ( 'C:\', passed_filename, NULL, 'Select A Directory', SAVE_FILE, FALSE );
if p_filename_client is null then
message ('Creation of the spreadsheet has been canceled.');
raise form_trigger_failure;
end if;
-- File Transfer to Client
PROCESS_COMM_FILE_CLIENT.FILE_TRANSFER('O', p_filename_client, v_filename, null, v_error);
EXCEPTION
WHEN others THEN
Text_IO.Fclose(p_file);
message( SQLERRM( SQLCODE ) ) ;
if p_filename_client is not null then
MESSAGE('An error occurred while creating file.');
end if;
END;
The code fails at the FILE_TRANSFER because the form does not get created on the App Server like it is supposed to.
A related problem that is occuring is that when I try to upload the excel document and read it in to oracle I get a ORA-305500 error. I have tried to have the DBA uninstall and reinstall Excel and made sure all of the features/add-ons were included during the installation but the problem still hasn't been fixed.
Could someone please give me some suggestions on what to do to fix this problem or continue to problem shoot this?
Thanks,
Bill
If the problem relates to the actual generation of the file using OLE, then I would sugest that you create the directory:
C:\Windows\System32\config\systemprofile
The OLE code in Oracle Forms checks in this directory for OLE configuration settings. It doesn't matter if the directory is empty, only that it exists!
Check your $ORACLE_HOME/forms/server/webutil.cfg, if there is any restriction in reading directories.
Basically, check the parameters "transfer.appsrv.read.<n>=/.../.../".
If I am understanding your problem, you intend to save the file in the client machine. Now assuming you are using WEB_FORMS (i.e. you use a web browser to access forms application), you can use the code below to save the file from AS to client machine, instead of PROCESS_COMM_FILE_CLIENT.FILE_TRANSFER. The OLE objects create the file at the AS, you need to get the file from AS (App server) to local machine-
l_success := webutil_file_transfer.AS_to_Client_with_progress
(clientFile => 'c:\fine.xlsx'
,serverFile => 'c:\data\file.xlsx'
,progressTitle => 'Save file in progress'
,progressSubTitle => 'Please wait');
if l_success then
message('File saved successfully');
else
message('Cannot save file');
end if;
The abve code should show a "Save file in progress" pop up box with progress bar to show that your file is being saved to local machine.