2012-09-16 33 views
9
ref參數

這裏是我的C#服務器方法:是否有可能Marshal在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);   
} 

我的C++客戶端設置和調用此方法。這工作正常,但狀態和輸出變量似乎不鏈接。就好像它們是通過價值傳遞而不是通過引用傳遞的。

這裏是我的客戶端代碼:

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

有人可以提供有關設置SAFEARRAY參數,使「裁判」 PARAMS被複制回了援助?

+0

您是否有理由選擇這個非常複雜的解決方案?難道你不能用/ clr開關編譯你的C++應用程序,並讓編譯器擔心它嗎?我一直在做很多互操作的東西,但我從來不必手動編組參數。 – PMF

回答

0

我可能不知道完整的答案,但我在你的代碼發現兩件事情:

字符串沒有被引用正確傳遞

字符串在C#中是不可變的參考對象。這意味着對它們的引用被傳遞(通過值),並且一旦創建了字符串,就不能修改它。如果修改字符串值,則實際上會創建一個新字符串並更改對其的本地引用。

有一個關於它here

所以,你需要你的C#函數的定義修改爲這樣的一個很好的解釋:

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

您應該改用出來

裁判

您似乎初始化參數值之前 C#函數調用本身不進入函數。

所以,你應該使用ref而不是out關鍵字;

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