I have converted my 2 GUI apps from Delphi to Lazarus.
Both apps compile for Win32 platform, i386 and with GUI.
Main form were converted using Lazarus tool and can be edited from IDE.
But when I run such application main form does not appear, only blank form without any controls.
I tried to debug this. It runs all code in initialization sections,
and runs code from .lpr project, but something wrong happens in CreateForm() because
it doesn't run code in the main form OnCreate event. In event log I can see all
texts I write to it with '<App.Run' appearing after I close this empty form.
Code in .lpr project:
Application.Initialize;
AddToEventLogInfo('App.CreateForm');
Application.CreateForm(TfrmTst, frmTst);
AddToEventLogInfo('App.Run>');
Application.Run;
AddToEventLogInfo('<App.Run');
I checked that I am able to create simple GUI apps from the Lazarus, but both converted GUI
apps do not work as expected. What can be wrong? Have I missed something?
Maybe one of many warnings and hints Lazarus write is important?
When I run my app Lazarus writes this:
windres: warning: 14: "MAINICON": 1045: duplicate value
windres: warning: 16: 1: 1045: duplicate value
Project "Tst_fpc" successfully built. :)
EDIT:
Lazarus conversion tool converted .dfm -> .lfm, but has some problems with .pas file. I had to manually:
add Lazarus units to uses:
uses
{$IFDEF FPC}
LCLIntf, LResources,
{$ENDIF}
Conditional compile Delphi form {$R *.dfm}:
{$IFNDEF FPC}
{$R *.dfm}
{$ENDIF}
Add .lrs resource in initialization code:
initialization
{$IFDEF FPC} {$i myunit.lrs} {$ENDIF}
I suspect that the mainform unit (I assume it is called utest) doesn't have a {$I utest.lrs} in its initialization section. The .lrs is the lazarus resource file, created from the lfm (dfm) in delphi.
The empty form is the form of for the current project as you used the convert Delphi project from tools which means the current project is active.
Try this:
On the project option close the current project.
On the small main window named as project wizard, use the convert Delphi project option.
I'm sorry I can't give you a straight answer. From what I understand there's a problem a problem with the resource file. In delphi that's the *.res, I don't know what they look like in Lazarus. Use a program like resedit, http://www.resedit.net/, to open the resource file. I tried it and found a "folder" Icon where there was a post MAINICON. I'm guessing you have two. In that case remove one of them.
Related
I want to make a component that uses some resources compiled in my package's project. My component will try to use this resource (a PNG image) during runtime (at its constructor).
I want to use it in my application's project, but as soon as the component gets created, I get the following exception:
First chance exception at $7579B9BC. Exception class EResNotFound with message 'Resource xxx not found'. Process yyy.exe (6060)
What am I missing here?
EDIT
The calling code for the resource in the package's project is like this:
Png.LoadFromResourceName(HInstance, 'png_resource_name');
EDIT 2
As suggested by David, I tried using the function GetModuleHandle, but it will always return 0 if I call it from the package's project or the application's project. The code being called in the package's project is like this:
PackageModuleHandle := GetModuleHandle(PChar('my_package.bpl'));
Png := TPngImage.Create;
Png .LoadFromResourceName(PackageModuleHandle, 'png_resource_name');
Absolute paths to the bpl file won't work either.
EDIT 3
New attempt based on new answer:
PackageModuleHandle := FindClassHInstance(TMyComponent);
Png := TPngImage.Create;
Png .LoadFromResourceName(PackageModuleHandle, 'png_resource_name');
Fails with the same exception.
EDIT 4
Using ResourceHacker, and if I used it right, the resources doesn't seem to be in my bpl file. What could I be doing wrong about this? Seems such a complicated matter to such a simple feature.
CONCLUSION
I had to add the .res file of my package to the package's .dpr just after the {$R *.res} line. Like this:
{$R *.res}
{$R 'my_pacakge.res'}
Also, I had to include the my_package.rc file to my project, so the resources would get compiled to the .res after each build. That did the trick, I guess. Thanks for all the answers.
You need to use FindClassHInstance(), specifying your component's class type, instead of using the global HInstance variable or GetModuleHandle(). That way, you obtain the correct module handle regardless of whether the package gets statically linked or dynamically linked into the main executable.
You are passing HInstance, the handle of the executable module to the resource loading function. That fails because the resource lives in the package module. Therefore you need to pass the module handle for the package. You can obtain the module handle of the package like this:
PackageModuleHandle := GetModuleHandle(PChar('MyPackage.bpl'));
If you are loading your package dynamically then the call to LoadPackage returned the module handle.
Update: Remy's suggestion of using FindClassHInstance is clearly a better way to obtain the module handle.
A component that uses a resource that is implemented in a unit called MyUnit1.pas should include the following line inside:
{$R MyUnitRc.res MyUnitRc.rc}
Note that the above syntax won't work on some old delphi versions (Delphi 7). The above works on 2010,XE,XE2 and so on, and it compiles the .rc into a .res when the project builds that unit. Alternatively you would add the {$R} declaration to each statically linked application and also to your BPL's .dpr file.
That .RC file mYUnitRc.res will contain one or more lines declaring your resources. I use RCDATA declarations to load PNGs, like this:
MYIMAGENAME RCDATA "MyFile.png"
If you do it this way, instead of using an RC file added to the .dproj/.dpr only, then it will work in two important cases:
When the BPL is loading at designtime.
When the component is loading at runtime from within an application that is compiled with Runtime Packages turned off.
To handle the third case, the one that the other answers (Remy and David) deal with, you do need to call FindClassHinstance as Remy stated. However I believe you should also look at how you are including the resource file and having it compiled and linked, both within your package, and within applications that use the component.
Here is some sample code showing loading a resource at runtime into a TPngImage, that I use in my own components:
procedure TSampleControl.LoadImageFromResource( button:TSubControl);
var
png:TPngImage;
begin
if button.DefaultResourceId='' then exit;
png := TPngImage.Create;
try
try
png.LoadFromResourceName(HInstance,button.DefaultResourceId);
button.Glyph.Assign(png);
except
on E:Exception do begin
OutputDebugString( PChar(button.DefaultResourceId+' load error:'+E.Message) );
end;
end;
finally
png.Free;
end;
end;
Note that I catch resource load exceptions, which leave some elements in my control without their glyphs but at least does not crash Delphi. HInstance may need to be changed as David and Remy Point out to use LoadFromResourceName to handle the case where you need to load from the .BPL but I don't think that you can assume that a person who uses your components is always going to redistribute your BPL file, and thus FindClassHinstance is preferable to GetModuleHandle..
Update: I should have used what Remy suggested:
png.LoadFromResourceName( FindClassHInstance(TSampleControl),
button.DefaultResourceId);
I'm trying to play around with some Delphi ActiveX library for MS-RDP (mstscax.dll), so I imported the library into my project, and started looking for some codes snippets on the web. On a first look, it's pretty obvious, but the lack of examples makes it a little complex.
First the library gives an error on Delphi Seattle, on this line:
property ConnectWithEndpoint: POleVariant1 write Set_ConnectWithEndpoint;
Ok, I commented this line out (not the best solution, I know), but it compiled. Later I tried to change POleVariant1 to OleVariant only, and still compiling.
Ok, after compiled, I tried this code:
var
Form1: TForm1;
RDP: TMsRdpClient8NotSafeForScripting;
implementation
{$R *.dfm}
procedure TForm1.Button1Click(Sender: TObject);
begin
RDP:= TMsRdpClient8NotSafeForScripting.Create(Nil);
RDP.Server:= 'xxxx';
RDP.AdvancedSettings8.RDPPort:= 3389;
RDP.UserName:= 'terminal';
RDP.AdvancedSettings8.ClearTextPassword:= '123456';
RDP.Connect;
if RDP.Connected.ToBoolean = true then
ShowMessage('connected')
else
ShowMessage('error');
end;
I tried some different types for the var RDP, like TMsRdpClient8 only, but still the same problem:
It don't even try to connect! While looking on the sniffer, no tcp connections are made, just nothing happens and the "error" message appears. Any idea about how to work with this guy?
This question intrigued me so I tried to import that ActiveX control and try it myself. It seems to work for me, so I'll explain what I did.
I imported the mstscax.dll ActiveX control then added it to a new package in order to install components onto the tool palette. I immediately ran into the error you did with the ConnectWithEndpoint property. I changed the type in the declaration to OleVariant because the Set_ConnectWithEnpoint property setter function takes an OleVariant. There is clearly something about the type information that our ActiveX importer code is getting confused by. Either way, that change got the file to compile and install the component package. There are now a bunch of TMsRdpClientXXXX components.
Created a new VCL Forms project, then dropped the TMsRdpClient9 component into the form. Added a TButton and then added this code into the button's OnClick handler:
MsRdpClient91.Server := '<some remote server>';
MsRdpClient91.Domain := 'embarcadero.com';
MsRdpClient91.UserName := 'abauer';
MsRdpClient91.Connect;
Once I ran the app, and pressed the button, it connected and the content of the ActiveX control showed the remote server login screen just fine.
I'm running Windows 10, build 10565.
Here's what I'm seeing on my little app I wrote:
My old Delphi 7 application is using IdStreamVCLWin32 unit in one pas file. This unit is located at following location.
C:\Program Files\Indy 10 for Delphi\Source\System\IdStreamVCLWin32.pas
When I am running same code in my Delphi XE4 environment, I am getting error IdStreamVCLWin32 not found.
Note: Delphi 7 is using Indy 10 but Delphi XE4 is using Indy which comes default with it. I have not installed indy explicitly in Delphi XE4 environment.
I searched my entire C drive where Delphi XE4 is installed but found no IdStreamVCLWin32.pas file.
How to get rid from this error?
From what I can tell, you were never meant to include that unit directly. The unit IdStreamVCL would delegate to either IdStreamVCLDotNet or IdStreamVCLWin32. And so it appears to me that IdStreamVCLWin32 is an implementation detail that you are shielded from by using IdStreamVCL.
These units have, nowadays, all been coalesced into IdStreamVCL. And so you could include that. However, it's not clear to me that you should even do that. Take a look at IdStream:
unit IdStream;
interface
{$I IdCompilerDefines.inc}
uses
{$IFDEF DOTNET}
IdStreamNET
{$ELSE}
IdStreamVCL
{$ENDIF};
type
{$IFDEF DOTNET}
TIdStreamHelper = TIdStreamHelperNET;
{$ELSE}
TIdStreamHelper = TIdStreamHelperVCL;
{$ENDIF}
implementation
end.
It seems pretty clear that you are meant to use IdStream and let the compiler work out whether that implementation is provided by IdStreamNET or IdStreamVCL.
So, the answer to your question is probably that you should replace your use of IdStreamVCLWin32 with IdStream. Note that the functionality in IdStream is implemented differently now. You no longer instantiate an instance of a stream class. The modern Indy offers you a helper class TIdStreamHelper which contains class functions. So you end up writing code like this:
BytesWritten := TIdStreamHelper.Write(Stream, Bytes, Count);
However, I cannot be sure that's the right approach since I don't know what you actually use from IdStreamVCLWin32. It's quite plausible that your code uses nothing from there and the use of IdStreamVCLWin32 is simply a stray hangover from some older version of your code.
So my advice is:
Remove IdStreamVCLWin32 from your uses.
Deal with any subsequent compiler errors by studying the code and working out the right way to do it with the current Indy code.
In Delphi 7 whenever I control+clicked a function/procedure it took me to that function/procedure. But it is not working in Delphi XE - at least not with all functions. I have a function called Associate in ExtUtils.pas
The function is correctly compiled so the compiler can find the ExtUtils.pas (and of course the ExtUtils is added to the Uses clause and its folder its added in 'Library path'). But when I control+click the function or the unit name, it doesn't take me there.
Any way to fix this?
UPDATE1:
Also, Control+Click on a function (declare in the current unit) does not move the cursor in the INTERFACE section where the function is declared.
UPDATE2:
I temporary put the ExtUtils unit in project's folder and now it works. So, the Control+Click by itself it works but it seems that the IDE has problems finding the unit even it its folder is present in Library Path and Browsing Path.
Similar reports:
http://webcache.googleusercontent.com
http://webcache.googleusercontent.com
http://cc.embarcadero.com/Item/28269
One report right here (see answers below)
New test:
I have fully uninstalled Delphi (and manually delete the files and registry leftovers). Then reinstalled again. NO additional tools except CodeSite were installed, not even the databases. Then I created a new project. It contains a button. When I click the button, it runs the TestMe procedure which is defined in an external PAS file called TestUnit.Pas. I added the path to this library in Library Path and Browsing Path. But the Control+Click on TestMe procedure is still not working! If I hover the mouse over the TestMe procedure, the pop-up says "Declared in TestUnit", where the 'TestUnit' word is a blue link. If I click it I hear a Windows system sound but the IDE doesn't take me there (to the unit).
The TestMe procedure is this:
procedure TestMe;
begin
Beep(800, 500);
end;
If I control+click the Beep procedure, it takes me to Windows.pas. So, this is working.
Please let me know if you have in mind a different test.
UPDATE:
And now it works! Without any apparent reasons! I just open and closed and compiled the project. But I make no changes to Delphi except these two: AutoSave options-> Editor files and Project Options.
UPDATE:
This cannot be!!!
So, now I can access the TestUnit.pas file when I control+click on TestMe procedure.
So, I moved the original PAS file (ExtUtils.pas) that didn't wanted to work in my initial test (before Delphi reinstall) in the same folder where TestUnit.pas is. Guess what: I can open (with control+click) to TestUnit.pas but not the ExtUtils.pas!!!!
Delphi acts so strange and inconsistent!
UPDATE:
I edited ExtUtils.pas and now I cannot open AGAIN TestUnit.pas.
Ken White won't let me say that Delphi could possible have bugs. So I cannot use the 'bug' together with 'Delphi'. Can anybody put these words together for me?
UPDATE:
I totally removed any reference to ExtUtils.pas - so I restored the project to the point where it worked (with TestUnit). But now the bug persists. Even if few seconds before it worked with TestUnit now its not working again.
UPDATE:
Now I realize an important thing: in my source code (in the test project) I have a single line of compilable code:
procedure TForm1.Button1Click(Sender: TObject);
begin
TestMe;
end;
The blue dots does not appear for this code - as it wouldn't have been compiled. In those few minutes when the program worked, I have seen the blue dots.
I have also excluded 'AutoSave options-> Editor files and Project Options' as a possible cause for this issue.
UPDATE:
I have found a way to fix the problem... for few minutes: I move the project and the library in a different folder (any location will do it). The control+click will work for a while. It even works if I put the files back into the original folder. So, it seems that Delphi keeps some kind of cache of some files. As long as the cache is broken and it keeps the cache, control+click won;t work. But when I move the files, it has to recreate that cache so it will work until the issue reappears and it is stored in the cache.
Here we are 5 developers using Delphi 2010 and 2 also using XE and we are experiencing the same thing with the Ctrl-click as you. It seems to stop working randomly. We never could find a pattern or a fix for that. So from time to time we hear swearing coming from cubicles...
When that happens, I use shift-ctrl-F, to do a search.
Sylvain
First, thanks for you all to give hints about this problem. Maybe this is a question long time ago, but at last, after tried many many times, I think the problem cause is, actually, in the "project source code"
IDE version: Delphi XE
please try:
in the Project Options >> Delphi Compiler>>Compiling , ensure:
Debug Information: true
Symbol Reference Info: Reference info
in the Project Source file(dpk file, open by Project >> View Source),
remove {$REFERENCEINFO OFF}
or change to {$REFERENCEINFO ON}
Note that step 2 is very important, even step 1 done, it still can not browse source without step 2.
I'm using Delphi 5 and the Ctrl-click have also problems, i don't know if it still working in the new delphi IDEs but i can go from declaration to implementation using CTRL-SHIFT-UpArrow or DownArrow.
Hope it helps.
There have always been these two distinct options in Delphi:
Library path – used when compiling your app.
Browsing path – used by Code Insight, i.e. when control-clicking identifiers too.
You need to check the second one. It must include the path(s) to the source files you are trying to navigate with Ctrl+Click.
I've found that if I use a record type in the interface section and it's not defined by a type expression, Ctrl-Click and other jumping functions (Ctrl+Shift+Up/Down) won't work.
type
TForm1 = class(TForm)
...
public
Something:record
A, B:integer;
end;
procedure DoSomething;
end;
With the code above I can't jump to implementation of the procedure with Ctrl+Shift+Down. The fix I have to use:
type
TMyRecord = record
A, B:integer;
end;
TForm1 = class(TForm)
...
public
Something:TMyRecord;
procedure DoSomething;
end;
Tested with Delphi XE4.
For future reference. Using Delphi 2010 i have found that a ; preceding virtual in the interface section makes a difference;
function MyProc(): String; overload; virtual;
function MyProc(): Integer; overload; virtual;
// >> ^ <<
This ; character can break the CTRL+Click (code insight) functionality. Compiles fine nonetheless.
I had just made a new groupproject with two projects in Delphi 11. After that I was having problem using Ctrl + Click to jump to functions. I right clicked the groupproject and did "Clean All" and then "Build All" after that it was working for me again.
(Symbol Reference info)This option has no effect unless Debug information and Local symbols (see above) are enabled.
Code completion and code navigation features (Ctrl+Click) work only when Symbol Reference info is set to Reference info.
Solved!
It works for me, change the Code Insight type.
This happens to me quite often, specially when two IDE is opened at the same time.
The way I have found to fix this is:
Clean your project.
List item
Close the IDE.
With the Windows Explorer, navigate to your project.
Search for *.dcu Delete all the .dcu
Launch the IDE and load your project.
Compile it.
At this point, the code navigation (Ctrl+Click) should work.
I am porting a Delphi application to FPC/Lazarus and this application shows info in splash screen. When unit has initialization section then this initialization section calls something like:
Splash.Info(unit_name)
This works in Delphi, but when I compiled this using FPC/Lazarus then I got exception when I create form with splash screen:
Failed to create win32 control, error 1407 : Cannot find window class
I found, that forms can be created after Application.Initialize; was called, so my workaround is to create splash form when ScreenInfo.Initialized=true. It works, but does not show all info. Is there any way to show splash form from unit initialization section, before Application.Initialize;?
Apparantly the FPC/Lazarus implementation of the VCL differs enough from the Delphi VCL to not allow form initialization before the Application object has been initialized.
So the best you can do to make it work in both Delphi and FPC/Lazarus is either
Delay the initialization until you are sure that both the Delphi VCL and FPC/Lazarus VCL are ready for it
Duplicate your code with conditional defines to generate optimum implementations for both Delphi VCL and FPC/Lazarus VCL
--jeroen
In SplashScreen initialization code that is called for every string I want to show on this splash I finished with:
...
{$IFDEF FPC}
if not ScreenInfo.Initialized then
exit;
{$ENDIF}
if not splash_inititialized then begin
SplashScreen := TSplashScreen.Create(Application);
splash_inititialized := true;
...