Delphi Firemonkey - loading style at runtime - delphi

I have loaded a couple of the sample styles from ......\RAD Studio\9.0\Styles as resources into my project and am 'simply' trying to load one of them at runtime.
I'm using the following code to try and do this:
var
vResourceStream : TResourceStream;
begin
vResourceStream := TResourceStream.Create( HInstance, 'DARKSTYLE', RT_RCDATA );
try
StyleBook1.LoadFromStream( vResourceStream );
finally
vResourceStream.Free;
end;
It compiles ok but when I run it I get a bunch of errors, the first being 'Property Align does not exist' then 'Error reading TStyleBook.Align: Property Align does not exist' and it seems to do this for a bunch more atributes, Height etc.
Can someone give me some pointers as to how to solve it please?

Not that I know a bit about FMX, but AFAIU the .style files are resource definition files. Instead of reading the stylebook object from the stream, you should read its resource:
StyleBook1.Resource.LoadFromStream( vResourceStream );

For reference, there are LoadFromStream and LoadFromFile methods at TStyleBook, but there is also TStyleStreaming class with an extra LoadFromResource utility method (apart from its own LoadFromStream and LoadFromFile). Probably they should add a LoadFromStream to TStyleBook class too (guess it would call into the respective TStyleStreaming one)

Related

Extracting Resources(i.e .MP4 file) from .BPL packages [duplicate]

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);

Display Bitmap Image from Access to Delphi 7

Regards for all Delphi Guru :)
I have table in Access 2010, one of the column type is OLE Object named "ProductImage"
I use that column to save Bitmap Image.
The problems is, How can I display that image using DBImage or TImage in Delphi 7?
I've tried this
procedure TF_Search2.DBGrid1CellClick(Column: TColumn);
begin
Image7.Picture.Assign(DataModule1.T_Products.FieldByName('ProductImage').LoadFromFile('c:\test.jpg'));
end;
It's error : need parameter in this part 'LoadFromFile('c:\test.jpg')'
I tried also using "TBlobField", but I got error : undeclared identifier TBlobField
I read that it should in unit and uses. I don't understand what's that mean.
Should I add something on installation folder or what?
Any helps would be appreciated.
Thank You
The field also contains an OLE Header. I ancient times I skipped this (I think the first 79 bytes) but I cannot find the code anymore. However, the internet has solutions as always. Imho this one is better than my 'skip' solution.
Here is one of them:How to read and write images from/to an access DB (page 4)
EDIT: I just saw that your problem is your syntax.
procedure TF_Search2.DBGrid1CellClick(Column: TColumn);
begin
Image7.Picture.Assign(DataModule1.T_Products.FieldByName('ProductImage').LoadFromFile('c:\test.jpg'));
end;
This is not valid delphi syntax and quite confusing. The Picture.Assign method expects a picture object. So what you first would want to do is to get the picture out of the access-DB.
You want to read the image data from an access db and display it in an image component?
Follow the steps in the link.
EDIT: I did find some very old code which I modified (and cannot test):
aBitmapStream := TMemoryStream.Create;
tblDrawing_BitmapColumnBLobField.SaveToStream (aBitmapStream);
// This hack enables Access BMP-Blobs to be imported
aBitmapStream.Seek (78,soFromBeginning);
myBitmap := TBitmap.Create;
myBitmap.LoadFromStream (aBitmapStream);
Image7.Picture.Assign (myBitmap);
myBitmap.Free;
aBitmapStream.Free;

How to set THTTPRio.Converter.Options to soLiteralParams in OnBeforeExecuteEvent

This refer to the post Delphi SOAP Envelope and WCF.
Could someone please post a sample code which can show me how to set soLiteralParams in THTTPRio.Converter.Options in Delphi 7. I have the following code currently.
I have drag-dropped a HTTPRIO component into the document which has created a line HTTPRIO1: THTTPRIO at the beginning of the code. I basically want to understand how I set soLiteralParams in the above component. Following is the code I am trying to execute which is giving me error.
procedure TForm1.CleanUpSOAP(const MethodName: String; var SOAPRequest: WideString);
var RIO: THTTPRIO;
begin
//The following line is giving error
// RIO.Converter.options := [soLiteralParams];
end;
In the above code I have declared a variable RIO of the type THTTPRIO, which I am not sure is correct.
Just guessing, as you provide very little information in your question.
Use the variable assigned to the component you dropped on your form. Don't declare a new local one (which you never created anyway). To set the Converter.Options in code, you'll need to add OPToSOAPDomConv to your uses clause.
implementation
uses
OPToSOAPDomConv;
// BTW, this name might not be a good one if it's the
// OnBeforeExecute event handler as that isn't
// clear from the name.
procedure TForm1.CleanUpSOAP(const MethodName: String; var SOAPRequest: WideString);
begin
// Note this clears any previous options!
HTTPRIO1.Converter.Options := [soLiteralParams];
// If you want to keep the previous options instead of replacing them
// HTTPRIO1.Converter1.Options := HTTPRIO1.Converter1.Options + [soLiteralParams];
end;
If you've dropped the component on the form, I'm not sure why you're not handling this in the Object Inspector instead, however.
If this doesn't solve the problem, edit your question and provide the exact error message you're receiving, including any memory addresses in the case of an exception being raised.
I have cracked this. The issue was that I didn't refer to OPconvert.pas file, which contained the TSOAPConvertOption enumeration. I don't know whether copying this file into the same folder as my project files and referring to this in the "uses" section is the right way, but it worked fine.

Delphi XE2: Reloading a custom VCL style from file?

I'm loading a custom style from file using:
TStyleManager.LoadFromFile(filename)
When the file is changed I want to load it again. But if I try that I get a EDuplicateStyleException because the style is already registered.
Is there a way to unload a style so I can load it again? The typical case for this is that you are making changes to a custom style and want to see it in action without restarting the whole application.
After scanning the sources I guess that is not possible in a straight forward way. Your only chance might be to implement some dirty hack.
Whatever you do, you should write a QC for this. Embarcadero could implement to reload the file if the style already exists instead of raising an exception. That would look like a natural behaviour to me.
Check this project vcl styles utils, one of the features exposed is the capacity of unload a vcl style. Just include the Vcl.Styles.Ext unit in your project and then use this code.
TStyleManager.RemoveStyle('Carbon');
Another idea:
This might work. Partial code for simplicity. In the code below, you first get a handle to the already registered Style. I guess then, you can dispose and re-assign the pointer with the one you loaded from the file. I believe the exception only show when you try to apply the style, not when you load it. Forgive me if I am wrong.
var
StyleName: String;
Style : TStyleManager.TStyleServicesHandle;
FileName : String;
begin
StyleName := 'Obsidian'; // or another style name
FileName := 'obsidian.vsf'; // or any other valid style file name
Style := TStyleManager.Style[ StyleName];
if Assigned( Style) then // style already registered
begin
TStyleManager.TrySetStyle( StyleName);
// insert other processing here
end
else // style not registered
begin
if TStyleManager.IsValidStyle( FileName) then
begin
Style := TStyleManager.LoadFromFile( FileName);
if Assigned( Style) then
begin
// insert other processing here, such as
// TStyleManager.SetStyle( Style);
end;
end;
end;
end;
Try this:
procedure TfrmMain.Button11Click(TObject *Sender);
var
MyStyle TCustomStyleServices;
const
usStylePath= 'c:\Users\Public\Documents\Embarcadero\Studio\19.0\Styles\vcl\MINE.vsf';
begin
if TStyleManager.IsValidStyle(usStylePath)
begin
// Get current style
MyStyle:= TStyleManager.Style["Emerald"]; // this will return a TCustomStyleServices obj
if (MyStyle <> NULL)
begin
// Set default Windows style (no style)
TStyleManager.SetStyle(TStyleManager.SystemStyle);
// Remove it
TStyleManager.UnRegisterStyle(MyStyle);
end;
// Load style from disk
TStyleManager.LoadFromFile(usStylePath);
TStyleManager.SetStyle(Emerald");
end;
end;
Note: I never complied the code. But it should work.
Anyway, you should use RRuz's library. He knows a lot about these VCL styles.
You could make a copy of each style in another file with different name of the style. Then you could load it's copy as a workaround. If you really need original then you can load it after loading copy.

How to retrieve a resource from within a tWebModule

I am trying to extract a gif image embedded as a resource within my ISAPI dll using WebBroker technology. The resource has been added to the DLL using the following RC code:
LOGO_GIF RCDATA logo.gif
Using resource explorer I verified it is in the DLL properly.
using the following code always throws an exception, "resource not found" (using Delphi 2009)
var
rc : tResourceStream;
begin
rc := tResourceStream.Create(hInstance,'LOGO_GIF','RCDATA');
end;
RCDATA is a pre-defined resource type with an integer ID of RT_RCDATA (declared in Types unit).
Try accessing it this way:
rc := tResourceStream.Create(hInstance,'LOGO_GIF', MakeIntResource(RT_RCDATA));
If I remember correctly you are actually dealing with an instance of the web server, not the dll. I don't remember the work around though, but that is the explanation for why that doesn't work. Hopefully someone else can build off of this.
Either use your own arbitrary resource type like GIF:
LOGO_GIF GIF logo.gif
then use
rc := tResourceStream.Create(hInstance,'LOGO_GIF','GIF');
or simply use
rc := tResourceStream.Create(hInstance,'LOGO_GIF', RT_RCDATA);
or simply use
rc := tResourceStream.Create(hInstance,'LOGO_GIF', RT__RCDATA);
This. Works like a charm.
D2009 here, too, had the same issue, but was trying to get TStringsList out of the DLL.
Thanks.

Resources