c - Hvordan overføres argumenter til DLL-initialisering (f.eks. ved indlæsning via LoadLibrary)?

Indlæg af Hanne Mølgaard Plasc

Problem



Hvordan kunne man passere argumenter til initialiseringsfunktionen af ​​en DLL indlæst via LoadLibrary? Er det muligt overhovedet? Uden at tage stilling til en eller anden form for eksporteret funktion eller delt hukommelse, så er det.

Bedste reference


Der er ingen direkte vej.


Det nemmeste kan være gennem miljøvariabler. De kan indstilles let, før du ringer LoadLibray med setenv, og derefter kan DLL'en (i samme proces) hente dem med getenv.

Andre referencer 1


Et alternativt middel



    Selvom jeg ikke er helt sikker på, om dette falder under 'delt hukommelse' (da du også kan bruge denne metode til at sende data til DLL'er i forskellige processer) ... Du kan tildele noget hukommelse til en bestemt adresse ved hjælp af VirtualAllocEx, sendes i en struktur, der indeholder alle de data, DLL'en skal bruge ved hjælp af WriteProcessMemory, og lås den derefter med VirtualLock, inden du læser DLL'en.


Derefter vil jeg bruge VirtualUnlock i DLLs indgangspunktfunktion, tag disse data ved hjælp af ReadProcessMemory og derefter VirtualFree for at rydde op.



Selv om det er lidt uhøfligt, er dette især nyttigt, hvis du har mere end blot en enkel streng at videregive.

Bemærk, at du skal have læse/skriveadgang i målprocessen, for at dette kan fungere.
 


Eksempel (pseudo-kode)



// YourApp.cpp

struct DataToSend {
    int myInt;
    char myStr[320];
};
DataToSend m\_data = { 1337, "This is a test string..." };

// ...
PVOID remoteData = VirtualAllocEx( hTargetProcess, NULL, sizeof(m\_data), MEM\_RESERVE|MEM\_COMMIT, PAGE\_READWRITE );
WriteProcessMemory( hTargetProcess, remoteData, &m\_data, sizeof(m\_data), NULL );
VirtualLock( remoteData, sizeof(m\_data) );
// Save the address (DWORD) of remoteData to the registry, to a local file, or using setenv as suggested in other answers here


&Nbsp;


// YourDll.cpp

BOOL APIENTRY DllMain( HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved )
{
    DataToSend m\_data = {0};
    PVOID localData = /* address used in YourApp */ NULL;
    //...
    VirtualUnlock( localData, sizeof(m\_data) );
    ReadProcessMemory( hProcess, localData, &m\_data, sizeof(m\_data), NULL );
    VirtualFree( localData, 0, MEM\_RELEASE );
}

Andre referencer 2


En anden mulig løsning: Opret en anden DLL, der kun udsætter en 'setparam' og en 'getparam' -metode, end at bruge den i både applikationen (setparam) og dll'ens DllMain (getparam). I deres grundlæggende form er metoderne implementeret med statiske variabler, men du kan bruge mere sofistikerede teknologier. Denne løsning, selv om det er sværere, har nogle fordele:



  • det bruger ikke nogen 'global' konvention (undtagen navnet på den fælles DLL!)

  • Det bruger ikke muligvis begrænsede ressourcer (fx miljøvariabler)

  • Det er generelt: Du kan bruge den samme DLL, hvor du vil.

  • Det kan gøres så kraftigt og kompliceret som du har brug for: f.eks. Du kan gøre det trådbeskyttet, hvis det kræves. Det er kun et spørgsmål om gennemførelse.



Her er et minimalt eksempel:


// The "helper" DLL //
static int param;
void setparam(int v) { param = v; }
int getparam(void) { return param; }

// The application //
setparam(12345);
LoadLibrary("TheDLL.dll");

// The DLL to which you want to pass parameters //
BOOL WINAPI DllMain(HINSTANCE h,DWORD re,LPVOID res)
{
int param;
  switch (re)
  {
  case DLL\_PROCESS\_ATTACH:
     param = getparam();
//...

Andre referencer 3


Det er 'dårligt' og 'grimt', men du kan skubbe argumenter på stakken med in-line ASM, før du foretager dit opkald og pop dem tilbage på samme måde. En meget hack-ish løsning, men det kan fungere. Jeg bemærker det kun fordi det er muligt, ikke fordi det er en god måde at gøre ting på.