Zasoby pliku dll - odczyt ikon

0

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

0

Ściągnij RxLib, tam w dołączonym demo masz wyciąganie Icon oraz bitmap z exe/dll

0

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

0

W Rx jest prosty kod bez komponentów, w tym demo demonstrują coś innego dotyczącego wizualizacji odczytanych danych.

0
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...

0

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:

  1. ciąg znaków z dwoma wpisami (0 i 1) - służą one identyfikacji zasobu, nie są tutaj ważne,
  2. 3 ikonki o nazwach 1, 2 oraz 3 (każda z nich zawiera różne rozmiary),
  3. 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...

0

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:

BinIcon.png

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;

0

Pepe, ja ci już podałem rozwiązanie działające na 100% i z przykładem użycia.

0

Witam, dzięki za kontynuowanie tematu. Odniose się teraz do powyższych.

  1. Dokładnie wiem jak ma wyglądać biblioteka z ikonkami. Zalaczylem w poprzednim poscie.
  2. 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.
  3. Biblioteka z ikonkami nie jest zaprojektowana przeze mnie. Ma format taki jaki ma, dokładnie taki jak podałem
    w przykladowej dllce.
  4. Ikonki znajdują się w sekcji Icon.
  5. Proszę dokładnie przeanalizować bibliotekę która załączylem powyżej.
  • Pawel

Ps: sprawdze dziś rxlib...

1 użytkowników online, w tym zalogowanych: 0, gości: 1