2012-09-16 11 views
9

Ecco il mio metodo di C# server:E 'possibile effettuare il marshalling parametri ref in SAFEARRAY

public void Exec(out int status, string output) 
{ 
    status = 3; 
    Console.WriteLine("Exec({0}, ...)", status); 

    output = string.Format("Hello from .NET {0}", DateTime.Now); 
    Console.WriteLine("Exec(..., {0})", output);   
} 

mio cliente C++ è la creazione e la chiamata di questo metodo. Funziona bene, ma le variabili di stato e di output non sembrano essere concatenate. È come se venissero passati per valore invece che per riferimento.

Ecco il mio codice cliente:

InitCLR(); 

LONG index = 0; 

LONG i1 = 12; // just some number for testing 
BSTR s1 = SysAllocString(L"Hello world"); 

SAFEARRAY* args = NULL; 
CHECK_HRESULT(SafeArrayAllocDescriptor(1, &args)); 

args->cbElements = sizeof(VARIANT); 
args->rgsabound[0].lLbound = 0; 
args->rgsabound[0].cElements = 2; 

CHECK_HRESULT(SafeArrayAllocData(args)); 

// byref not working for in/out param 
VARIANT arg1; 
VariantInit(&arg1); 
V_I4REF(&arg1) = &i1; 
V_VT(&arg1) = VT_I4 | VT_BYREF; 

// byref not working 
VARIANT arg2; 
VariantInit(&arg2); 
V_BSTR(&arg2) = SysAllocString(L"Hello world"); 
V_VT(&arg2) = VT_BSTR; 

index = 0; 
CHECK_HRESULT(SafeArrayPutElement(args, &index, &arg1)); 

index = 1; 
CHECK_HRESULT(SafeArrayPutElement(args, &index, &arg2)); 

int bindingFlags = mscorlib::BindingFlags_InvokeMethod | 
    mscorlib::BindingFlags_Instance | 
    mscorlib::BindingFlags_Public; 

VARIANT retval; 
VariantInit(&retval); 

bstr_t methodName("Exec"); 
HRESULT hRes = Type->InvokeMember_3(
    methodName, 
    static_cast<mscorlib::BindingFlags>(bindingFlags), 
    NULL, // binder * 
    Instance, 
    args, 
    &retval); 

_tprintf(TEXT("Exec() == 0x%x\n"), hRes); 

_tprintf(TEXT("i1=%d\n"), i1); 

Qualcuno può fornire assistenza su come impostare gli argomenti SAFEARRAY in modo che i params 'ref' vengono copiati di nuovo fuori?

+0

C'è una ragione per questa soluzione molto complicata? Non puoi semplicemente compilare la tua app C++ con l'opzione/clr e lasciare che il compilatore si preoccupi di ciò? Ho fatto un sacco di roba di interoperabilità, ma non ho mai dovuto effettuare il marshalling degli argomenti manualmente. – PMF

risposta

0

potrei non conoscere la risposta completa, ma ho posto due cose nel codice:

String non viene passata correttamente con riferimento

stringhe in C# sono oggetti di riferimento immutabili. Ciò significa che i riferimenti ad essi vengono passati (in base al valore) e una volta creata una stringa, non è possibile modificarla. Se si modifica il valore di stringa, si crea effettivamente una nuova stringa e si modifica il riferimento locale a esso.

C'è una grande spiegazione su di esso here

Quindi, è necessario cambiare la definizione della vostra funzione C# per qualcosa di simile:

public void Exec(out int status, out string output) 
{ 
    ... 
} 

si dovrebbe usare ref anziché fuori

Sembra che inizializzi i valori degli argomenti prima della chiamata della funzione C# non nella funzione stessa.

Quindi, si dovrebbe usare la parola chiave ref anziché out;

public void Exec(ref int status, ref string output) 
{ 
    ... 
} 
Problemi correlati