Witam,
Czy ktoś mógłby napisać jak w najprostszy sposób odczytać i wyświetlić na formie ikonki z zasobów dowolnego pliku dll/exe?
Plik powiedzmy ma 20 ikon (w sekcji Icon, każda z nich w czterech rozmiarach (16x16, 32x32, 48x48, 256x266px)).
Będę wdzięczny za wskazówki, dzięki
-Pawel
Ściągnij RxLib, tam w dołączonym demo masz wyciąganie Icon oraz bitmap z exe/dll
Tak, dzięki za powyższe. Obadam (choć kiedyś już analizowałem te źródła).
A teraz, cóż, liczyłem na prosty, gotowy kod :D Bez zbędnych zewnętrznych komponentów etc.
-Pawel
W Rx jest prosty kod bez komponentów, w tym demo demonstrują coś innego dotyczącego wizualizacji odczytanych danych.
Pepe napisał(a)
A teraz, cóż, liczyłem na prosty, gotowy kod Bez zbędnych zewnętrznych komponentów etc.
Proszę bardzo:
procedure TForm1.FormCreate(Sender: TObject);
var
hDLL: hWnd;
rsIcon: TResourceStream;
begin
hDLL := LoadLibrary('DLLWithIcon.dll');
if hDLL <> 0 then
try
rsIcon := TResourceStream.Create(hDLL, 'DLLIcon', 'RT_ICON');
imgDLLIcon.Picture.Icon.LoadFromStream(rsIcon);
rsIcon.Free();
except
on Exception do
MessageBox('Loading icon from DLL failed!', 'Load Icon', MB_ICONSTOP);
end;
FreeLibrary(hDLL);
end;
Co do tego jest potrzebne - utworzenie prostej biblioteki i dodanie do niej pliku zasobów z ikonkami; Po kompilacji plik z zasobami łączy się z biblioteką w jedną całość (więcej o zasobach - Zasoby w Exe) i to wszystko jeśli o bobliotekę chodzi;
W programie głównym w odpowiedniej procedurze wystarczy załadować bibliotekę (funkcja LoadLibrary
dla uchwytu hDLL
) i sprawdzić, czy jej uchwyt jest pusty (hDLL <> 0
); Jeśli nie wskazuje na 0
to znaczy, że załadowanie biblioteki udało się; Następnym krokiem jest utworzenie strumienia zasobów (rsIcon
), gdzie jako pierwszy argument konstruktora podajemy uchwyt biblioteki (pobierana jest ikona o identyfikatorze DLLIcon
typu RT_ICON
), zamiast głównego okna czy hInstance
; Jeśli nie pojawi się wyjątek to znaczy, że zasób został poprawnie załadowany; Kolejnym krokiem jest załadowanie pobranej ikony do kontrolki imgDLLIcon
(tutaj z klasy TImage
) ze strumienia; Na koniec zwolnić strumień oraz bibliotekę przez FreeLibrary
; W załączniku podaję program (ExtractIconFromDLL.zip), w którym wykorzystałem powyższy kod i ikonka z biblioteki ładowana jest pomyślnie; Do skompilowania pod D7 - analogicznie kod można wykorzystać w Lazarusie (ewentualnie z niewielkimi poprawkami, choć powinien się bez problemu dać importować);
Ja w powyższym przykładzie wykorzystałem importowanie zasobu według jego nazwy - można także nie nadawać zasobom nazw jako łańcuchy znaków, lecz liczby; W tak przygotowanej bibliotece możesz umieścić dowolne pliki dowolnego typu, zarówno ikony, kursory, bitmapy, obrazy JPEG
, dźwięki Wave
, czcionki oraz każde inne pliki, gdzie typem zasoby jest RT_RCDATA
; Jeśli chodzi o sposób wyciągania zasobów z biblioteki to jest dokładnie taki sam, jak i z plików wykonywalnych - jedyną różnicą jest ww. argument konstruktora strumienia zasobów - Instance
, gdzie zamiast uchwytu aplikacji czy formularza podaje się uchwyt biblioteki; Więcej o zasobach programu możesz przeczytać w Kompendium Delphi - Rozdział 10 - Biblioteki DLL;
Ja jednak dalej nie wiem, czy potrzebny jest Ci kod do wykorzystania w programie, który wyciąga ikony z biblioteki dla własnego UI, czy edytor zasobów jedynie do przygotowania pliku DLL/EXE...
OK, na początek, dzięki za zainteresowanie tematem.
Sprawdziłem ten kod, rzeczywiście działa. Ale, szybki test na mojej
przykładowej bibliotece z ikonkami pokazuje, że jednak nie o to chodzi (albo robię coś źle).
Spróbuje wyjaśnić szerzej. Może się uda. Otóż, biblioteka ma za zadanie przechowywać ikonki. Każda z ikonek
posiada różne rozmiary (czyli ikonka o nazwie "1" posiada na przykład wersje 32x32, 48x48 i 256x256). Program,
ma za zadanie wyświetlenie dowolnej z nich (i dowolnego rozmiaru, np: odczyt ikonki o nazwie "7" i wyświetlenie jej w rozmiarze 48x48).
Przykładowa biblioteka:
http://shup.com/Shup/557739/TestIcon.dll
Opis:
TestIcon.dll
-String:
0: LibraryName
1: Library Desc
- Icon
1 -> 16x16, 24x24 etc
2 -> 16x16, 24x24 etc
3 -> 16x16, 24x24 etc - Version
Czyli, biblioteka posiada 3 sekcje:
- ciąg znaków z dwoma wpisami (0 i 1) - służą one identyfikacji zasobu, nie są tutaj ważne,
- 3 ikonki o nazwach 1, 2 oraz 3 (każda z nich zawiera różne rozmiary),
- Informacje o wersji (info, które tutaj nie jest istotne).
Zadaniem jest odczyt i wyświetlenie w TImage dowolnej z ikonek oraz dowolnego rozmiaru.
Mam nadzieję, ze teraz jest to jasne i pomożecie. Dzięki.
Ps: Problem dla niektórych może wydawać się trywialny, jednak mimo że mam już pewne
doświadczenie w Delphi nigdy tego poprawnie nie zaimplementowałem. Szczególnie ważne
jest by móc wyświetlić ikonkę w rozmiarze 256x256...
Sprawdziłem ten kod, rzeczywiście działa. Ale, szybki test na mojej
przykładowej bibliotece z ikonkami pokazuje, że jednak nie o to chodzi (albo robię coś źle).
Coś mi się wydaje, że nie rozumiesz co ten kod wykonuje i jak go wykorzystać; Jak napisałem Ci wcześniej w ten sposób można wyciągnąć z zasobów zarówno pliku wykonywalnego (*.exe
) jak i biblioteki (*.dll
) dowolne pliki dowolnego typu zasobów - jedynie co trzeba znać to nazwę zasobu (obojętne czy nazwy są przydzielane jako łańcuch znaków, czy przez indeks) oraz typ zasobu (jak RT_ICON
, RT_BITMAP
, RT_CURSOR
, RT_JPEG
, dowolne pliki RT_RCDATA
czy nawet RT_MANIFEST
i wiele wiele innych); Więcej o typach zasobów możesz przeczytać na: MSDN - Resource Types;
Otóż, biblioteka ma za zadanie przechowywać ikonki. Każda z ikonek posiada różne rozmiary (czyli ikonka o nazwie "1" posiada na przykład wersje 32x32, 48x48 i 256x256).
Sprecyzuj co to znaczy, że "każda z ikonek ma różne rozmiary"; Masz każdy rozmiar w osobnych plikach, czy jeden plik zawierający kilka grafik o różnych rozmiarach? Jeśli to pierwsze, to nie wiem z czym masz problem - wystarczy nadać im odpowiednie nazwy i podanym wcześniej przeze mnie sposobem wyciągać w pętli ikonki i pakować je do jakiejś listy, czy choćby macierzy; Jeśli masz jeden plik z wieloma grafikami (osobna grafika dla każdego rozmiaru w jednym pliku) to należy wyciągnąć taką ikonę z zasobów biblioteki, po czym albo korzystając z gotowych rozwiązań albo ręcznie "wyłuskać" ze strumienia grafikę o zadanym rozmiarze; To drugie rozwiązanie jest trudniejsze i w tym przypadku mało optymalne jeśli nie potrzebujesz potem tej ikony obrabiać i eksportować (jak w edytorze grafiki);
Jeśli potrzebujesz w bibliotece trzymać ikony po to, by program "przystrajał" sobie UI, to utwórz tyle plików, ile jest rozmiarów danej ikony i nazwij je jakoś sensownie, po czym wyciągaj z tej biblioteki to, co Cię interesuje - jeśli potrzebujesz daną ikonę o rozmiarze przypuśćmy 32x32
- wyciąg taką bezpośrednio (bez kombinowania);
Dam Ci przykład - mamy ikonę kosza:
mamy trzy rozmiary, więc tworzymy sobie trzy pliki dla każdego rozmiaru; Nadajemy im podobne identyfikatory, np.: BIN_48x48
, BIN_32x32
i BIN_16x16
; Dodajemy je do pliku z zasobami, po czym plik kompilujemy i dołączamy do programu; W programie gdy chcemy wuciągnąć ikonkę to wystarczy znać identyfikator i wykorzystać podany wcześniej kod:
const
BIN_16x16 = 'BIN_16x16';
BIN_32x32 = 'BIN_32x32';
BIN_48x48 = 'BIN_48x48';
var
hDLL: hWnd;
rsIcon: TResourceStream;
begin
hDLL := LoadLibrary('LibraryName.dll');
if hDLL <> 0 then
try
{ dla rozmiaru 16x16 pikseli }
rsIcon := TResourceStream.Create(hDLL, BIN_16x16, 'RT_ICON');
{ dla rozmiaru 32x32 pikseli }
rsIcon := TResourceStream.Create(hDLL, BIN_32x32, 'RT_ICON');
{ dla rozmiaru 48x48 pikseli }
rsIcon := TResourceStream.Create(hDLL, BIN_48x48, 'RT_ICON');
{ wykorzystanie strumienia z załadowaną ikoną }
rsIcon.Free();
except
on Exception do
MessageBox('Loading icon from DLL failed!', 'Load Icon', MB_ICONSTOP);
end;
FreeLibrary(hDLL);
end;
i to tyle zabawy; Oczywiście identyfikatory zasobom nadaj po swojemu, czy to jako ciągi znaków (dla konstruktora Create
) czy liczbowy indeks (dla kontruktora CreateFormID
); Wypadałoby utworzyć sobie jakąś macierz z identyfikatorami i w pętli (jeśli tak właśnie wczytujesz) pobierać nazwę dla odpowiedniego konstruktora; Jeśli wykorzystać chcesz identyfikatory liczbowe i importować zasób przez indeks, także wypadałoby konkretniej nadawać je zasobom; Dla tego samego zestawu ikon można ustalić im nazwy podobnie - zakładając z góry, że ikona ww. kosza będzie miała indeks np. 1
, poszczególne ikony mogą mieć identyfikatory np.: 116
, 132
i 148
, gdzie liczba setek oznacza jej numer porządkowy, a liczba dziesiątek i jedności (czyli dwie młodsze cyfry) oznaczają rozmiar; To tylko przykład, ja osobiście nie korzystam z liczbowych identyfikatorów - wolę importować zasoby przez nazwę jako ciąg znaków, bo łatwiej jest się połapać;
Ps: Problem dla niektórych może wydawać się trywialny, jednak mimo że mam już pewne doświadczenie w Delphi nigdy tego poprawnie nie zaimplementowałem.
To mnie trochę dziwi, jednak najprawdopodobniej przekombinowałeś z tymi zasobami; Utwórz ich listę intuicyjnie i tak, jak napisałem wcześniej i wykorzystaj podany kod do pobierania ich z biblioteki; Najważniejsze jest tutaj nazewnictwo zasobów i ich zawartość, resztę bez problemu powinieneś wykonać bazując na najprostszym jaki znam sposobie;
Możesz także "w ciemno" próbować importować ikonki, jeśli ich rozmiary nie są jednakowe (np. jedna ikona ma rozmiary 16x16
i 32x32
, a druga 32x32
, 48x48
i 256x256
), ale żeby nie powodować błędów wyłapuj wyjątek EResNotFound
i odpowiednio reaguj; Wtedy algorytm importu ikonek będzie uniwersalny, jednak nie wiem czy wszystkie ikony będą miały jednakowe rozmiary, czy mogą się między sobą różnić;
Jeśli dalej nie wiesz jak to zaplanować i zaimplementować - podaj w końcu kod, którym próbujesz importować zasoby oraz pokaż jakie ikony masz, jak wygląda kod biblioteki oraz jak wygląda plik *.rc
, w którym masz opisane zasoby;
Pepe, ja ci już podałem rozwiązanie działające na 100% i z przykładem użycia.
Witam, dzięki za kontynuowanie tematu. Odniose się teraz do powyższych.
- Dokładnie wiem jak ma wyglądać biblioteka z ikonkami. Zalaczylem w poprzednim poscie.
- Każda z ikonek zawiera kilka rozmiarów. Oznacza to to co ma oznaczać. Ikonka o nazwie "1" jest jednym
plikiem, który ma osadzonych kilka ikonek różnej wielkości. Normalny plik ico. - Biblioteka z ikonkami nie jest zaprojektowana przeze mnie. Ma format taki jaki ma, dokładnie taki jak podałem
w przykladowej dllce. - Ikonki znajdują się w sekcji Icon.
- Proszę dokładnie przeanalizować bibliotekę która załączylem powyżej.
- Pawel
Ps: sprawdze dziś rxlib...