问题
Here is my C# server method:
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);
}
My C++ client is setting up and calling this method. This works fine, but the status and output variables don't appear to be chaining. It's as though they're being passed by value instead of by reference.
Here's my 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);
Can someone provide assistance on setting up the SAFEARRAY arguments so that the 'ref' params are copied back out?
回答1:
I might not know the full answer, but I spot two things in your code:
String is not passed correctly by reference
Strings in C# are immutable reference objects. This means that references to them are passed around (by value), and once a string is created, you cannot modify it. If you modify string value, you actually create a new string and change local reference to it.
There is a great explanation about it here
So, you need to change the definition of your C# function to something like this:
public void Exec(out int status, out string output)
{
...
}
You should use ref instead of out
You seem to initialize argument values before C# function call not into function itself.
So, you should use ref instead of out keyword;
public void Exec(ref int status, ref string output)
{
...
}
来源:https://stackoverflow.com/questions/12443784/is-it-possible-to-marshal-ref-parameters-in-safearray