2012-09-16 12 views
9

Hier ist mein C# Server-Methode Marschall:Ist es möglich, ref Parameter 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);   
} 

Meine C++ Client einrichtet und dem Aufruf dieser Methode. Das funktioniert gut, aber die Status- und Ausgabevariablen scheinen nicht verkettet zu sein. Es ist, als würden sie nach Wert anstatt nach Referenz weitergegeben.

Hier ist mein Client-Code:

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); 

jemand so die SAFEARRAY Argumente Unterstützung bei der Einrichtung zur Verfügung stellen kann, dass die params ‚ref‘ kopiert werden aus zurück?

+0

Gibt es einen Grund, warum Sie sich für diese sehr komplizierte Lösung entscheiden? Können Sie nicht einfach Ihre C++ - App mit dem Schalter/clr kompilieren und sich den Compiler Sorgen machen? Ich habe eine Menge Interop-Sachen gemacht, aber ich musste nie Argumente manuell ordnen. – PMF

Antwort

0

Ich könnte nicht die vollständige Antwort weiß, aber ich zwei Dinge in Ihrem Code erkennen:

String wird durch das Bezugs

Strings in C# sind unveränderlich Referenzobjekte nicht korrekt übergeben. Dies bedeutet, dass Verweise auf sie (nach Wert) weitergegeben werden, und sobald eine Zeichenfolge erstellt wird, können Sie sie nicht ändern. Wenn Sie den Zeichenfolgenwert ändern, erstellen Sie eine neue Zeichenfolge und ändern den lokalen Verweis darauf.

Es gibt eine große Erklärung darüber here

So, müssen Sie die Definition Ihrer C# Funktion, so etwas ändern:

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

sollten Sie ref out statt verwenden

Sie scheinen Argument Werte vor C# Funktionsaufruf nicht in Funktion selbst zu initialisieren.

Also, Sie sollten ref statt out Schlüsselwort verwenden;

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