artykuły

Delphi - Zasoby

20:36
śro, 8 wrzesień 2004
Artykuł opisujący tworzenie i wykorzystywanie zasobów w Delphi. Krok po kroku pokazuje jak tworzyć i dołączać do programu zasoby, takie jak np. ikony, kursory, obrazki i inne. Do artykułu dołączona jest skromna autorska aplikacja umożliwiająca łatwe i szybkie utworzenie zasobu.

Wstęp

Pisząc ten artykuł, postanowiłem sobie za cel wytłumaczenie istoty zasobów programistom. Choć na pewno spora część "pisarzy kodu" zetknęła się już z tym pojęciem to myślę, że mała powtórka nikomu nie zaszkodzi, może nawet uzupełni niektóre luki (?). Przynudzać dalej? Chyba nie. Zabieramy się więc do roboty.

Czym są zasoby?

Na pewno nieraz zdarzyło Ci się, że program ładował grafikę, której nie było na Twoim dysku. Zastanawiałeś się pewnie wtedy gdzie ten obrazek jest zapisany, jak nie w pliku BMP. I tu wkraczamy w świat zasobów. Zasoby umożliwiają nam włączenie do pliku EXE innych plików (obrazki, ikony, kursory, itp.).

Jak je podejrzeć?

Do podglądania zasobów innych programów, możemy użyć takich programów jak Restorator, czy ResHacker. Osobiście polecam pierwszy program - Restorator. Jest to rzadkie połączenie możliwości i prostoty obsługi, które w zupełności wystarczy nam do podglądnięcia, a nawet zmiany zasobów innych programów.

Jak stworzyć zasób dla naszego programu?

Powinniśmy rozpocząć od przygotowania pliku, jaki chcemy włączyć do zasobów. Przypuśćmy, że to będzie plik graficzny (jakiś obrazek BMP). Dla wygody zakładamy na dysku nowy katalog do którego kopiujemy naszą grafikę i program brcc32.exe który domyślnie znajduje się w podkatalogu Bin katalogu z Delphi ;). Domyślna ścieżka wygląda więc następująco:

C:\Program files\Borland\Delphi6\Bin\brcc32.exe 

W naszym katalogu mamy teraz obrazek i program. Teraz tworzymy nowy plik tekstowy .txt i piszemy:

; To jest komentarz jednoliniowy, który może zostać pominięty NaszObrazek BITMAP "obrazek.bmp"

Jak widzicie składnia przedstawia się następująco:
DowolnaNazwaZasobu    TypZasobu    "NazwaPlikuDoWłączenia"

Zapisujemy nasz plik tekstowy i zamykamy edytor (np. Notatnik). Teraz zmieniamy rozszerzenie naszego pliku na .rc .
Kolejnym krokiem jest uruchomienie programu brcc32.exe . Powinniśmy to zrobić następująco:

  1. Otwieramy okno konsoli MS-DOS.
  2. Wpisujemy ścieżkę do programu brcc32.exe, a po niej ścieżkę do pliku .rc . Przykładowo:C:\katalog\brcc32.exe C:\katalog\mojzasob.rc
  3. Program "kompiluje" nam wszystko do pliku RES (plik z zasobami Delphi).
  4. Możemy już usunąć naszą Bitmapę i program brcc32.exe zostawiając jedynie nowopowstały plik RES (będzie nam bardzo potrzebny, ponieważ to właśnie w nim siedzi teraz nasza bitmapa).

Trudne? Troszkę, ale dojdziecie do wprawy.
No dobrze, ale co wpisać do pliku RC w przypadku gdy chcemy umieścić w zasobach inny program, a nie bitmapę? Aplikacje są typu RCDATA, więc należy wpisać:

; To nasz kochany komentarz NaszProgramik RCDATA "program.exe" Oto inne, przydatne typy zasobów:
Tabela 1.1 - Typy zasobów
Typ pliku do włączenia Nazwa typu dla zasobów (plik RC) Nazwa typu zasobów w Delphi
Bitmapa BITMAP RT_BITMAP
Obraz JPEG JPEGFILE JPEGFILE
Dźwięk typu Wave WAVE WAVE (w przypapadku odczytywania przez strumien) lub SND_RESOURCE (w przypadku funkcji PlaySound)
Czcionka FONT RT_FONT
Kursor CURSOR RT_CURSOR
Ikona ICON RT_ICON
Program RCDATA RT_RCDATA
Informacja o wersji programu VERSION RT_VERSION

Mamy plik RES. Jak to teraz władować do naszego EXE'ca?

Jest to chyba najprostsze do wykonania, ale trudne do zgryzienia ;). Dlaczego? Ponieważ aby władować zasób do EXE'ca należy napisać w sekcjiinterfacenastępujący "komentarz":

{$R C:\naszkatalog\ppp.RES}

Taaa... Ktoś Ci mówił, że kompilatora nie interesują komentarze i w ogóle na nie nie patrzy? No właśnie. A jednak! Jest to specjalny typ komentarzy na które, jak się okazuje, kompilator zwraca szczególną uwagę. Są to tak zwane dyrektywy. Kiedyś sobie o nich więcej powiemy. Póki co, skompilujcie kod i sprawdźcie ile zajmuje nasz EXEc. Niewiarygodne? Jeśli wsadziliśmy do niego duuużą bitmapę (powiedzmy 1 MB) od razu się zorientujemy, że również program ma dużo większy rozmiar. Udało się więc.
Pozostała nam jeszcze jedna sprawa, mianowicie: wyciąganie naszej bitmapy z zasobów i wyświetlanie jej. Zaczynamy!

Wyciąganie bitmapy z zasobów

Aby wyciągnąć bitmapę z zasobów potrzebujemy położyć na formę przycisk (paleta Standard) i komponent Image (paleta Addtional). Gdy już to zrobimy, klikamy dwukrotnie na przycisk, przenosząc się tym samym do Edytora Kodu. Piszemy:

var Obrazek : TBitmap; begin Obrazek := TBitmap.Create; Obrazek.LoadFromResourceName(hInstance, 'Obrazek'); Image1.Picture.Bitmap := Obrazek; Obrazek.Free;

Już tłumacze te zawiłe instrukcje. Pierwsza linijka to zadeklarowanie zmiennej Obrazek jako TBitmap (jako bitmapę). Dalej następuje utworzenie zmiennej (kto czytał "Delphi - Strumienie #3" - wie dlaczego). Następnie wczytanie do zmiennej obrazku z zasobów za sprawą funkcji LoadFromResourceName(). Gdy zauważycie analogię do LoadFromFile(), będzie Wam łatwiej ją przyswoić. Jej budowa jest następująca:

LoadFromResourceName(Instance: THandle; const ResName: string)

Pierwszym jej parametrem jest uchwyt. My podajemy tutaj hInstance (czyli uchwyt który mówi, że będziemy korzystać z zasobów). Kolejny, drugi parametr to nazwa zasobu jaką nadaliśmy naszej bitmapie pisząc plik RC, czyli jeśli ktoś zatem napisał...

; To jest komentarz jednoliniowy, który może zostać pominięty NaszObrazek BITMAP "obrazek.bmp" ...to w to miejsce wpisujemy 'NaszObrazek'. Rozumiecie?

Kolejna linia:

Image1.Picture.Bitmap := Obrazek;

Wyświetla w komponencie naszą bitmapę poprzez przypisanie do komponentu zmiennej Obrazek.
W ostatniej linii następuje zwolnienie pamięci wykorzystywanej przez zmienną Obrazek (już nie będzie nam potrzebna, bo skopiowaliśmy ją i jest teraz wyświetlana w komponencie).
Uruchomcie teraz program. Na pewno działa! Oczywiście plik ppp.RES siedzi w EXEcu i możecie spokojnie go usunąć pod warunkiem, że nie będziecie już nigdy więcej kompilować programu (kompilatorowi ten plik jest potrzebny). 

Ładowanie ikon...

...jest nieco złożone, ponieważ ikony nie mają swojej funkcji ładującej tak jak to mają bitmapy (LoadFromResourceName()). W przypadku ikon musimy korzystać z funkcji udostępnianych przez WinAPI - w tym wypadku LoadIcon(). Funkcja ta zwraca nam uchwyt ikony którą chcemy załadować. Zobaczmy jak to zrobić. Najpierw musimy stworzyć plik RC, który wyglądał będzie tak:

NaszaIkonka ICON "Ikona.ico"

Oczywiście do katalogu w którym mamy plik RC przenosimy iknoę i nadajemy jej nazwę "Ikona.ico".  Spójrzcie teraz jak wyświetlić ikonę z zasobów:

var Ikonka : TIcon; begin Ikonka := TIcon.Create; Ikonka.Handle := LoadIcon(hInstance, 'NaszaIkonka'); Image1.Canvas.Draw(0, 0, Ikonka); Ikonka.Free;

To wszystko! Powinno działać!

Ładowanie kursorów

Gdzieś znalazłem ( chyba na http://4programmers.net) mały, prosty i przydatny kod, który umożliwi nam szybkie wczytanie kursora z zasobów, proszę:

Screen.Cursors[1] := LoadCursor(hInstance, 'ID_CUR1'); Screen.Cursor := 1;

"ID_CUR1" to w naszym przypadku nazwa zasobu (którą podajemy pisząc plik RC).

Odtwarzanie dźwięku bezpośrednio z zasobów...

...jest prostsze niż przypuszczasz. Wystarczy jedynie skorzystać z jednej z procedur modułu MMSystem. Musimy go więc dodać do naszego programu. Aby to uczynić ;) należy dodać do listyuses, znajdującej się na początku modułu słówko MMSystem (po przecinku). W ten sposób uzyskaliśmy dostęp do multimedialnych funkcji z których wykorzystamy na razie tylko jedną - PlaySound().
Funkcja ta ma spore możliwości (jak na prostą funkcję ;), aczkolwiek za jej pomocą bynajmniej nie zbudujemy kombajnu multimedialnego to możemy postarać się urozmaicić naszą aplikację dźwiękami. Jak za jej pomocą odegrać zwykły plik WAV (bo tylko takie pliki ona odgrywa)? To proste, spójrzcie:

PlaySound('C:\plik.wav', 0, SND_FILENAME);

... a jak teraz odegrać plik bezpośrednio z zasobów? Popatrz:

PlaySound('NazwaZasobu', hInstance, SND_ASYNC + SND_RESOURCE);

Przy czym musimy oczywiście pamiętać o dyrektywie, którą umieszczamy przed sekcjąimplementationi która wskazuje kompilatorowi lokalizację zasobu do włączenia.
Jak widzicie powyższa funkcja jako pierwszy parametr przybrała nazwę zasobu (zamiast nazwy pliku). Jako drugi parametr mamy uchwyt zasobów naszego programu. Trzecim parametrem natomiast jest flaga (albo flagi < da się zastosować więcej niż jedną). Taka flaga może oznaczać dla funkcji poszczególne zachowania. W naszym wypadku flagi "mówią" funkcji, że dźwięk odgrywany będzie z zasobów (flaga SND_RESOURCE) oraz, że nasza aplikacja ma się typowo nie wieszać (ah, ten system wielozadaniowy ;) podczas odgrywania dźwięku (flaga SND_ASYNC). Możliwe są jeszcze inne flagi:

Tabela 1.2 - opisy flag procedury PlaySound
Flaga Opis flagi
SND_ALIAS Gdy użyjesz tej flagi, pierwszy parametr funkcji PlaySound() będzie wtedy oznaczał nazwę dźwięku systemowego. Np. jako pierwszy parametr można wtedy wprowadzić 'MailBeep' co wygeneruje dźwięk nadchodzącej poczty. Reszta dźwięków znajduje się w rejestrze systemowym (klucz: HKEY_CURRENT_USER\AppEvents\EventLabels)
SND_FILENAME "Mówi" funkcji PlaySound(), że pierwszy parametr to ścieżka do pliku dźwiękowego.
SND_NOWAIT Polecenie nakazuje zignorowanie odtwarzania w przypadku, gdy jest odtwarzane coś innego.
SND_NOSTOP Ta flaga powoduje uruchomienie odtwarzania, tylko wtedy, gdy nie jest uruchomiony żadny inny utwór.
SND_RESOURCE Nakazuje funkcji odtwarzanie bezpośrednio z zasobów.
SND_LOOP Powoduje zapętlenie utworu. Należy używać wraz z funkcją SND_ASYNC.
SND_ASYNC Dzięki tej fladze, będzie możliwe odtwarzanie naraz dwóch dźwięków.
SND_NODEFAULT Jeśli funkcja nie może odnaleźć wymaganego pliku do odtwarzania, zazwyczaj wydaje systemowe piknięcie. Ta flaga likwiduje to piknięcie w momencie gdy funkcja nie znajdzie pliku.
SND_PURGE Flaga oznacza zatrzymanie odtwarzania. Używa się jej jedynie do dźwięków opisanych jako "non-waveform". Aby zatrzymać odtwarzanie normalnego dźwięku należy przeczytać akapit "Zatrzymywanie odtwarzania dźwięków" znajdujący się w tym artykule ;)

Tabela 1.2 - Flagi funkcji PlaySound() na podstawie artykułu
"Multimedia w Delphi" autorstwa Adama Boducha.

Zatrzymywanie odtwarzania dźwięków

Aby zatrzymać odtwarzanie dźwięku, należy wywołać funkcję z pierwszym parametrem ustawionym jakonil:
Przykładowo, rozpoczynając odtwarzanie w ten sposób:PlaySound('Bomba',hInstance,SND_ASYNC+SND_RESOURCE);... możemy je zakończyć w następujący sposób:PlaySound(nil,hInstance,SND_NODEFAULT);Aby zatrzymać odtwarzanie dźwięku określanego w dokumentacji API systemu Windows jako "non-waveform" należy skorzystać z flagi SND_PURGE, którą dodajemy do trzeciego parametru.

Jak uruchomić program bezpośrednio z zasobów?

Odpowiedź na to pytanie znajdziecie w moim artykule z cyklu "Delphi - strumienie" dotyczącym strumienia TResourceStream.

Jak ustawić czcionkę przechowywaną w zasobach?

Jest możliwość dodania do systemu czcionki przechowywanej w zasobach programu. Niestety, nie udało mi się opracować eleganckiej metody polegającej na niezapisywaniu czcionki na dysku. Będziemy musieli zadowolić się więc nieco mniej eleganckim rozwiązaniem: var odpowiedz : DWORD; RS : TResourceStream; begin RS := TResourceStream.Create(hInstance,'czcionka','RT_FONT'); RS.SaveToFile('.\czcionka_drifttype.ttf'); RS.Free(); odpowiedz := AddFontResource('.\czcionka_drifttype.ttf'); // Ustawianie czcionki - UWAGA - należy podac oryginalną nazwę czcionki a nie nazwę zasobu czy pliku Memo1.Font.Name := 'DriftType'; Memo1.Font.Size := 30; // Informowanie wszystkich kontrolek o sytuacji dodania i zmiany czcionki SendMessage(HWND_BROADCAST, WM_SETFONT, 0, 0); SendMessage(HWND_BROADCAST, WM_FONTCHANGE, 0, 0); end; Oczywiście, aby powyższy kod zadziałał, musimy najpierw utworzyć zasób o zmiennej czcionka i dodać do naszego modułu informację o tym, że kompilator ma wkompilować nasz zasób do wynikowego EXEca:{$R czcionka.RES}Kod źródłowy niniejszego rozwiązania znajdziecie na końcu tego artykułu.
Jak wspomniałem, próbowałem znaleźć najpierw rozwiązanie eleganckie, które nie wymagało by zapisywania zasobu na dysk, ale wczytania go bezpośrednio z pamięci. Problem polega jednak na tym, że system Windows nie daje nam tak dużych możliwości w tym zakresie jak ma to miejsce z kursorami, ikonami czy innymi zasobami (jak np. dźwięki). Chcąc wczytać czcionkę z zasobów, prawdopodobnie postępowalibyśmy tak samo jak wyżej (jeśli chodzi o wczytanie zasobu do strumienia TResourceStream), jednak późniejsze załadowanie czcionki potoczyłoby się zapewne inaczej, coś w ten deseń: // w sekcji var zainstalowanych : DWORD; uchwyt : HFONT; // w ciele funkcji (po słowie begin, po zwolnieniu obiektu RS) zainstalowanych = Screen.Fonts.Count; uchwyt := AddFontMemResourceEx(RS.Memory,RS.Size,0,@zainstalowanych); Następnie moglibyśmy spróbować zrobić coś takiego: Memo1.Font.Handle := uchwyt; Jednak, cóż... ten sposób nie wypali. Również nigdzie w Internecie nie udało mi się znaleźć rozwiązania. Cóż... być może ktoś kiedyś na to wpadnie.

Czy do zasobów można dodać inne pliki, jak choćby pliki tekstowe?

Tak, da się. Jednak musimy w tym przypadku utworzyć z nich zasób o nieprawidłowym typie - na przykład jako JPEGFILE. Z racji, że Kreator Zasobów nie ma możliwości wykonania pliku RC wskazującego na inny typ niż typ prezentowany przez wskazywany plik, musimy utworzyć plik RC sami. Tworzymy więc plik RC o następującej treści:wiadomosc JPEGFILE "C:\wiadomosc.txt"i wydajemy polecenie:.\brcc32.exe TUTAJ_SCIEZKA_DO_PLIKU_RC.rcPowstanie nam plik RES. Kolejnym krokiem jest przekopiowanie go do folderu z naszym projektem, napomknięcie kompilatorowi, aby wkompilował nasz zasób:{$R NAZWA_PLIKU_ZASOBU.RES}...i wyciągnięcie zasobu oraz zapisanie go do pliku: var RS : TResourceStream; begin RS:=TResourceStream.Create(hInstance,'wiadomosc','JPEGFILE'); RS.SaveToFile('C:\oryginal.txt'); RS.Free; ... tak więc wykonuje się to dokładnie tak, jakbyśmy zapisywali na dysku obrazek.

Zakończenie

Być może kiedyś powiem więcej na temat zasobów. Dla tych którzy chcą więcej - zapraszam do "Delphi - strumienie - TResourceStream". Znajdziecie tam bardzo prostą metodę na zasoby. Jak na dziś wystarczy. Sam wiem, że temat zasobów jest dość trudny dlatego dołączam źródła do tego artykułu:

Kody źródłowe:

Dla chcących przyśpieszyć sobie pracę, napisałem program, który automatycznie tworzy pliki RES. Wystarczy wskazać mu plik jaki chcemy włączyć do zasobów i nacisnąć przycisk - prościej się nie dało ;)
Program dostępny jest tutaj. Ale UWAGA! Przed rozpoczęciem pracy z programem musicie go skompilować oraz przekopiować program brcc32.exe z podkatalogu Bin katalogu Delphi do katalogu z programem "Kreator zasobów".

Przy pisaniu artykułu korzystałem z:

12345
Delphi - Zasoby Autor opinii: Czytelnicy, data przesłania: 5

Podobne artykuly:

Skomentuj

Aby zamieścić komentarz, proszę włączyć JavaScript - niestety roboty spamujące dają mi niezmiernie popalić.






Komentarze czytelników

    • TomRiddle
    • pon, 7 luty 2011, 13:24
    • To pytanie na dole jest nie aktualne, Ale mam inne.
      Jak odtworzyć dźwięk WAV, powiedzmy 0:00 - 0:30, potem od 0:30 - 2:30, i potem znowu 0:30-2:30 (i tak pare razy w pętli) i potem 2:30 do końca?




      Odp: Nie jest to możliwe z wykorzystaniem funkcji PlaySound. Aby to zrobić, należy wyekstrahować zasób dźwiękowy (np. do pliku lub do strumienia) i użyć dowolnej klasy (np. komponentu) który umożliwia odtwarzanie dźwięku (z pliku lub strumienia) oraz umożliwia ustalenie parametrów tego odtwarzania (np. kontrola pozycji startowej). Można to zrobić za pomocą standardowego komponentu TMediaPlayer.
    • TomRiddle
    • nie, 6 luty 2011, 16:58
    • A ja mam takie pytanie, jak wyciągnąć program z zasobów i zapisać go gdzieś na dysku?
    • amator
    • śro, 22 grudzień 2010, 16:41
    • Przeczytałem artykuł o dołączaniu plików .wav, i inych do zasobu pliku .exe. Okazał się bardzo pomocny.
      Przy okazji przeglądania podręcznika programowania w Delphi znalazłem sposób na uruchomienie
      plików .avi z zasobu. o oto kod:


      begin
      with Animate1 do
      begin
      ResHandle:= hInstance;
      //nazwa zgodna z podaną w pliku tekstowym .rc i .res
      ResName:= 'nazwa_pliku';
      Animate1.Visible:=True;
      Active:= True;
      end;
      end;


      Wykorzystujemy komponent TAnimate z palety Win32 i manipulujemy kodem zmieniając w miarę potrzeb
      nazwy plików avi "skompilowanych w zasobie" lub dodając kolejny kod. Zastosowałem tę metodę
      w swoim programie (2 pliki avi) i działa bez zarzutu.

      Odp: Dziękuję za informacje, twój komentarz przeniosłem z "komentarzy strony" do niniejszego artykułu, gdzie wydaje się bardziej na temat. Pozdrawiam!
    • TomRiddle
    • czw, 16 wrzesień 2010, 13:51
    • Sorry, ale mi nie działa.

      Prubuje z Bitmapą i takie coś:
      "Project Project2.exe raised exception class EResNotFound with message 'Resourse TForm1 not found". Process stoped. Use Step or Run to contiunue.

      Odpisz proszę na maila:
      tom_riddle_lol_vp.pl@vp.pl
    • TomRiddle
    • czw, 29 lipiec 2010, 9:27
    • A video.
      Bardzo mi zależy.




      Odp: Spróbuj wsadzić wideo jako RCDATA.
    • Andrew
    • nie, 27 czerwiec 2010, 16:18
    • Problem rozwiązany, uff dużo szukania było.
    • scoop
    • nie, 27 czerwiec 2010, 13:20
    • Przyłączam się do pytania kolegi niżej.
    • Adrew
    • sob, 26 czerwiec 2010, 22:49
    • Bardzo dobry poradnik. Mam pytanie, jak odczytać tekst z zasobów innej aplikacji np. z zakładki "Version"?
      Byłbym wdzięczny za pomoc.
    • skuzi
    • pią, 14 maj 2010, 14:19
    • Czy można dać inne pliki do zasobów ? Chodzi mi o pliki tekstowe.




      Odp: Zaktualizowałem artykuł. Znajdziesz w nim teraz odpowiedź na swoje pytanie.
    • Pirotechnik
    • pią, 14 maj 2010, 13:31
    • Chciałbym użyć w swoim programie czcionkę której na pewno przeciętny użytkownik programu nie będzie posiadał więc w jaki sposób mogę załadować do programu czcionkę z zasobów i jak jej następnie użyć?




      Odp: Zaktualizowałem artykuł. Znajdziesz w nim teraz odpowiedź na swoje pytanie.
    • TomRiddle
    • pon, 29 marzec 2010, 15:06
    • A jak otowrzyć tą konsole MS-DOS?




      Odp: Chodzi o tzw. "wiersz poleceń systemu Windows". Znajdziesz go w menu "start" w katalogu "Akcesoria".
    • skuzi
    • pon, 7 grudzień 2009, 20:39
    • Przy odtwarzaniu plików wav cały program się jakby wiesza i tylko odtwarza jest możliwe zatrzymanie wykonywania tych plików wav ?




      Odp: Owszem. Użyj flagi SND_ASYNC w trzecim parametrze. Po tej operacji dźwięk będzie odtwarzany asynchronicznie (bez blokowania pętli komunikatów Twojej aplikacji, przez co nie będzie efektu "zawieszania się " programu).

      Natomiast z zatrzymaniem już odtwarzanego dźwięku sprawa jest nieco dziwna. Według dokumentacji API funkcji PlaySound(), aby zatrzymać dźwięk należy podać jako pierwszy jej parametr wartość pustą - słówko nil. Powinno to moim zdaniem wyglądać tak:

      implementation

      {$R *.dfm}
      {$R Bomba.RES}

      procedure TForm1.Button1Click(Sender: TObject);
      begin
      // Rozpoczęcie odtwarzania
      PlaySound('Bomba',hInstance,SND_ASYNC+SND_RESOURCE);
      end;

      procedure TForm1.Button2Click(Sender: TObject);
      begin
      // Zatrzymanie odtwarzania
      PlaySound(nil,hInstance,SND_NODEFAULT);
      end;



      Zaktualizowałem artykuł - rzeczywiście brakowało tej informacji.

      Pozdrawiam czytelnika!
    • Kanashimi
    • sob, 29 sierpień 2009, 15:53
    • Tak :) Wszystko działa należycie :D
      Dzięki wielkie za fatygę i email :]
    • Kanashimi
    • nie, 23 sierpień 2009, 0:27
    • A czy istnieje możliwość załadowanie JPEG zamiast BMP (w ten sam sposób)?
      Stworzyłem plik zasobu, wpisałem wszystko poprawnie ale problem pojawia się przy wyciągnięciu programu z zasobu. Zmieniłem Bitmap na JPEGIMAGE itd. Pokazuje że LoadFromResourceName jest niezadeklarowany (zadeklarowałem moduł JPEG w uses)
      Ogólnie ciężko w sieci z informacjami o JPEG jako wyciąganiu z zasobów :D albo nie wiem jak szukać.
      Chodzi o to, że zrobiłem jeden program-zabawkę dla dziewczyny, i 85% jego rozmiaru to ta bitmapa w nim, (2,5mb)... przy JPEG to byłoby ok 60kb :D



      Odp: Witam! Tak, z plikami JPEG jest już nieco trudniej, ponieważ Delphi nie dostarcza przyjaznych w użyciu funkcji których możemy użyć. W takich wypadkach należy posłużyć się ogólną metodą - strumieniami - a dokładniej jednym typem strumienia - TResourceStream. O strumieniach możecie przeczytać dokładniej na LHP w serii artykułów o nich. Tymczasem TResourceStream to obiekt którego zadaniem jest ładowanie i udostępnianie nam do użytku zasobów o podanej nazwie. Problem jest w tym, że w klasie TBitmap mamy funkcję LoadFromResourceStream() natomiast w klasie TJPEGImage już takiej funkcji nie mamy. Mamy tam natomiast LoadFromStream() którą wykorzystamy. Najpierw załadujemy zasób do strumienia typu TResourceStream, a następnie załadujemy go do zmiennej TJPEGImage za pomocą funkcji LoadFromStream(). Następnie wyświetlimy zmienną TJPEGImage na komponencie TImage za pomocą funkcji Assign. Zaczynamy! Należy stworzyć zasób z plikiem JPEG (polecam do tego celu "Kreator Zasobów" dostępny do ściągnięcia w tym artykule) - plik z danymi podawany do komilatora brcc32.exe powinien wyglądać więc następująco (jeśli korzystasz z "Kreatora Zasobów" to nie interesuje Cię to ;):

      obrazek JPEGFILE "C:_______4.jpg"


      Tworzymy zasób w sposób opisany w artykule - wychodzi nam plik np. obrazek.RES.
      W Delphi, na formularzu należy umieścić komponent TImage. W kodzie formularza, pod sekcją implementation dodajemy linijkę:

      {$R obrazek.RES}

      Która wkompiluje nam nasz zasób do pliku EXE tworzonej aplikacji.
      Klikamy dwa razy na formularz - pojawia się nam edytor kodu z nowowygenerowaną procedurą FormCreate() wywoływaną przy tworzeniu formularza. W tej procedurze będziemy wczytywać i wyświetlać nasz zasób. Uzupełniamy tę pocedurę następująco:

      procedure TForm1.FormCreate(Sender: TObject);
      var
      Obrazek : TJPEGImage;
      RS : TResourceStream;
      begin
      RS := TResourceStream.Create(hInstance,'obrazek','JPEGFILE');

      Obrazek := TJPEGImage.Create;
      Obrazek.LoadFromStream(RS);
      Image1.Picture.Assign(Obrazek);
      Obrazek.Free;

      RS.Free;
      end;

      To wszystko, po uruchomieniu powinnismy widziec na formularzu nasz obrazek. Jeśli nazwa Waszego zasobu nie brzmi "obrazek" pamiętajcie by zmienić ją również w odpowiednich miejscach w kodzie. Pozdrawiam!
    • whosho
    • nie, 26 kwiecień 2009, 11:45
    • Bardzo pomocny tekst. Dzięki za trud :)
    • zergqq
    • sob, 17 styczeń 2009, 22:49
    • Dobry artykuł, bardzo konkretny.
      Chociaż do tego pliku wav, zamiast
      "PlaySound('NazwaZasobu', hInstance, SND_ASYNC + SND_RESOURCE);"
      użyłem:
      "PlaySound('nazwa zasobu',hInstance,SND_ALIAS or SND_ASYNC);"
      bo twój kod nie odtwarzał mi tego pliczku.
      Może to błąd u Ciebie, sprawdź to :), pozdrawiam




      Odp:Witam! Sprawdziłem ;) (na Delphi 6 oraz Delphi 2009), postępowałem dokładnie według artykułu i podtrzymuje to co napisałem. Podczas odtwarzania pliku typu WAVE z zasobów należy używać flagi SND_RESOURCE. Flaga SND_ALIAS (jak można przeczytać) służy do odgrywania dźwięku systemowego o etykiecie podanej jako pierwszy parametr.

      Nie mam pojęcia dlaczego u Ciebie flaga SND_ALIAS sprawia, że plik odtwarzany jest z zasobów. W każdym razie, gdyby któremuś z Was nie działało odtwarzanie z zasobów z użyciem flagi SND_RESOURCE, kolega napisał co zrobić, wystarczy zastąpić ją flagą SND_ALIAS i powinno działać (choć według mnie jest to co najmniej dziwne i nipożądane zachowanie z którym się osobiście nie spotkałem - co nie znaczy, że tak się nie dzieje).
    • Dzyszla
    • czw, 25 wrzesień 2008, 11:52
    • Co chwilę wracam do tego artykułu :)
    • anonimg3
    • nie, 14 wrzesień 2008, 0:53
    • Zarąbisty artykuł!!! ;))))
      Mi też wyskoczyło "Fatal error. Could not spawn program:Ilink32.exe" ale robiłem wszystko dalej tak jak tu pisze i wszystko chodzi ;D
    • weber
    • nie, 20 kwiecień 2008, 20:16
    • fajne.
      ale mi przy kompilowaniu do RES'a w kosoli wyskakuje taki błąd:
      Fatal error. Could not spawn program:Ilink32.exe co jest?
Dexter