Newsgroup: it.comp.lang.delphi
Titolo: Come richiamare un file risorsa di tipo wave da una DLL ?

Ciao a tutti,
ho bisogno di aiuto su come richiamare
dei files audio di tipo wave incapsulati
come risorsa dentro una libreria DLL
compilata precedentemente con Delphi,
usando MMsystem e le funzioni Win32
Grazie in anticipo.
Sde
--- posted by geoForum on 
http://www.delphiedintorni.it

 usando MMsystem e le funzioni Win32
credo (?) allo stesso modo di come se fossero incluse in un EXE, e cioč:
type
  TForm1 = class(TForm)
//////
  private
    P: Pointer;
    hFindRes, hLoadRes: TResourceHandle;
///
  end;
var
  Form1: TForm1;
implementation
{$R *.dfm}
{$R sounds.res}
uses
  MMSystem;
procedure TForm1.btnSoundClick(Sender: TObject);
begin
  sndPlaySound(P, SND_ASYNC or SND_MEMORY);
end;
procedure TForm1.FormCreate(Sender: TObject);
begin
  hFindRes := FindResource(HInstance, 'SOUND_1', 'WAVE');    
//i nomi sono cmq case insensitive
  hLoadRes := LoadResource(HInstance, hFindRes);
  P := LockResource(hLoadRes);
end;
procedure TForm1.FormDestroy(Sender: TObject);
begin
  if (hLoadRes <> 0) then
  begin
    UnlockResource(hLoadRes);
    FreeResource(hLoadRes);
  end;
end;
-- 
Mauro Falzari 
 
 "Se guardi nell'abisso, anche l'abisso guarda in te." 
   (Friedrich Nietzsche)

Mauro Falzari 
Salve Mauro, purtroppo no, č questo il problema. 
Cosě funziona solo se le risorse sono compilate nell'eseguibile... 
da quello che sň, bisogna richiamare la funzione
LoadLibrary('Nomemiadll.DLL') e alla fine
liberare la risorsa con FreeLibrary(LoadLibrary('Nomemiadll.DLL')).
Il fatto č che ci sono tanti esempi su come caricare Icone, Bitmap,
Stringhe da una DLL... ma non riesco a trovare un'esempio concreto
che riguardi i file 'Wav'. Comunque grazie.


 che riguardi i file 'Wav'.
ok esempi semplicissimi tipo questo:
http://66.249.93.104/search?q=cache:lib-Hm-
LP3gJ:
delphi.about.com/library/weekly/aa010405a.htm+load+resource+library+d
elphi&hl=it
beh invece di usare LoadIcon, usa LoadResource (generico). No?
Boh ho voluto provare.
Ho creato un nuovo progetto di un EXE (Project1) e una nuova DLL 
(Project2).
Avendo un suono di nome ARG.WAV, ho creato un file di testo contenente solo 
questa riga:
  SUONO_ARG WAVE ARG.WAV
e ho salvato il file di testo col nome SOUNDS.RC.
Poi ho creato un file di testo contenente questa sola riga:
  BRCC32 SOUNDS.RC
che ho salvato col nome di COMPILA.BAT. Ho quindi cliccato sopra 
COMPILA.BAT e ho così ottenuto SOUNDS.RES. (Tutti i file si trovano per 
semplicità nella stessa cartella di Project1 e Project2).
In Project2.dpr ho scritto solo questo:
library Project2;
{$R SOUNDS.RES}
begin
end.
e ho compilato. Così ho ottenuto la DLL (Project2.dll) che contiene il 
suono come risorsa.
In Project1, ho rimosso la form predefinita, in modo da avere un DPR nudo e 
crudo e ci ho scritto dentro:
program Project1;
uses
  Windows, MMSystem;
var
  hDLL: THandle;
  hSoundInfo, hSound: TResourceHandle;
  PLocked: Pointer;
begin
  hDLL := LoadLibrary('Project2.dll');
  try
    hSoundInfo := FindResource(hDLL, 'SUONO_ARG', 'WAVE');
    hSound := LoadResource(hDLL, hSoundInfo);
    PLocked := LockResource(hSound);
    try
      sndPlaySound(PLocked, SND_MEMORY);
    //non capisco perchè non funziona:
    //  sndPlaySound(PLocked, SND_ASYNC or SND_MEMORY);
    finally
      if (hDLL <> 0) then
      begin
        UnlockResource(hSound);
        FreeResource(hSound);
      end
    end
  finally
    FreeLibrary(hDLL);
  end
end.
Questo è quello che ho buttato giù apportando lievi modifiche al codice che 
avevo già postato in precedenza. Probabilmente ci sono cose inutili, tipo 
l'UnlockResource (It is not necessary for Win32-based applications to 
unlock resources that were locked by the LockResource function.).
Ma funziona.
Naturalmente si possono includere risorse di qualunque tipo, come ho già 
fatto in diversi programmi. Si può includere di tutto in un EXE (ma anche 
in una DLL come abbiamo visto): pagine HTML, file DOC, immagini. La risorsa 
generica è RCDATA
IMG RCDATA "google 2004.gif"
IMG2 RCDATA "sfondo blu.jpg"
TXT RCDATA "note di rilascio.txt"
DOC RCDATA "Lavori in corso.doc"
in questi casi è molto semplice usare TResourceStream e TFileStream per 
estrarre, manipolare le risorse e salvarle su disco.


Grazie Mauro,
era proprio quello che cercavo...
ho quindi scritto una UNIT, che può essere
inserita in un qualsiasi progetto Delphi
per richiamare i suoni inclusi in una DLL risorsa
tramite un semplice comando del tipo Suona('nome');
ecco la UNIT:
***
unit Suoni_DLL;
interface
uses
  SysUtils, WinTypes, WinProcs,MMsystem, Dialogs;
PROCEDURE Suona (Name : String) ;
implementation
PROCEDURE Suona (Name : String) ;
    (*   Suona il "Nome" della risorsa wave. *)
VAR
    Ascii       : Array [0..255] OF Char;
    lpRes       : PChar;
    hRes        : THandle;
    hResInfo    : THandle;
    h           : THandle;
 
BEGIN
if waveOutGetNumDevs <= 0 then exit;
(* carica la libreria di risorsa DLL compilata *)
h := LoadLibrary('suonidll.DLL');
try
  if h <> 0 then
    begin
  StrPCopy(Ascii, Name);{ Conversione Stringa }
    (* ritrova in h, il nome ed il 'tipo' di risorsa *)
  hResInfo := FindResource(h, Ascii, 'WAV');
  (* Se la risorsa esiste caricala *)
    IF hResInfo <> 0 THEN BEGIN
    (* carica la risorsa da 'h' usando il nome ed il 'tipo' *)
    hRes := LoadResource(h, hResInfo);
    (* se la risorsa è valida, suonala *)
    IF hRes <> 0 THEN BEGIN
      lpRes := LockResource(hRes);
      SndPlaySound(lpRes, SND_MEMORY);
      UnlockResource(hRes);
    END;    { IF hRes }
    FreeResource(hRes);  (* scarica la risorsa *)
    end;      { IF hResInfo }
    end else
    begin     (* errore nel caso la DLL fosse errata o inesistente *)
      ShowMessage('Load Resource DLL FAILED!');
    end;  (* if h *)
 finally
    FreeLibrary(h); (* scarica la libreria DLL *)
  end;
  end;
  end.
****
Di seguito il listato con la main form che usa l'unità di cui sopra
e richiama alcuni suoni inseriti nella DLL tramite un pulsante:
****
unit Programma_prova;
interface
uses
  Windows, Messages, Classes, Controls, Forms,
  StdCtrls, MMsystem, suoni_DLL;
type
  TForm1 = class(TForm)
    Button1: TButton;
    procedure Button1Click(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;
var
  Form1: TForm1;
implementation
{$R *.DFM}
procedure TForm1.Button1Click(Sender: TObject);
begin
suona('suono_arg');
suona('eip');
end;
end.
*****
Grazie ancora.
Sde.


giusto per completezza, riporto il modo semplicissimo di caricare una 
risorsa inclusa in un EXE e salvarla su file.
Dato un file di nome DATA.RC contenente per esempio:
TEMPLATE RCDATA "template.dot"
compilato in DATA.RES nel modo visto in precedenza, posso salvarlo su file 
nel seguente modo:
{$R data.res}
var
  RS: TResourceStream;
begin
  if not FileExists(<nome_file>) then
  begin
    RS:= TResourceStream.Create(HInstance, 'TEMPLATE', RT_RCDATA);
    try
      RS.SaveToFile(<nome_file>);
    finally
      RS.Free
    end;
  end
end;
Infine ricordo che si può passare allegramente da un tipo di stream 
(TMemoryStream, TFileStream, TStringStream) all'altro con 
Destination.CopyFrom(Source, 0); //copia tutto Source in Destination
Ciao!
