【问题标题】:Is it possible to marshal ref parameters in SAFEARRAY是否可以在 SAFEARRAY 中编组 ref 参数
【发布时间】:2012-09-08 18:08:26
【问题描述】:

这是我的 C# 服务器方法:

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 参数以便将“ref”参数复制回来吗?

【问题讨论】:

  • 你有理由选择这个非常复杂的解决方案吗?难道你不能只用 /clr 开关编译你的 C++ 应用程序并让编译器担心吗?我一直在做很多互操作的东西,但我从来不需要手动编组参数。

标签: .net parameters marshalling safearray


【解决方案1】:

我可能不知道完整的答案,但我在您的代码中发现了两点:

字符串没有通过引用正确传递

C# 中的字符串是不可变的引用对象。这意味着对它们的引用是(按值)传递的,一旦创建了字符串,就不能修改它。如果修改字符串值,实际上是创建了一个新字符串并更改了对它的本地引用。

有一个很好的解释here

因此,您需要将 C# 函数的定义更改为:

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

你应该使用 ref 而不是 out

您似乎 C# 函数调用之前初始化参数值而不是函数本身。

所以,你应该使用 ref 而不是 out 关键字;

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

【讨论】:

    猜你喜欢
    • 2014-01-17
    • 2021-10-11
    • 2010-10-08
    • 2011-04-16
    • 1970-01-01
    • 1970-01-01
    • 2018-01-21
    • 2021-01-14
    相关资源
    最近更新 更多