2012-03-30 8 views
5

C'è una funzione API esistenti che non consentono solo il plugin (DLL) per ricevere tre parametri ed eseguire qualche azione:Come modificare il contenuto della variabile originale che viene passato per valore?

int ProcessMe(int nCommand, unsigned int wParam, long lParam); 

Ora, dal programma principale (exe), vorrebbe passare due variabili per il plugin, e richiede il plugin per modificare il loro contenuto, e il programma principale leggerà di nuovo, per eseguire alcune attività.

La mia domanda è, dalla funzione sopra, posso eseguire questo, senza modificare i parametri di funzione?

Esempio:

int ProcessMe(int nCommand, unsigned int wParam, long lParam) 
{ 
    // modify the parameters// 
    return 0; 
} 

int main() 
{ 
    BOOL bSave = TRUE; 
    int nOption = 0; 
    ProcessMe(0, (unsigned int)(&bSave), (long)(&nOption)); 
    if(FALSE==bSave) 
    printf("bSave is modified!"); 
    return 1; 
} 
+1

No. È necessario passare per riferimento, cosa che non si può fare senza modificare l'API. Dovrai reimplementare l'interfaccia con i puntatori o imparare a vivere senza. – tbert

+0

Purtroppo non ho il permesso di cambiare l'interfaccia, dato che attualmente ci sono molte altre DLL in esecuzione con l'exe che usa l'interfaccia simile .... preoccupazione per la compatibilità con le versioni precedenti per me :( – wengseng

+1

Questo non ha senso. Ci si aspetta di usare i parametri per memorizzare i risultati Non sono per l'output È necessario dichiarare una nuova funzione –

risposta

5

Posizionare le variabili da modificare in una struct e passare il puntatore al sturuct al plug in:

struct MyStruct 
{ 
    BOOL bSave; 
    int nOption; 
}; 

int ProcessMe(int nCommand, unsigned int wParam, long lParam) 
{ 
    ((MyStruct*)lParam)->nOption = ...; 
    return 0; 
} 

usare in questo modo:

int main() 
{ 
    MyStruct struct; 
    struct.bSave = TRUE; 
    struct.nOption = 0; 
    ProcessMe(0, 0, (long)(&struct)); 
    if(FALSE==struct.bSave) 
    printf("bSave is modified!"); 
    return 1; 
} 

In senso stretto si tratta di comportamento non definito. Devi controllare, se funziona sulla tua piattaforma.

Nota: ho usato una struct qui, perché in questo modo è anche possibile passare più variabili o variabili più grandi come il doppio della funzione.

+0

Wrong, questo non modificherà i parametri originali. 'wParam' sarà sempre lo stesso. –

+2

@LuchianGrigore - ovviamente! L'intento è di modificare il contenuto della struttura. – Henrik

+0

Quale struttura? Non c'è nessuna struttura nel suo codice. La tua risposta risponde a una domanda completamente diversa. –

3

No, non c'è modo di farlo.

Passando per valore si creano copie di quelle originali. Nell'ambito del metodo, non avrai informazioni sulle variabili originali.

È necessario passare per riferimento o valore.

+0

Questo non è corretto. Anche se non puoi farlo in un modo sicuro dal tipo, puoi farlo reinterpretando il contenuto di 'lParam'. Questo in effetti accade molto nell'API Win32. Henrik ha già mostrato una soluzione che funziona. – AlefSin

+0

@AlefSin dereferencing Anche i puntatori NULL si verificano nell'API Win32. Ecco perché abbiamo uno standard per guidarci, non la documentazione MSDN. –

+3

So che non è sicuro per il tipo, e l'ho detto. Tutto ciò deriva dal fatto che alcune API più vecchie sono state progettate in un'epoca in cui i programmatori C non si preoccupavano molto della sicurezza del tipo. Quando non puoi modificare il codice dell'API, dovrai comunque ricorrere a una soluzione brutta, pericolosa, non portatile e potenzialmente pericolosa. – AlefSin

1

Prova questo ... è POSSIBILE !!!

includono

int ProcessMe (int n comando, unsigned int wParam, lungo lParam)

{

int *nCommand_ptr = (int*)nCommand; 
unsigned int *wParam_ptr = (unsigned int*)wParam; 
long *lParam_ptr = (long*)lParam; 
*nCommand_ptr = 10; 
*wParam_ptr = 10; 
*lParam_ptr = 10; 
return 0; 

}

int main() {

int nCommand = 5; 
unsigned int wParam = 5; 
long lParam = 5; 
printf("\n %d %u %lu",nCommand,wParam,lParam); 
ProcessMe((int)&nCommand,(unsigned int)&wParam,(long)&lParam); 
printf("\n %d %u %lu",nCommand,wParam,lParam); 
return 0; 

}

uscita:

$> g ++ passbyref.cc

$> ./ a.out

10 10 10 $>

1

Compilazione per 32 piattaforma bit in cui potresti giocare al puntatore del parametro:

#include <stdio.h> 
typedef int BOOL; 
#define FALSE 0 
#define TRUE 1 

int ProcessMe(int nCommand, unsigned int wParam, long lParam) 
{ 
    // cast to match what you passed in 
    *((BOOL*)wParam) = FALSE; 
    return 0; 
} 

int cast_arguments_main(int, char **) 
{ 
    BOOL bSave = TRUE; 
    int nOption = 0; 
    ProcessMe(0, (unsigned int)(&bSave), (long)(&nOption)); 
    if(FALSE==bSave) 
    printf("bSave is modified!"); 
    return 1; 
} 

Su una piattaforma a 64 bit il compilatore si lamenta l'impossibilità di rappresentare il puntatore:

cast_arguments.cpp:17:37: error: cast from ‘BOOL*’ to ‘unsigned int’ loses precision 

Ho dovuto cambiare il unsigned int wParam dichiarazione di parametro su unsigned long wParam e modifica simile al punto di chiamata: ProcessMe(0, (unsigned long)(&bSave), (long)(&nOption)); ma in questo caso si potrebbe semplicemente dichiarare il tipo giusto per il parametro, per essere BOOL *. Quindi la fattibilità dipende dall'architettura della macchina target ...

+0

Su Windows a 64 bit (che è il punto in cui compare il nome 'lParam'), il tipo di lParam non è' long'. In realtà probabilmente dovrebbe usare solo 'intptr_t' per cominciare. –

Problemi correlati