maybe this is a lame question, but nevertheless...
I asked some questions about the plugins in delphi. What is the better way dll, bpl, OCX, scripting engine...
I dont feel like to distribute all *.bpls, and all its dependencies...
All I need is a *.dll which contains a TForm. And that Form should be placed into the host application.
There is no direct support for this in delphi (very sad situation). Some workarounds exists, but there are problems with tab key etc... So non workaround is perfect.
But maybe there is an another possibility. Inject dll code directly into the host *.exe.
So the *.exe will think that injected code his its own... And lot of problems (e.g. with tab key in form) should be gone.
Is it possible? isn't it a dirty hack, e.g. is that technique "programatically" legal?
(I have no experience with code injecting, and maybe it doesn't make sence what I'm saying here ;)
best regards
Peter
[edited]
To clarify some things... When we put a TForm in dll and than we try this form embed to the host *.exe application, a lot of problems arise. First is an error "cannot assign TFont to a TFont", but there is a some workaround for this.
Second is that host application take whole embeded form as one component, so you cannot use a tab key. (After pressing tab, focus will completly jump out of embeded form). Also we have some workaround for this, but it is far away from perfect...
So I had an idea, if we inject some code to the host, maybe host will be think that emebeded form his is own code, so tab key will be working.
But as I said before, I dont know anything about injecting, just a (maybe) crazy idea ;)
This is perfectly possible without recourse to any of the hacks you describe. For example:
library FormDLL;
uses
Windows,
Forms,
uMyForm in 'uMyForm.pas' {MyForm};
procedure ShowForm(MainFormHandle: HWND); stdcall;
begin
Application.Handle := MainFormHandle;
with TMyForm.Create(nil) do begin
ShowModal;
Free;
end;
end;
exports
ShowForm;
begin
end.
You can put pretty much anything you like in TMyForm. On the other side create a Delphi app and add the following code to call the DLL:
procedure ShowForm(MainFormHandle: HWND); stdcall; external 'FormDLL.dll';
procedure TMainForm.Button1Click(Sender: TObject);
begin
ShowForm(Handle);
end;
This behaves just perfectly.
So, I'm afraid it's not obvious what your problem is. If you can supply more details, then please do so.
Related
I am having some problems in some components, and I want to disable their design time packages, I just enable when I need. When I open my code, that some times is togheter with the form, when I open in the IDE, I want to first open by default de code part of it, instead the form itself. Is there a option for it?
I am not aware of IDE options allowing you to do this. But there are some ways you can work around the issue, though it is not as convenient as a specific option.
You could comment out the {$R *.dfm} directive when you don't want the form to open. Of course, compiling like this would cause application to fail creating the form at runtime.
So a more dynamic approach would be to wrap it in a conditional compilation.
{$IFDEF WHATEVER}
{$R *.dfm}
{$ENDIF}
According to some quick testing, this seems to work. Though, I'm not aware of any built-in conditions that says whether your are compiling or designing. So I'd guess the less error prone way to do it would be to pass -dWHATEVER to the "Additional options to pass to the compiler"
DISCLAIMER : I did not extensively test this. This may/may not cause issues further down the road.
i have a test.bpl package in my application and it has a form named myPackageForm.
after loading my Package when i want to close myPackageForm, Application will Terminate.
Main Project Initialization:
Application.Initialize;
Application.CreateForm(TMainForm,MainForm);
Application.Run;
MainForm FormCreate :
aPackage := LoadPackage('my bpl path'+test.bpl);
#P_ItemClick := GetProcAddress(aPackage,'ItemClickExcecute');
MainForm ButtonClick:
P_ItemClick(Sender);
testPackage CommandsUnit :
Procedure ItemClickExecute(Sender : TObject)
begin
TmyPackageForm.ShowForm();
end;
exports
ItemClickExecute;
end.
myPackagForm has a class procedure to show it:
Class Procedure TmyPackagForm.ShowForm;
begin
if not Assigned(myPackagForm)
myPackagForm := Application.CreateForm(TmyPackagForm ,myPackagForm );
myPackagForm.Show;
end;
And in OnClose Procedure has:
Release;
As a solution i try another command:
myPackagForm := TmyPackagForm.Create(Application);
to myPackagForm creation;
Can anybody know what happend in Delphi XE4 with CreateForm command on the packages?
Sir Rufo has got the basics covered. The first form created with a call to CreateForm becomes the main form. When the main form closes, the application closes.
Now, you have shown two calls to CreateForm. One in the host application, and one in your dynamically loaded package. And it seems clear that the first one to run is from the host application. So, how can the form in the package can bring down the application? Well, that can only happen, as Sir Rufo said, if there are two application instances in your process.
So the next question is, how can there be two application instances in your process? That should not happen. The entire point of packages is to allow Delphi units to be shared between different modules. If you have built your application correctly then you will have only one instance of TApplication that is shared between the host executable, and all of your packages.
So, the only reasonable conclusion to reach is that one of your modules is not built using runtime packages. For instance, perhaps the host application includes the RTL/VCL, linked statically inside the executable file. And your packages link to the RTL/VCL runtime packages. Or perhaps it is the dynamically loaded package that includes the RTL/VCL linked statically. Although IIRC, the compiler prevents that happening.
Whatever has gone wrong, the solution is that all your modules must be built using runtime packages. All the RTL/VCL libraries must be linked via runtime packages and must not be linked statically.
So, replacing Application.CreateForm with TMyPackageForm.Create is simply suppressing a wider problem. It is critical that you have only one instance of the RTL/VCL in your application. Achieve that by using runtime packages in all your modules.
It is certainly the case that TMyPackageForm.Create is the right way to create a form in your package. I only use Application.CreateForm for the main form. I never use it anywhere else. But don't try to fix your immediate problem solely by removing Application.CreateForm from your package. Fix the linking to the RTL/VCL.
TApplication.CreateForm not only just create a form, but also make the first form created by this method the TApplication.MainForm.
And closing the MainForm results in closing the application.
UPDATE
You have 2 TApplication instances inside your application.
your normal application
inside the BPL
So your form inside the BPL will become the MainForm of your BPL.Application and closing this form will perform a PostQuitMessage(0) in the context of your main application process and this forces the whole application to quit.
I am using Delphi XE. I have come across a memory leak problem using Delphi Soap. It turns out to be due to a missing .Free call in TWSDLLookup.Destroy, as described in QC 91160
The problem that I have is the described work-around, which is simply to add FLookup.Free to the TWSDLLookup.Destroy method.
I don't want to change the Delphi source, so I tried copying the unit to my project folder, making the change and recompiling, as described here in Tom's answer. The problem with this technique is that it apparently only works if you also recompile all the dependent units. I have tried copying just WSDLLookup.pas to my project directory and I get a Stackoverflow error. I'm not familiar with Web Services / SOAP so I don't know what other units I should copy over if I do use this technique.
Rob Kennedy's answer on the same page describes a different technique involving code hooking - but it doesn't seem to apply to object methods. I have done as he suggests and downloaded the free code for the TNT Unicode controls and located the relevant procedures, but I have been unable to find info on how to hook an object's methods - if indeed this is possible. If I could do this, I would then hook TWSDLLookup.Destroy and add the FLookup.Free call.
Any ideas for how to fix this will be much appreciated. I'm a bit of a newbie programmer so I'm hoping that I've missed something obvious?
What you are trying to do does in fact work fine. I tested it out myself. Here's the project file I used:
program WSDLLookupTest;
{$APPTYPE CONSOLE}
uses
WSDLLookup in 'WSDLLookup.pas';
var
intf: IInterface;
begin
intf := GetWSDLLookup as IInterface;
end.
I made a copy of the WSDLLookup.pas file and placed it in the same directory as the .dpr file. Then, in the copy rather than the original, I modified TWSDLLookup.Destroy.
destructor TWSDLLookup.Destroy;
begin
Beep;
ClearWSDLLookup;
FLookup.Free;
inherited;
end;
I added the Beep to prove to myself that this code was indeed being executed.
In your position I would definitely use this solution instead of attempting code hooks. And of course the other simple solution is to upgrade to a later Delphi version.
One thing to be careful of is to remember to remove the modified unit when you do upgrade. The leak was fixed in XE2.
After years of Delphi development I now have hundreds of forms shared throughout our Applications. Compilation ranges from Delphi 7 through to XE, thus one form might be opened in any IDE. The well-known Explicitxxx property addition after Delphi 7 has solutions to avoid a form accidentally acquiring properties that earlier compilers can't process (e.g Andreas's DDevExtensions) but I'd like a more positive 'switch' that prevented Delphi from making or saving any form modifications at all. Period.
Of course you could use the read-only flag, and a version control system provides additional means particulay of seeing that such a modification has occured. What I'd really like though is a {$LockDFM} switch that I could put in the form's unit, or a context menu option when viewing the form layout.
Can anyone think of a neat way of achieving this?
Thanks
The only thing I can think of (other than the read-only/VCS options you mentioned) is the Edit menu's Lock Controls option. This sets a flag that prevents controls from being moved around. I'm not sure how much good it would actually do, as I've never tried it; I just know it's there.
Helo
I am pretty sure that Delphi has no such a thing. I have been searching for a solution to this problem as well.
But, theres one thing you can do: You can write your own Delphi addon using OTA (Open Tools API). I know that there are a few classes which are able to notify you when something are about to be saved. You can intercept this event and decide if you wanna save it (in your case, if it is a DFM).
BTW, if you have plans to do such component, tell me. :)
EDIT:
I have found a piece of code that may help you. Extracted from http://www.gexperts.org/otafaq.html
TMyFormNotifier = class(TNotifierObject, IOTANotifier, IOTAFormNotifier)
protected
procedure FormActivated;
procedure FormSaving;
procedure ComponentRenamed(ComponentHandle: TOTAHandle; const OldName, NewName: string);
end;
In design time there is Edit->Lock Control.
LE: this is only for resizing/repositioning the controls on the forms. Concerning the ObjectInspector I don't know if there is anything that can 'lock' the values set there(so the developer can not change them).
Basically, no. Aside from the f'ing (pardon my french) explicit size and position properties which IMO never should have been in the .dfm, there are some third party components will change stuff just by you viewing the form. F.x. TMS components will update a version number even if you didn't change a thing since the previous version of their components.
Has anyone come across a framework or library for Delphi to simplify the generation of x86 code? I am not looking for an assembler, but rather a framework that abstracts the code generation process above the low level bits and bytes. Ideally I would like to build on top of an existing library or framework rather than hardcode the logic on a case by case basis.
The initial usage will be to generate small code stubs at runtime similar to the way Delphi dispatches SOAP requests. If I cannot find something I will likely roll my own, but I would hate to reinvent the wheel. Something in "C" might me interesting provided the license will permit translation and use in commercial and open source projects.
Update:
Here is some more context: What I am working toward is runtime implementation of interfaces and/or classes as part of a persistence framework. Something sort of like Java annotation driven persistence (JPA/EJB3) except with a distinctly Delphi flavor. The invocation target is a modular/extensible framework which will implement a generalized persistence model. I need to dispatch and hook method calls based on RTTI and an annotation/attribute model (something similar to InstantObjects metadata) in a very dynamic and fluid manner.
Thanks,
David
The more I have thought about your question. I am not sure if all you trying to just do Dynamic Method Invocation. Even though your asking about generating x86 code.
There are several techiniques that do this.
If you know the signature of the method in question you can do it easily by using a
TMethod and setting the method address and data.
procedure TForm8.Button1Click(Sender: TObject);
begin
Showmessage('Hello1');
end;
procedure TForm8.Button2Click(Sender: TObject);
var
M : TMethod;
begin
M.Code := MethodAddress('Button1Click');
M.Data := Self;
TNotifyEvent(M)(self);
end;
If you don't know the method signature you can write the class with {$METHODINFO ON}
Then use the functionality in ObjAuto.pas to invoke the method.
I have an example in my RTTI Presentation code from DelphiLive on how to do that.
According to features of PaxCompiler, you can create stand alone executable files.
Very spectulative answer:
Something like LLVM? I am not sure if it can be used from delphi or not, but you should be able to create dll's wth it.
Logically you would simply generate delphi code, compile to a DLL/BPL by cmdline compiler and then dyn load that one?
Unfortunately Delphi Explorer doesn't come with the cmdline compiler though. And your main binary would also have to be in Delphi Explorer (or at least in D2006 if that is binary compatible enough)
Any mix of Delphi versions (or Free Pascal) will probably not work on the package or HLL level, only at basic procedural DLL level.
I just found an interesting framework that does much of what I was looking for when I originally posted the question. A little late for my purposes, but thought someone else might find this useful:
DAsmJit a Delphi port of the asmjit project