How to get the shell folder icon location for a specific folder? - delphi

In Delphi XE7, I need to get the LOCATION of the icon used by Windows Explorer to display a folder, especially in thumbnail view. So I use this code:
var
Shell32DllFilePath: string;
// Get shell32.dll FilePath:
Shell32DllFilePath := IncludeTrailingPathDelimiter(JclSysInfo.GetWindowsSystemFolder) + 'shell32.dll';
if not FileExists(Shell32DllFilePath) then
begin
Shell32DllFilePath := '';
// Todo: log this error
end;
Then I ASSUME that the default folder icon is the icon with IconIndex 3 in shell32.dll:
However, this gives me a static image for every folder, while Windows Explorer uses different folder icons according to the folder location and/or the folder content.
So how can I get the exact folder icon location (icon dll file and icon index) Windows Explorer uses for any SPECIFIC folder?

There may not be a file path to an icon with the way Windows works. You mention "especially in thumbnail view", which means images and icons (within the folder) are stacked together in the folder icon. This does not save a file anywhere, so you can't load from any file.
I'm assuming this is the type of icon you're talking about:

Related

How can I use ALL system registered themes/styles in my Delphi App?

With Vcl.Themes.TStyleManager.StyleNames, I have access to just the style names enabled in the project options (Application/Appearance).
How can I list all of the style names registered in the system, and make it active in Delphi 11?
This is how I fill a TComboBox with the available styles:
procedure FillComboboxWithStyles;
var
stylename: string;
begin
for stylename in TStyleManager.StyleNames do
CBVclStyles.Items.Add(stylename);
end;
To activate a certain style you fill TStyleManager.SetStyle(const Name: string) with the stylename. For example the selected one from the TComboBox.
if (CBVclStyles.ItemIndex >= 0) then
TStyleManager.SetStyle(CBVclStyles.Items[CBVclStyles.ItemIndex])
else
;// handle a non-selected style
Don't forget Vcl.Themes in your uses.
You can include the style files (*.vsf from C:\Program Files (x86)\Embarcadero\Studio\22.0\Redist\styles\vcl with 22.0 marking your RAD Studio version) along with (externally from) your .EXE and then iterate over them when you fill your ComboBox. Then manually load the style from the file with TStyleManager.LoadFromFile when selected.
This will also allow your user to add his own style files to the setup.
This, I believe, is what the IDE does (except that it reads the list directly from the folder, since there's no "installation" of a style other than making the file available in a recognized location).

Changing paths in Delphi

I am working on a project where I need to play a video from a file in Delphi. I often work from home and school, and I have the problem that at home, my USB is drive 'J' and at school my USB is drive 'D'.
I manually go and change it every time. Is there a way for Delphi to automatically get the video from where ever it is?
Each sector has an image component laid over it for selecting the sector.
*Note, I know I can search for a specific file's location in Delphi, but I have over 24 different places where I need to play different videos, so searching would probably be my last resort, unless I use a procedure and set constants for each sector to differenciate between them.
The code currently looks as follows:
procedure TtForm.imgSector1Click(Sender: TObject);
begin
//Variables,this is for initializing them when I create them later.
//Procedures
SectorDeselect; //Procedure to turn all sector borders white
// Video
WindowsMediaPlayer1.Controls.stop;
WindowsMediaPlayer1.URL := 'J:\IT\PAT\phase 2\Videos\Footage1.mp4'; //Where my problem lies
WindowsMediaPlayer1.Controls.Play;
// Sector Info. The memos and Rich edits
redSectorInfo.Lines.Clear;
redSectorInfo.Lines.Add('');
// Sector. Highlighting the sector borders surrounding the sector
SectorBordr1.Brush.Color := clGreen;
SectorBorder10.Brush.Color := clGreen;
end;
I would suggest adding a TEdit control in your app's UI to let you specify the base drive/path for the files on the machine the app is currently running on. Your code can then construct individual file paths at runtime that are relative to that base path. Don't use hard-code paths in your code.
You can then save that base path into the Windows Registry in a new key you create, ie HKEY_CURRENT_USER\Software\MyApp. Or, you can save the path in a configuration file (INI, XML, JSON, etc) created in a subfolder in your Windows user profile, like %APPDATA%\MyApp. Your code can then read in that base path each time the app is run.
If the files are stored on a USB drive, an alternative solution would be to simply enumerate the available drives at runtime, such as with GetLogicalDriveStrings(). For each drive, append a relative path for a given file onto the end of it, and then check if that file exists, such as with FileExists(). If so, you now know which drive to use for all of the files until the next time your app is run (you can save the drive path between runs, as described above). If the file is not found, move on to the next drive.
What about adding a parameter on the CommandLine?
Start
D:\myfolder\myfile D
OR
Start
J:\myfolder\myfile J
GUI files can accept a parameter. Capture it with code like:
DriveLetter := ParamStr(1);

How cand I include a bitmap in my custom component (if is possible)?

I am writing a component (a button) which needs a bitmap to be displayed on it. I don't want to make an ImageList property and the user assigns an image. I want that button to have only the image chosen by me.
I tried to include the bitmap in a resource file but when I try to access it I get "Resource not found" error message. This is what I've done:
myres.rc
FIXED BMP "fixed.bmp"
I compiled the resource file with: brcc32 myres.rc
Then I included it in my component unit...
implementation
{$R .\resources\myres.res}
And access it with...
MyComponent.Glyph.LoadFromResourceName(HInstance,'FIXED');
// MyComponent = class(TSpeedButton)
Edit1:
I deleted the {$R .\resources\myres.res} directive and I loaded the resource from menu Project -> Resources and it's working, both with HInstance or FindClassHInstance(MyComponent).
Using a resource editor I found that when I load the resource from the menu the resource appears with the name "FIXED" as it should, but when I load the resource compiled with brcc32 it appears with the name "0". It seems that brcc32 doesn't set the name correctly.
But I don't want to load it from menu, I want it to be loaded automatically with the component.
Edit2:
Remy Lebeau is correct. I was using a wrong BMP format (the file starts with 'BM6' characters instead 'BM8' like Photoshop produce it, and it works).
Change BMP to BITMAP in your RC file, and change HInstance to FindClassHInstance() in your code:
FIXED BITMAP "fixed.bmp"
Glyph.LoadFromResourceName(FindClassHInstance(MyComponent), 'FIXED');

Adding a .res file to project replaces the default icon.How to prevent it?

I needed to add some icons to my project as a resource (I can't use a TImageList in this case, because of a bug in TCoolTrayIcon, and I can't replace the component quickly).
I've created an icons.rc script to add the two ico files to a Delphi resource file:
redicon ICON "c:\icon\red.ico"
greenicon ICON "c:\icon\green.ico"
it compiles fine to icons.res, so I add it to the first unit of my Delphi 7 project:
{$R icons.res}
then I store the handles in OnCreate() of the MainForm:
hRedIcon := LoadIcon(hInstance,'redicon');
hGreenIcon := LoadIcon(hInstance,'greenicon');
and then use the handles just fine.
Now to the problem - after doing that the project icon that was added in the project options (in sizes of 16x16 to 48x48) is replaced by the first icon (16x16 redicon) I've added in {$R icons.res}.
How to prevent this? How to add additional icons to a project as a resource without replacing the icon that is added in Project Options -> Application -> Load Icon?
The VCL hard codes the name 'MAINICON' for your application's icon. This can be seen in the code in TApplication.Create:
FIcon.Handle := LoadIcon(MainInstance, 'MAINICON');
On the other hand, the shell assumes that the first icon in your executable is the main application icon. The order that the shell uses is alphabetical by icon name.
The consequence of this is that all your icons should have names that appear after MAINICON in the alphabet.

How I Compile Resources into my Application and Access them?

How can I make a single executable package that contains DLL and Image Resource Files?
Then how do I extract them from my Executable at Runtime?
Option 1 using the IDE (Delphi 2007 or Higher):
You can click the Project menu, then select Resources..., which you can load any file into. For your purpose this would be RC_DATA.
Option 2 without the IDE
If you do not have the above option, you will need to use the BRCC32 (Borland Resource Compiler) to create a .RES file from RC file, which you then link to your Application. To link Resource files without using the IDE, try the following:
Lets say for example we want to add a a couple of DLL files, and the name of the DLL files are MyLib1.dll and MyLib2.dll, to add this open Notepad, and type the following:
MYLIB1 RCDATA "..\MyLib1.dll"
MYLIB2 RCDATA "..\MyLib2.dll"
Make sure the ..\xxx.dll paths are correct, so obviously you need to edit that.
Now you need to save this as a .rc file, so File>Save As..(make sure the dropdown filter is All Files .) and name it MyResources.rc. Now you need to use the Resource Compiler to generate the Res file, using this console command:
BRCC32 MyResources.RC
You can write that command by using the Command Prompt, Start Menu > Run > cmd.exe, alternatively you can find the BRCC32.exe inside the bin folder of your Delphi setup and drag the MyResource.RC file onto.
This will create a Res file named MyResources.RES which you can include inside the Main Delphi form of your Application, like so:
{$R *.dfm}
{$R MyResources.res}
you can extract the resources by using something like this:
procedure ExtractResource(ResName: String; Filename: String);
var
ResStream: TResourceStream;
begin
ResStream:= TResourceStream.Create(HInstance, ResName, RT_RCDATA);
try
ResStream.Position:= 0;
ResStream.SaveToFile(Filename);
finally
ResStream.Free;
end;
end;
What I've found out to be convenient, is to use a .zip container.
Then you'll have two implementations:
Append some .zip content to an existing .exe, and the .exe code will retrieve the .zip content on request;
Embed the .zip content as a resource, then extract on request each content.
Solution 1 will add the .zip content after compilation. Whereas 2 will add the .zip content at compilation. For a setup program, I think solution 1 makes sense to me. For a way of retrieving some needed files (libraries, and even bitmaps or text) which are linked to a particular exe release, solution 2 could be envisaged.
Using .zip as format make it easy to parse the content, and allow compression. Using a tool like TotalCommander, you can even read the .zip file content with Ctrl+PgDown over the .exe. Very convenient.
You'll find in this link how you implement solution 1, and in this link (same page, but another post) how to use the TZipRead.Create() constructor to directly access to a .zip bundled as resource. You'll find in our repository how it works with working applications: e.g. how we embedded icons, textual content and graphviz + spell-checker libraries in the SynProject executable.
About performance, there is no difference between the two solutions, at least with our code. Both use memory mapped files to access the content, so it will be more or less identical: very fast.

Resources