I installed the package DEXIF and am able to read some EXIF-Entries. But not computed values as described in the documentation.
The following code shows what works. For the commented lines I get the Error: identifier idents no member "focalLenght" and so on..
How can I get hold on these and more fields?
procedure TForm1.EXIFAnzeigen(filename: string);
var
ImgData: TImgData;
i :integer;
begin
//EDitor leeren
ValueListEditor1.Strings.Clear;
if FileExists(filename) then begin
ImgData:= TImgData.Create();
ImgData.Tracelevel :=1;
try
if uppercase(ExtractFileExt(filename)) = '.JPG' then begin
if ImgData.ProcessFile(filename) then begin
if ImgData.HasEXIF then begin
ValueListEditor1.InsertRow('Camera Make',
ImgData.ExifObj.CameraMake,True);
ValueListEditor1.InsertRow('Camera Modell',
ImgData.ExifObj.CameraModel,True);
ValueListEditor1.InsertRow('Picture DateTime',
FormatDateTime(ISO_DATETIME_FORMAT, ImgData.ExifObj.GetImgDateTime),True);
ValueListEditor1.InsertRow('Width',
inttostr(ImgData.ExifObj.Width),True);
ValueListEditor1.InsertRow('FlashUsed',
intToStr(ImgData.ExifObj.FlashUsed),True);
// ValueListEditor1.InsertRow('FocalLength',
// inttostr(ImgData.ExifObj.FocalLength),True);
// ValueListEditor1.InsertRow('ApertureFNumber',
// ImgData.ExifObj.ApertureFNumber,True);
// ValueListEditor1.InsertRow('ExposureTime',
// ImgData.ExifObj.ExposureTime,True);
// ValueListEditor1.InsertRow('Distance',
// ImgData.ExifObj.Distance,True);
// ValueListEditor1.InsertRow('Process',
// ImgData.ExifObj.Process,True);
end else begin
ValueListEditor1.InsertRow('No EXIF','No Data',True);
end;
end else begin
ValueListEditor1.InsertRow('No EXIF','Processdata',True);
end;
end else begin
ValueListEditor1.Strings.Clear;
end;
finally
ImgData.Free;
end;
end;
end;
The documentation says:
Some of the more common fields are accessible as properties of the
EXIFObj of the ImgData.
and shows an example reading those properties, partly same as you succeed to read with your code.
But the FocalLength, and the others that fail in your code, have to be accessed in another way as the document says:
Other EXIF field can be read by using the property TagValue and
specifying the name of the EXIF property
The following example clarifies:
ValueListEditor1.InsertRow('FocalLength',
inttostr(ImgData.ExifObj.TagValue['FocalLength']),True);
Related
Can some one please help me to let me know how to call a oracle subroutine in Perl script
I have a procedure already existing in oracle db. Say below
Case 1) return a ref cursor and accept a IN parameter.
CREATE OR REPLACE PROCEDURE procCursorExample(
cursorParam OUT SYS_REFCURSOR, userNameParam IN VARCHAR2)
IS
BEGIN
OPEN cursorParam FOR
SELECT * FROM DBUSER WHERE USERNAME = userNameParam;
END;
In SQL developer i can then execute it directly:
DECLARE
dbUserCursor SYS_REFCURSOR;
dbUserTable DBUSER%ROWTYPE;
BEGIN
procCursorExample(dbUserCursor,'mkyong');
LOOP
FETCH dbUserCursor INTO dbUserTable;
EXIT WHEN dbUserCursor%NOTFOUND;
dbms_output.put_line(dbUserTable.user_id);
END LOOP;
CLOSE dbUserCursor;
END;
Can some tell me how to invoke subroutine with argument through Perl script
Anwser
#!/usr/bin/perl
use warnings ;
use strict ;
use DBI;
print "Connecting to DB..";
my $dbh = DBI->connect('dbi:Oracle:xe', 'scott', 'tiger') or
die "Cannot connect to DB => " . DBI->errstr;
# prepare ????????
am not sure about prepare statement. Any help is highly appreciable.
Please read the documentation examples for calling stored procedures in Perl with DBD::Oracle, which is the driver you are using.
From this link specifically:
use DBI;
my($db, $csr, $ret_val);
$db = DBI->connect('dbi:Oracle:database','user','password')
or die "Unable to connect: $DBI::errstr";
# So we don't have to check every DBI call we set RaiseError.
# See the DBI docs now if you're not familiar with RaiseError.
$db->{RaiseError} = 1;
# Example 1 Eric Bartley <bartley#cc.purdue.edu>
#
# Calling a PLSQL procedure that takes no parameters. This shows you the
# basic's of what you need to execute a PLSQL procedure. Just wrap your
# procedure call in a BEGIN END; block just like you'd do in SQL*Plus.
#
# p.s. If you've used SQL*Plus's exec command all it does is wrap the
# command in a BEGIN END; block for you.
$csr = $db->prepare(q{
BEGIN
PLSQL_EXAMPLE.PROC_NP;
END;
});
$csr->execute;
# Example 2 Eric Bartley <bartley#cc.purdue.edu>
#
# Now we call a procedure that has 1 IN parameter. Here we use bind_param
# to bind out parameter to the prepared statement just like you might
# do for an INSERT, UPDATE, DELETE, or SELECT statement.
#
# I could have used positional placeholders (e.g. :1, :2, etc.) or
# ODBC style placeholders (e.g. ?), but I prefer Oracle's named
# placeholders (but few DBI drivers support them so they're not portable).
my $err_code = -20001;
$csr = $db->prepare(q{
BEGIN
PLSQL_EXAMPLE.PROC_IN(:err_code);
END;
});
$csr->bind_param(":err_code", $err_code);
# PROC_IN will RAISE_APPLICATION_ERROR which will cause the execute to 'fail'.
# Because we set RaiseError, the DBI will croak (die) so we catch that with eval.
eval {
$csr->execute;
};
print 'After proc_in: $#=',"'$#', errstr=$DBI::errstr, ret_val=$ret_val\n";
# Example 3 Eric Bartley <bartley#cc.purdue.edu>
#
# Building on the last example, I've added 1 IN OUT parameter. We still
# use a placeholders in the call to prepare, the difference is that
# we now call bind_param_inout to bind the value to the place holder.
#
# Note that the third parameter to bind_param_inout is the maximum size
# of the variable. You normally make this slightly larger than necessary.
# But note that the Perl variable will have that much memory assigned to
# it even if the actual value returned is shorter.
my $test_num = 5;
my $is_odd;
$csr = $db->prepare(q{
BEGIN
PLSQL_EXAMPLE.PROC_IN_INOUT(:test_num, :is_odd);
END;
});
# The value of $test_num is _copied_ here
$csr->bind_param(":test_num", $test_num);
$csr->bind_param_inout(":is_odd", \$is_odd, 1);
# The execute will automagically update the value of $is_odd
$csr->execute;
print "$test_num is ", ($is_odd) ? "odd - ok" : "even - error!", "\n";
# Example 4 Eric Bartley <bartley#cc.purdue.edu>
#
# What about the return value of a PLSQL function? Well treat it the same
# as you would a call to a function from SQL*Plus. We add a placeholder
# for the return value and bind it with a call to bind_param_inout so
# we can access its value after execute.
my $whoami = "";
$csr = $db->prepare(q{
BEGIN
:whoami := PLSQL_EXAMPLE.FUNC_NP;
END;
});
$csr->bind_param_inout(":whoami", \$whoami, 20);
$csr->execute;
print "Your database user name is $whoami\n";
$db->disconnect;
When I create a textfile, next copy it to another directory and then try to delete the original, it won't work, because the programa keeps the file locked.
Before deleting the file, I set the file-attribute to 'normal'like this:
SetFileAttributes((pchar('C:\test')),FILE_ATTRIBUTE_NORMAL);
I cannot find any simple solution to resolve this.
I create the file like this:
bestand:= tstringlist.Create;
try
r:= FindFirst('test.*', faAnyFile, Res);
try
EOFound:= False;
if (r = 0) then
while not EOFound do
begin
bestand.Add(res.Name);
EOFound:= FindNext(Res) <> 0;
end;
finally
FindClose(Res);
end;
finally
bestand.SaveToFile('C:\test');
bestand.Free;
end;
The same problem occurs when only reading the file like this:
AssignFile(Txt,TmpBest);
Reset(Txt);
while not Eof(Txt) do
begin
Readln(Txt, s);
L.Items.add.caption:=s;
end;
CloseFile(Txt);
Later, I set the file attributes to 'Normal' and try to delete the file:
if CopyFile(pchar(file-org), pchar(file-dest), false) then
begin
SetFileAttributes(pchar(file-org),FILE_ATTRIBUTE_NORMAL);
if not DeleteFile(file-org) then
showmessage('delete ' + file-org + ' failed!');
where file-org is file Txt/TmpBest from the description above.
I must say: I am not a Delphi programmer; I write in COBOL, but 'inherited' this Delphi-program from a former collegue and need to add some changes to it.
I found the answer to my own question. I already mentioned that I am not a Delphi-programmer, so I did not notice another left-over statement from before my changes:
FSource := TFileStream.Create(SourceFile, fmOpenRead or fmShareDenyNone);
Removing that statement solved my problem; obviously that statement locked my file until close of the program. Thanks for your trying to help anyway.
I have the following code which connects to a oracle database via soap, creates an XML Blob and returns it to the screen.
I am receiving the following error, and cannot figure out why.
array(3) {
["faultcode"]=>
string(11) "soap:Client"
["faultstring"]=>
string(22) "Error processing input"
["detail"]=>
array(1) {
["OracleErrors"]=>
string(39) "
Incorrect Input Doc/URL
"
}
}
I am using the following function to call a stored procedure.
function getUsersData(){
$xmlfunc = 'GETUSERS';
$pkg = 'JSON_EXPORTS';
$inparam = array("SESSIONHASH-VARCHAR2-IN" => $_SESSION['sessionhash']);
$outparam = array("USERSDATA-XMLTYPE-OUT");
$oradb = oradb::getconnection();
$oradb->newxml($xmlfunc,$pkg,$inparam,$outparam);
$result = $oradb->getxml(false,false,false,true);
print_r($result);
}
This is the stored procedure I am calling:
CREATE OR REPLACE PACKAGE BODY vivouser.json_exports IS
-- #Oracle bexV2
PROCEDURE getusers(sessionhash IN VARCHAR2,
usersdata OUT XMLTYPE)
IS
p_companyid number;
p_storegroupid number;
p_userid number;
BEGIN
bexcore.checksessionid(sessionhash, p_companyid, p_storegroupid, p_userid);
usersdata := bexcore.CreateXMLData(
'select userid,
tbu.companyid,
tbu.firstname,
tbu.middlename,
tbu.lastname,
tbu.gender,
tbu.payrollnumber,
tbu.ismanager,
tpt.description,
tpt.wagerate
from tbuser tbu
left join tbposition tbp using (USERID)
left join tbpositiontype tpt using (POSITIONTYPEID);'
);
END getusers;
END json_exports;
Also, please note: $_SESSION['sessionhash'] is proven to be a logical hash value. All other soap calls using this format function as expected. Bexcore.checksessionid is also proven to be valid, and not the cause of this error, as is bexcore.createXmlData (they are each used in thousands of other cases in the same way and run as expected.)
The problem I was having, was that the user accessing the database did not have permissions set to allow calling the requested packages.
use
grant all on <packagename> to <user>;
to solve this problem.
I need to refresh dbgrid constantly, in real time. Close and open dataset works fine, but blink the dbgrid. What can I do to avoid this?
I'd like a solution like Ajax, that update only the necessary.
Thanks
Have you tried to use Disable- & EnableControls?
DataSet.DisableControls;
try
DataSet.Close;
DataSet.Open;
finally
DataSet.EnableControls;
end;
Furthermore, it should be possible to just call DataSet.Refresh instead of closing and opening to get the same result.
I use this in my app
DataSet.MergeChangeLog;
DataSet.ApplyUpdates(-1);
DataSet.Refresh;
The above code is in an action named actRefreshData, in the ActionManager
When I need to use I just call it like
actRefreshData.Execute;
Hope this helps.
Hint: you can add a Timer and automate this
Look here:
type THackDataSet=class(TDataSet); // a nice "hack" so we can access
//protected members
THackDBGrid=class(TDBGrid);
procedure {tdmdb.}refreshgrid(grid : tdbgrid);
var row, recno : integer;
ds : tdataset;
b : tbookmark;
begin
Row := THackDBGrid(grid).Row;// or THackDataSet(ds).ActiveRecord
ds := grid.datasource.dataset;
RecNo := ds.RecNo;
b := ds.GetBookmark;
try
ds.close;
ds.Open;
finally
if (b<>nil) and ds.BookMarkValid(b) then
try
// ds.GotoBookMark(b);
ds.CheckBrowseMode;
THackDataSet(ds).DoBeforeScroll;
THackDataSet(ds).InternalGotoBookmark(b);
if THackDataSet(ds).ActiveRecord <> Row - 1 then
THackDataSet(ds).MoveBy(Row - THackDataSet(ds).ActiveRecord - 1);
ds.Resync([rmExact{, rmCenter}]);
THackDataSet(ds).DoAfterScroll;
finally
ds.FreeBookMark(b);
end
else if (recno<ds.RecordCount) and (recno<>ds.RecNo) then
begin
ds.First;
ds.MoveBy(Max(0, recno-1));
end;
end;
end;
In Delphi you can create a standalone Windows VCL Forms application. You can also create a Windows service application.
Is it possible to combine the two in a single application that can run as a standalone application and can also be installed as a Windows service?
Totally possible. The trick is to edit the .dpr to create main form when you want to run as an application and the service form when you want to run as a service. Like this:
if SvComFindCommand('config') then begin
//When run with the /config switch, display the configuration dialog.
Forms.Application.Initialize;
Forms.Application.CreateForm(TfrmConfig, frmConfig);
Forms.Application.Run;
end
else begin
SvCom_NTService.Application.Initialize;
SvCom_NTService.Application.CreateForm(TscmServiceSvc, scmServiceSvc);
SvCom_NTService.Application.Run;
end;
The code above uses SvCom to run the service but exactly the same effect could be achieved using the standard TService.
I wrote an article about that for The Delphi Magazine many years ago. You can read it here: Many Faces Of An Application.
It'll be hard to explain but I will try :)
I've done it in my project like that (Delphi 5):
program TestSvc;
uses SvcMgr,
SvcMain, //the unit for TTestService inherited from TService
...
;
var
IsDesktopMode : Boolean;
function IsServiceRunning : Boolean;
var
Svc: Integer;
SvcMgr: Integer;
ServSt : TServiceStatus;
begin
Result := False;
SvcMgr := OpenSCManager(nil, nil, SC_MANAGER_CONNECT);
if SvcMgr = 0 then Exit;
try
Svc := OpenService(SvcMgr, 'TestService', SERVICE_QUERY_STATUS);
if Svc = 0 then Exit;
try
if not QueryServiceStatus(Svc, ServSt) then Exit;
Result := (ServSt.dwCurrentState = SERVICE_RUNNING) or (ServSt.dwCurrentState = SERVICE_START_PENDING);
finally
CloseServiceHandle(Svc);
end;
finally
CloseServiceHandle(SvcMgr);
end;
end;
begin
if (Win32Platform <> VER_PLATFORM_WIN32_NT) or FindCmdLineSwitch('S', ['-', '/'], True) then
IsDesktopMode := True
else begin
IsDesktopMode := not FindCmdLineSwitch('INSTALL', ['-', '/'], True) and
not FindCmdLineSwitch('UNINSTALL', ['-', '/'], True) and
not IsServiceRunning;
end;
if IsDesktopMode then begin //desktop mode
Forms.Application.Initialize;
Forms.Application.Title := 'App. Title';
ShowTrayIcon(Forms.Application.Icon.Handle, NIM_ADD); // This function for create an icon to tray. You can create a popupmenu for the Icon.
while GetMessage(Msg, 0, 0, 0) do begin
TranslateMessage(Msg);
DispatchMessage(Msg);
end;
ShowTrayIcon(Forms.Application.Icon.Handle, NIM_DELETE); // for delete the tray Icon
end else begin // Service mode
SvcMgr.Application.Initialize;
SvcMgr.Application.CreateForm(TTestService, TestService);
SvcMgr.Application.Run;
end;
end.
Another almost simpler option is available at http://cc.embarcadero.com/item/19703, you just need to include a unit and change your DPR to something like:
begin
if CiaStartService('SERVICE NAME') then begin
CiaService.CreateForm(TMain, Main);
CiaService.Run;
Exit;
end;
Application.Initialize;
Application.Title := 'SERVICE NAME';
Application.CreateForm(TMain, Main);
Application.Run;
end.
While this example is now quite dated, the technique is simple enough that it still works, even with Delphi XE2. With this in place, your application will continue to operate as a non-service until you use the "/install" parameter (on an elevated command prompt). After which it will operate as a service until you use the "/uninstall" parameter (also on an elevated command prompt).
There is a solution for this problem without writing a single line of code. It depends a little on your application, but generally it is achievable. Try this: http://iain.cx/src/nssm. Don't forget to start all services that you application depends on BEFORE you start your application as a service. Google around for info on how to do that.
It is possible but in that case you cannot use the normal TServiceApplication and TService. You should implement all the service specific code yourself.
We had a similat problem and made two frame applications: one for the sand alone exe and one for the service. Now we can create a single BPL/DLL that is embedded in both containers.
If you want to spend some money: you should look at SvCOM, I think they have a solution to the problem.