I'd like create a dll to import data from a file (different format, for example csv, txt, xls, ...). My idea is this: the dll load the data with her "engine" then send this data to my application so my application can show them inside a grid.
This is my second DLL so I have some problems/questions.
I think my DLL should send the data to a TDataset on my application but how can I call a DLL with a TDataset as argument?
Any suggestions?
What is the easiest way to accomplish what I have in mind? (if possible)
If you are the creator of those DLL's, then consider to use packages instead of DLL. This will avoid the problems, like dublicate Delphi RTTI, plain DLL API. Then you will need to properly split classes between packages, load packages statically or dynamically, get reference to a class implementing import engine, and call the corresponding method with a dataset reference as a parameter value.
Easier way for you would be to store the data directly into database in DLL. And after import you just refresh your TDataset.
BTW, you don't "call DLL", you call some method that is public in DLL and there you can use arguments as in normal methods.
EDIT: For more generic DLLs that don't require data components just send data in struct
TMyData
{ int ID;
String Value;
};
int MyDataImport(TMyData & data)
{
...
}
Related
I have a Delphi VCL application that manipulates a TClientDataset object. I need to pass this object as a parameter to a custom COM library, also written in Delphi.
I have two questions:
1) Is this possible?
2) If so, how?
No you cannot pass such an object. It is not a valid COM interop type. In fact you cannot even pass such an object between Delphi modules other than runtime packages.
The most obvious solutions are:
Wrap the object with a COM interface and pass that. The interface would have to expose methods to extract the data.
Serialize the data, for instance as JSON, and pass that as text. On the other side you would need to de-serialize.
Use the built in serialization capabilities as offered by the Data and XMLData properties of client data set.
The latter two serialization based options are probably simpler. But more costly in terms of memory. Using an interface requires more work to code, but may result in more efficient runtime performance.
I'm working in Delphi XE, windows 7.
In an application I want to enable different report types for my users to select.
To do this, I have 1 base report class and a subclass per report type (xml, csv, ppt, etc).
{Just an illustrating example}
TBaseReport = class
public
constructor Create;
procedure GenerateReport; virtual; abstract;
class function ReportType: string; virtual; abstract;
end;
T*Report = class(TBaseReport);
//Etcetera.
What I want to do is use Rtti to detect all report classes and list their ReportType.
After that, I want to use Rtti to create an instance of the chosen report class and call GenerateReport. All in all, this is not too difficult to achieve.
However there is a major drawback: I'm never hard coding the use of the descending classes, so the code does not get included in the executable.
Is there a decent way to force the linker/compiler to include these classes?
A(n ugly) work around would be to simulate usage of the reports in their initialization section, but I'd rather not do that.
A better solution is to make the base class persistent and to call 'RegisterClass(T*Report);' in the initialization section. It works, but I do not see any other need to make them persistent, so again, I'd rather not do that. On the other hand, maybe this is the only way to do it?
Thanks in advance.
You can create your own version of RegisterClass. Something like RegisterReportClass. Internally you keep your own list of report classes that can be used. Your register function will take a TBaseReport class type - No need for TPersistent.
Your RegisterReportClass method should be called in the Initialization section making sure the classes are included.
If you look in the Graphics unit you can see TFileFormatsList = class(TList). This is the class that is used to hold the different Graphic Types and could be used as an example for creating your own TReportFormatsList. Delphi uses a static function TPicture.RegisterFileFormat to add items to their internal list.
You can use the {$STRONGLINKTYPES ON} Compiler Directive, to include all symbols of your app in the final exe, remember that this option increases the executable size, as more RTTI is included in the executable.
I have a DLL file from which I need the memory address of a class procedure. I am getting the handle to the DLL file, but when I use GetProcAddress, I can't get the address of the procedure. I have tried the following strings for the process name parameter:
"ProcName"
"ProcClass.ProcName"
"ProcClass::ProcName"
"ProcInterface::ProcName"
"ProcInterface.ProcName"
In none of the cases have I gotten the memory address of the procedure. I am mostly certain that the procedure is public.
What is the string format for doing this? Would it be easier to declare a function pointing to the external procedure and get the address later? Like this:
procedure ProcName(); stdcall; far; external 'Example.DLL';
ProcPointer := #ProcName;
GetProcAddress only gives you the address for exported functions. Your DLL surely doesn't export the methods of a class!
Use an PE explorer to look for the exported names. For example, use the PE explorer available in GExperts. I've got a "PE Information" menu entry under the GExperts menu.
You are into reverse engineering territory here.
I think that if I were you I would just step through in the CPU view of the debugger, following a call to the method of interest, and find the entry point address. I'd subtract it from the base address of the DLL and that would be the offset. Then to calculate the address at runtime you just add the offset it to the base address of the DLL in memory at that time. You can find out the base address with calls to LoadLibrary or GetModuleHandle.
Why hard code the offset? Well, since you can't modify your DLL it doesn't seem to be too limiting. If hard coding the offset is not viable then there are other means of locating entry points, but I must admit I'm not the world's greatest expert on that.
Finally, when you implement the replacement method, you will need to replace it with a global function/procedure with an extra parameter, the first parameter, which takes the place of Self.
I might be reading this wrong. But it seems to me you wrote the DLL.
You should write a function that is NOT a member of any class, and export it from your DLL. Inside that function, call your class method.
If you didn't write the DLL, you still need to find out what functions it exports, and it is very unlikely any of them were class methods, at least not in Pascal.
If someone wrote a dll in C++ and exported its methods, then you would have to investigate C++ name mangling rules.
10 years have ellapsed since I used COM/OLE, and I forget 90% of them.
Now we need to make a COM object to access some data from PHP/Python (this is specific thing, the php ODBC don't access the output params of a DataBase - like stored proc output), and my idea the I realize a minimal object with one method, and PHP/Python can call this to get the output...
procedure ExecSQL(Config, IP, Port, DBName, SQL, IDFieldName : variant) : output
output is [IDValue, ErrorMsg, HResult]
Please help me a very little example, how to start it?
I need only this, but I'm confused by many ActiveX/COM in the palette.
What I need to use to make a simple COM DLL, and how to register my COM object with this DLL?
Thanks:
dd
Select File\New\ActiveX Library - this creates ActiveX DLL project
Select File\New\Automation Object - this creates the type library and implementation
Using the type library editor, add methods/properties to the interface
Write implementation code
Select Run\Register ActiveX Server - this registers the COM server DLL
For COM related applications in Delphi this link is usefull http://www.techvanguards.com/
I've been trying to get a soap server up that implements (is that the correct term?) a wsdl specification made by a third party. I have used Delphi's wsdl importer. (Part of) the generated code looks like this:
miniPortType = interface(IInvokable)
['{824D172A-9C1F-D202-5B21-4C324553BCF0}']
// Cannot unwrap:
// - Input element wrapper name does not match operation's name
function miniService(const aMessage: MiniMessageType): MiniAnswerType; stdcall;
end;
When called, the server says that "No method named 'MiniMessageType' is supported by interface 'miniPortType'".
I can only get this to work by making the name of the function and name of the main element of the message the same.
I think it should be possible to have different names. At least soapUI doesn't complain. And I actually have no choice but to implement the wsdl as is. Does anybody know how I can work around this?
I'm using Delphi 2007.
Thanks, Miel.
If I recall correctly, the SOAP interface is actually defined in a "table" at the bottom of the definitions, and it is this which is used to do the conversion between Delphi types and SOAP types in the communications. I've "corrected" this sort of thing in the past by manually changing the table building calls, but you have to be careful, and may also need to mangle the SOAP text at the appropriate point to make it all fit.