If I would like to save a IXMLDOMDocument3 in runtime to a file on my harddrive, what is the syntax for that?
E.g. like IXMLDOMDocument3.save('c:\test.xml')
Or is it even possible?
Best regards!
the sample code below demonstrates how to load and save IXMLDomDocument3 XML at runtime. It uses msxml header file from Delphi-2010. IXMLDomDocument3 inherits from IXMLDomDocument and has Save method (as you wrote in your question). If method parameter is a string, then it specifies file name (it creates or replaces target file).
program Project3;
{$APPTYPE CONSOLE}
uses SysUtils, msxml, comObj, activex;
procedure LoadAndSaveXML(LoadFile, SaveFile : string);
var xml : IXMLDOMDocument3;
tn : IXMLDOMElement;
begin
xml := CreateComObject(CLASS_DOMDocument60) as IXMLDOMDocument3;
xml.load(LoadFile);
xml.save(SaveFile);
end;
begin
try
CoInitialize(nil);
try
LoadAndSaveXML('D:\in.xml', 'D:\out.xml');
finally
CoUninitialize();
end;
except
on E: Exception do begin
Writeln(E.ClassName, ': ', E.Message);
readln;
end;
end;
end.
Related
I want to use a GUID to uniquely identify my Application and to get at this value from within the code. I see that there is a GUID that would be ideal in the DPROJ:
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<ProjectGuid>{D4DB842C-FB4C-481B-8952-77DA04E37102}</ProjectGuid>
Does this get into the exe anywhere, eg as a resource? If not, what is the neatest way of linking in this GUID value into my exe file and reading it in code. The above GUID resides in a dedicated text file and is pasted into the DPROJ with my DprojMaker tool, so I can INCLUDE it in anything you might suggest.
Thanks
AFAIK the <ProjectGUID> is not embedded in the Exe file, but you can create an application to read the project guid and insert as a resource in your exe.
Check this sample app which read a file a create/updates a resource in a exe.
program UpdateResEXE;
{$APPTYPE CONSOLE}
uses
Classes,
Windows,
SysUtils;
//you can improve this method to read the ProjectGUID value directly from the dproj file using XML.
procedure UpdateExeResource(Const Source, ResourceName, ExeFile:string);
var
LStream : TFileStream;
hUpdate : THANDLE;
lpData : Pointer;
cbData : DWORD;
begin
LStream := TFileStream.Create(Source,fmOpenRead or fmShareDenyNone);
try
LStream.Seek(0, soFromBeginning);
cbData:=LStream.Size;
if cbData>0 then
begin
GetMem(lpData,cbData);
try
LStream.Read(lpData^, cbData);
hUpdate:= BeginUpdateResource(PChar(ExeFile), False);
if hUpdate <> 0 then
if UpdateResource(hUpdate, RT_RCDATA, PChar(ResourceName),0,lpData,cbData) then
begin
if not EndUpdateResource(hUpdate,FALSE) then RaiseLastOSError
end
else
RaiseLastOSError
else
RaiseLastOSError;
finally
FreeMem(lpData);
end;
end;
finally
LStream.Free;
end;
end;
begin
try
if ParamCount<>3 then
begin
Writeln('Wrong parameters number');
Halt(1);
end;
Writeln(Format('Adding/Updating resource %s in %s',[ParamStr(2), ParamStr(3)]));
UpdateExeResource( ParamStr(1), ParamStr(2), ParamStr(3));
Writeln('Done');
except
on E: Exception do
Writeln(E.ClassName, ': ', E.Message);
end;
end.
Now from your app, you can use the Post build events to call this application on this way
"C:\The path where is the tool goes here\UpdateResEXE.exe" "C:\The path of the file which contains the ProjectGUID goes here\Foo.txt" Project_GUID "$(OUTPUTPATH)"
And use like so :
{$APPTYPE CONSOLE}
uses
Windows,
Classes,
System.SysUtils;
function GetProjectGUID : string;
var
RS: TResourceStream;
SS: TStringStream;
begin
RS := TResourceStream.Create(HInstance, 'Project_GUID', RT_RCDATA);
try
SS:=TStringStream.Create;
try
SS.CopyFrom(RS, RS.Size);
Result:= SS.DataString;
finally
SS.Free;
end;
finally
RS.Free;
end;
end;
begin
try
Writeln(Format('Project GUID %s',[GetProjectGUID]));
except
on E: Exception do
Writeln(E.ClassName, ': ', E.Message);
end;
readln;
end.
Why not just hard-code your own GUID inside your code itself? The Code Editor has a CTRL+SHIFT+G keyboard shortcut for generating a new GUID string at the current active line of code. You can tweak that declaration into a constant variable for your code to use as needed, eg:
const
MyGuid: TGUID = '{04573E0E-DE08-4796-A5BB-E5F1F17D51F7}';
I have a url of a website. It looks something like this: http://www.example.com/downloads/file/4789/download?
I would like to save the file to my system, but I do not know how to get the file name of the download triggered by the URL in my example. Some files are pdf others are doc and rtf etc.
If someone can please point me in a direction of the filename problem and also what components to use, I would really appreciate it.
to get the filename from a url you can retrieve the HEAD information and check Content Disposition header field. For this task you can use the TIdHTTP indy component. if the Content Disposition doesn't have the file name you can try parsing the url.
Try this sample .
{$APPTYPE CONSOLE}
{$R *.res}
uses
IdURI,
IdHttp,
SysUtils;
function GetRemoteFileName (const URI: string) : string;
var
LHttp: TIdHTTP;
begin
LHttp := TIdHTTP.Create(nil);
try
LHttp.Head(URI);
Result:= LHTTP.Response.RawHeaders.Params['Content-Disposition', 'filename'];
if Result = '' then
with TIdURI.Create(URI) do
try
Result := Document;
finally
Free;
end;
finally
LHttp.Free;
end;
end;
begin
try
Writeln(GetRemoteFileName('http://dl.dropbox.com/u/12733424/Blog/Delphi%20Wmi%20Code%20Creator/Setup_WmiDelphiCodeCreator.exe'));
Writeln(GetRemoteFileName('http://studiostyl.es/settings/downloadScheme/1305'));
except
on E: Exception do
Writeln(E.ClassName, ': ', E.Message);
end;
Readln;
end.
I'm attempting to use a local .sdf file as a means of temporary storage should the main database be unreachable. I have the .sdf file, but when I try to set it to the file it seems to not at all know if the .sdf exists. The current connection string I have currently is:
Driver={SQL Native Client};Data Source=C::\users\username\desktop\file\MyData.sdf;Persist Security Info=False
and for the Provider it generated for me:
Provider=Microsoft.SQLSERVER.CE.OLEDB.3.5
When I try to use the connection, I get a "Provider cannot be found. It may not be properly installed." The .sdf is most definitely in the folder. I also had/have a problem with it wanting a username and/or password, neither of which I had to specify when creating the database.
The Question: Is there something wrong with my connection string? Is it reasonable to use ADO connections to access SQL Compact Databases? Might there be an easier way to query/retrieve data from a temporary storage (I would prefer doing it with SQL though)?
Most documentation seems to be from 2003/2005, which is unhelpful.
I used "connectionstrings.com" for help making the string. Any advice would be helpful, thanks
First to open the sdf file you must use a provider compatible with the version of the sdf file. since you mention in your comments the version 3.5 you must use this provider Microsoft.SQLSERVER.CE.OLEDB.3.5
Then you must ensure which the provider is installed
Try this code to list the OLEDB providers installed in your system
{$APPTYPE CONSOLE}
{$R *.res}
uses
Windows,
Registry,
Classes,
SysUtils;
procedure ListOLEDBProviders;
var
LRegistry: TRegistry;
LIndex: Integer;
SubKeys,Values: TStrings;
CurKey, CurSubKey: string;
begin
LRegistry := TRegistry.Create;
try
LRegistry.RootKey := HKEY_CLASSES_ROOT;
if LRegistry.OpenKeyReadOnly('CLSID') then
begin
SubKeys := TStringList.Create;
try
LRegistry.GetKeyNames(SubKeys);
LRegistry.CloseKey;
for LIndex := 0 to SubKeys.Count - 1 do
begin
CurKey := 'CLSID\' + SubKeys[LIndex];
if LRegistry.KeyExists(CurKey) then
begin
if LRegistry.OpenKeyReadOnly(CurKey) then
begin
Values:=TStringList.Create;
try
LRegistry.GetValueNames(Values);
LRegistry.CloseKey;
for CurSubKey in Values do
if SameText(CurSubKey, 'OLEDB_SERVICES') then
if LRegistry.OpenKeyReadOnly(CurKey+'\ProgID') then
begin
Writeln(LRegistry.ReadString(''));
LRegistry.CloseKey;
if LRegistry.OpenKeyReadOnly(CurKey+'\OLE DB Provider') then
begin
Writeln(' '+LRegistry.ReadString(''));
LRegistry.CloseKey;
end;
end;
finally
Values.Free;
end;
end;
end;
end;
finally
SubKeys.Free;
end;
LRegistry.CloseKey;
end;
finally
LRegistry.Free;
end;
end;
begin
try
ListOLEDBProviders;
except
on E:Exception do
Writeln(E.Classname, ':', E.Message);
end;
Writeln('Press Enter to exit');
Readln;
end.
Now this is a basic sample to connect to a Sql Server compact file.
{$APPTYPE CONSOLE}
{$R *.res}
uses
ActiveX,
ComObj,
AdoDb,
SysUtils;
procedure Test;
Var
AdoQuery : TADOQuery;
begin
AdoQuery:=TADOQuery.Create(nil);
try
AdoQuery.ConnectionString:='Provider=Microsoft.SQLSERVER.CE.OLEDB.3.5;Data Source=C:\Datos\Northwind.sdf';
AdoQuery.SQL.Text:='Select * from Customers';
AdoQuery.Open;
While not AdoQuery.eof do
begin
Writeln(Format('%s %s',[AdoQuery.FieldByName('Customer ID').AsString,AdoQuery.FieldByName('Company Name').AsString]));
AdoQuery.Next;
end;
finally
AdoQuery.Free;
end;
end;
begin
try
CoInitialize(nil);
try
Test;
finally
CoUninitialize;
end;
except
on E:EOleException do
Writeln(Format('EOleException %s %x', [E.Message,E.ErrorCode]));
on E:Exception do
Writeln(E.Classname, ':', E.Message);
end;
Writeln('Press Enter to exit');
Readln;
end.
also check this wich helps with protected databases
"Provider=Microsoft.SQLSERVER.OLEDB.CE.2.0; data
source=\NorthWind.sdf; SSCE:Database Password="
Im writing a database application, using Delphi and need to export data from an access database to an Excel spreadsheet. I Could manage the reverse sequence (import excel to access) using a docmd.spreadsheet. Works 100%. But I do not know how to set the parameters for the export. I need help please.
Check this sample code, Also I recommend you which you read the DoCmd.TransferSpreadsheet Method documentation too.
{$APPTYPE CONSOLE}
uses
SysUtils,
ActiveX,
ComObj;
procedure ExportDataAccess(const AccessDb, TableName, ExcelFileName:String);
Const
acQuitSaveAll = $00000001;
acExport = $00000001;
acSpreadsheetTypeExcel9 = $00000008;
acSpreadsheetTypeExcel12 = $00000009;
var
LAccess : OleVariant;
begin
//create the COM Object
LAccess := CreateOleObject('Access.Application');
//open the access database
LAccess.OpenCurrentDatabase(AccessDb);
//export the data
LAccess.DoCmd.TransferSpreadsheet( acExport, acSpreadsheetTypeExcel9, TableName, ExcelFileName, True);
LAccess.CloseCurrentDatabase;
LAccess.Quit(1);
end;
begin
try
CoInitialize(nil);
try
ExportDataAccess('C:\Datos\Database1.accdb','Sales','C:\Datos\MyExcelFile.xls');
Writeln('Done');
finally
CoUninitialize;
end;
except
on E:EOleException do
Writeln(Format('EOleException %s %x', [E.Message,E.ErrorCode]));
on E:Exception do
Writeln(E.Classname, ':', E.Message);
end;
Writeln('Press Enter to exit');
Readln;
end.
I want to get the whole list of classes defined in a specific unit
How can I get the list of all instances of those classes, irrespective of where they are created?
First before to answer your question, remember always include your delphi version in questions related to the Rtti.
1) Asumming which you are using a new version of delphi (>=2010) you can get the unit name of a type using the QualifiedName property , from there you must check the IsInstance property to determine if is a class.
Check the next sample.
{$APPTYPE CONSOLE}
{$R *.res}
uses
Rtti,
System.SysUtils;
procedure Test;
Var
t : TRttiType;
//extract the unit name from the QualifiedName property
function GetUnitName(lType: TRttiType): string;
begin
Result := StringReplace(lType.QualifiedName, '.' + lType.Name, '',[rfReplaceAll])
end;
begin
//list all the types of the System.SysUtils unit
for t in TRttiContext.Create.GetTypes do
if SameText('System.SysUtils',GetUnitName(t)) and (t.IsInstance) then
Writeln(t.Name);
end;
begin
try
Test;
except
on E: Exception do
Writeln(E.ClassName, ': ', E.Message);
end;
Readln;
end.
2) The Rtti can't list the instances of the classes. because the Rtti is about type information and not of instances.
Question 1
The following code does what you ask, relying on the new RTTI introduced in Delphi 2010:
program FindClassesDeclaredInUnit;
{$APPTYPE CONSOLE}
uses
SysUtils, Rtti, MyTestUnit in 'MyTestUnit.pas';
procedure ListClassesDeclaredInNamedUnit(const UnitName: string);
var
Context: TRttiContext;
t: TRttiType;
DeclaringUnitName: string;
begin
Context := TRttiContext.Create;
for t in Context.GetTypes do
if t.IsInstance then
begin
DeclaringUnitName := t.AsInstance.DeclaringUnitName;
if SameText(DeclaringUnitName, UnitName) then
Writeln(t.ToString, ' ', DeclaringUnitName);
end;
end;
begin
ListClassesDeclaredInNamedUnit('MyTestUnit');
Readln;
end.
unit MyTestUnit;
interface
type
TClass1 = class
end;
TClass2 = class
end;
implementation
procedure StopLinkerStrippingTheseClasses;
begin
TClass1.Create.Free;
TClass2.Create.Free;
end;
initialization
StopLinkerStrippingTheseClasses;
end.
Question 2
There is no global registry of object instances.