PDA

Visualizza la versione completa : [C++] Caricare DLL (LAME Encoder)


gianvituzzi
02-01-2010, 00:02
Salve,

avrei bisogno di usare la libreria LAME per creare un programmino in C++ che converta un file WAVE in MP3. Ho cercato in rete ed ho trovato sia i codici sorgenti di Lame Encoder (che però dovrei ricompilare) sia la DLL lame_enc.dll a questo indirizzo: http://lame.buanzo.com.ar/

Insieme a "lame_enc.dll" vi è anche un file: "BladeMP3EncDLL.def"

Ora viene la scelta di come caricare la libreria. Essa svolge un ruolo importante nel programma ed il suo utilizzo inizia con l'inizio del programma.

Ho letto che il metodo principale (ma più complicato) per caricare una libreria è usando il collegamento esplicito tramite le funzioni LoadLibrary() e GetProcAddress(); al termine del programma si usa poi la funzione FreeLibrary().

Devo considerare però che per motivi di brevetti non potrei distribuire al DDL di Lame insieme al programma ma l'utente dovrebbe scaricarla e inserirla nella dir che contiene il file eseguibile della mi application.

In rete ho trovato un file di header della "lame_enc.dll" di qui posto l'indirizzo: http://theartofweb.net/cpp/BladeMP3EncDLL_H.txt

credo che questo file header serva per fare un caricamento implicito della DLL nel programma principale, quindi tramite:



#include <BladeMP3EncDLL.h> // Giusto ??


Quindi non farebbe al caso mio. però verso l'ultimo nel file header ci sono quelle che credo siano le funzioni che posso caricare e chiamare dal main() del mio programma, ad esempio:



__declspec(dllexport) VOID beVersion(PBE_VERSION pbeVersion);


sono quelle o sbaglio? dato che non ho trovato molte info sulla libreria Lame l'unica cosa che posso fare è studiarmi i vari file header...

grazie

shodan
02-01-2010, 00:30
Originariamente inviato da gianvituzzi
credo che questo file header serva per fare un caricamento implicito della DLL nel programma principale, quindi tramite:


Il caricamento implicito avviene se fai il link del tuo programma con il file .lib della lameENC. Quello di cui parli è solo l'header file con le dichiarazioni delle strutture e delle funzioni esportate.

Se devi fare il caricamento dinamico della libreria , quello che a te interessa ( delle funzioni ) è compreso tra:

#ifndef _BLADEDLL
...
#else

gianvituzzi
02-01-2010, 00:50
ok, quindi quella libreria header diciamo che server solo a me per studiare le funzioni a disposizione...soltanto che nella parte che dici tu mi è difficile capire come funziona questa implementazione ovvero, nello specifico mi interesserebbe per iniziare usare una funzione chemi ritorna la versione trovo tra #ifndef _BLADEDLL ... #else questo:



...
typedef VOID (*BEVERSION) (PBE_VERSION);
...
#define TEXT_BEVERSION "beVersion"


il che mi è molto difficile come lettura! al contrario dopo #else avevo:



__declspec(dllexport) VOID beVersion(PBE_VERSION pbeVersion);


che già è di più facile comprensione...

shodan
02-01-2010, 01:22
Ora viene la scelta di come caricare la libreria

Partiamo da qui.

Se ricompili la libreria, crei il .lib e lo colleghi (linki ), quando il tuo programma andrà in esecuzione, la lame_enc.dll dovrà già essere nella cartella dell'eseguibile ( o comunque nel path di ricerca di windows) altrimenti la prima cosa che succede è un bel messaggio di errore con il programma che non si avvia.

Se la lame_enc.dll non puoi distribuirla insieme al programma, hai due scelte:
1) dire chiaro e tondo all'utente di scaricarsela per conto suo e metterla nella cartella dell'eseguibile [b]prima di avviare il programma;

2) far partire il programma e controllare che la lame_enc sia nella cartella dell'eseguibile, o nel path di ricerca di windows o in una cartella di tua scelta.
Quest'ultima opzione è quella scelta da Audacity.



__declspec(dllexport) VOID beVersion(PBE_VERSION pbeVersion);

Questo prototipo lo userai se ricompili la libreria, crei il .lib e lo colleghi direttamente al tuo programma.



typedef VOID (*BEVERSION) (PBE_VERSION);

Questo puntatore a funzione (non prototipo) lo userai se decidi di caricare dinamicamente la lame_enc.dll tramite la LoadLibrary.
Dopo che ne avrai ricavato l'indirizzo tramite la GetProcAddress(), sarà come usare una funzione qualsiasi.


HINSTANCE hdll = LoadLibrary("lame_enc.dll");
BEVERSION beVersion = (BEVERSION) GetProcAddress(hdll,"beVersion");
if (beVersion != NULL)
beVersion(quel che è);

ecc

In questo caso, i prototipi come questo:


__declspec(dllexport) VOID beVersion(PBE_VERSION pbeVersion);


servono come riferimento per sapere cosa passare, ma non si possono usare se si carica la libreria con LoadLibrary.

gianvituzzi
02-01-2010, 01:28
grazie mille per la risposta! stavo per postare questo ma forse adesso non ha più senso:



VOID beVersion(PBE_VERSION pbeVersion); intuisco venga passato un puntatore ad una struttura di tipo PBE_VERSION che verrà riempita con le informazioni sulla versione.

allora per adesso ho fatto:



#include <windows.h>
#include <stdio.h>
#include "BladeMP3EncDLL.h" // Devo includerla per poter usare PBE_VERSION

const LPSTR DLL_NAME = TEXT("lame_enc.dll");

void main()
{
PBE_VERSION pb;
VOID (*pFn)(PBE_VERSION);
HINSTANCE hIns;
hIns = LoadLibrary(DLL_NAME);
if(hIns)
{
printf("lame_enc.dll loaded!\n");
pFn = GetProcAddress(hIns,"BeVersion");
pFn(pb);
}
}


Ma questo è l'errore che ottengo:

error C2440: '=' : cannot convert from 'FARPROC' to 'void (__cdecl *)(PBE_VERSION)'

Credevo di avre fatto bene il cast :-(


e ti chiedo...anche se uso LoadLibrary posso cmq includere il file di header così posso usare delle strutture della libreria?

grazie

gianvituzzi
02-01-2010, 01:36
ora stavo provando questo:



...
#include "BladeMP3EncDLL.h"
void main()
{
PBE_VERSION pb;

HINSTANCE hdll = LoadLibrary("lame_enc.dll");
BEVERSION beVersion = (BEVERSION) GetProcAddress(hdll,"beVersion");
beVersion(pb);
}


ma mi esce questa popup:

The variable 'pb' is being used without being initializated e come dovrei inizializarla?

grazie

oregon
02-01-2010, 07:09
PBE_VERSION è un puntatore alla struttura BE_VERSION ... quindi



BE_VERSION bev;
...
beVersion(&bev);

gianvituzzi
02-01-2010, 12:42
ok, ho usato anche le costanti messe a disposizione dalla libreria: (TEXT_BEVERSION)



void main()
{

BE_VERSION bev;

HINSTANCE hdll = LoadLibrary(DLL_NAME);
BEVERSION beVersion = (BEVERSION) GetProcAddress(hdll,TEXT_BEVERSION);
beVersion(&bev);
FreeLibrary(hdll);
system("pause");
}


grazie!

gianvituzzi
02-01-2010, 14:35
ora però c'è un problema con questo codice:



void main()
{
// Define BE_CONFIG Structure:
BE_CONFIG bec;

bec.dwConfig = BE_CONFIG_MP3;
bec.format.mp3.dwSampleRate = 44100;
bec.format.mp3.byMode = BE_MP3_MODE_STEREO;
bec.format.mp3.wBitrate = 128;
bec.format.mp3.bCopyright = false;
bec.format.mp3.bCRC = false;
bec.format.mp3.bOriginal = false;
bec.format.mp3.bPrivate = false;

HINSTANCE hdll = LoadLibrary(DLL_NAME);
BEINITSTREAM beInitStream = (BEINITSTREAM) GetProcAddress(hdll,TEXT_BEINITSTREAM);

DWORD dwSamples = 1;
DWORD dwBufferSize = 4096;
HBE_STREAM hbe;

BE_ERR res = beInitStream(&bec, &dwSamples, &dwBufferSize, &hbe);

system("pause");
}



mi da errore: "Access violation" alla chiamata beInitStream() // inoltre prima quando facevo:



BEVERSION beVersion = (BEVERSION) GetProcAddress(hdll,TEXT_BEVERSION);


e chiamavo beVersion() mi appariva un "highlight" giallo con i parametri da passare, in questo caso no! ma non credo che sia un problema di casting della funzione:



typedef BE_ERR (*BEINITSTREAM) (PBE_CONFIG, PDWORD, PDWORD, PHBE_STREAM);
...
#define TEXT_BEINITSTREAM "beInitStream"


inoltre credo di aver passato bene i parametri alla funzione beVersion() come spiegato quì: http://www.fi.muni.cz/~qruzicka/Smid/man.htm

:bhò:

shodan
02-01-2010, 15:15
Con il tuo codice io non ho problemi.
Sicuro che la DLL venga caricata? E perché hai tolto il controllo su hdll?

Loading