【问题标题】:Sending an Array of strings from c# to c++ via COM通过 COM 将字符串数组从 c# 发送到 c++
【发布时间】:2013-03-19 11:54:24
【问题描述】:

我尝试通过 com 互操作将数组从 c# 发送到 c++。

这里是c#代码

public void SendArraytoCPlusPlus()
{
    GGXForVBA.GeoAtlas GA = new GGXForVBA.GeoAtlas();
    string[] arr = new string[3];
    arr[0] = "One";
    arr[1] = "Two";
    arr[2] = "Five";
    GA.GetArrayVar(arr);
}

这里是c++代码

void GeoAtlas::GetArrayVar(VARIANT& arr)
{ 
    AFX_MANAGE_STATE(AfxGetStaticModuleState());
    SAFEARRAY* pSafeArray = arr.parray;
    long lStartBound = 0;
    long lEndBound = 0;
    SafeArrayGetLBound(pSafeArray,1,&lStartBound);
    SafeArrayGetUBound(pSafeArray,1,&lEndBound);
    LPCSTR * arrayAccess = NULL;

    SafeArrayAccessData( pSafeArray , (void**)&arrayAccess);
    for(int iIndex = lStartBound; iIndex <= lEndBound; iIndex ++)
    {   
        LPCTSTR myString = (LPCTSTR)arrayAccess[iIndex];
        AfxMessageBox(myString);        
    }  
}

这是idl

[id(23)] void GetArrayVar(VARIANT arr);

问题是,消息框只显示字符串的第一个字母,即''O'。 'T','F'。我想阅读整个字符串。有什么建议吗?

【问题讨论】:

  • 您的应用是使用 Unicode 还是多字节字符集构建的?
  • c++ 是用 MBCS 构建的

标签: c# c++ arrays string com


【解决方案1】:

这是基于这样一个事实,即您发送的是 Unicode/UTF8 字符串,但消息框需要一个 ANSI C 字符串。在发送之前尝试将字符串转换为 ASCII。看这里的Encoding类http://msdn.microsoft.com/en-us/library/system.text.encoding.aspx

您可能想尝试将它们作为字节数组发送。

var bytes = Encoding.ASCII.GetBytes("one");

【讨论】:

    【解决方案2】:

    您应该传递 SAFEARRAY 而不是 VARIANT:

    [id(23)] void GetArrayVar([in] SAFEARRAY(BSTR) arr);
    

    在实现中,像这样访问它:

    void GeoAtlas::GetArrayVar(SAFEARRAY* arr)
    {
        CComSafeArray<BSTR> sa;
        sa.Attach(arr);
    
        for (int i = sa.GetLowerBound(); i <= sa.GetUpperBound(); ++i)
        {
            AfxMessageBox(sa[i]);
        }
    
        sa.Detach();
    }
    

    【讨论】:

    • DISP_FUNCTION_ID(GeoAtlas, "GetSafeArray", dispidGetSafeArray, GetSafeArray, VT_EMPTY, VT_SAFEARRAY) ,这一行给出了这个错误 "error C2440: 'initializing' : cannot convert from 'VARENUM' to 'LPCSTR'" 。其他声明为 void GeoAtlas::GetSafeArray(SAFEARRAY* arr) 和 idl is [id(27)] void GetSafeArray(SAFEARRAY(BSTR)* arr);
    • 另外,如果我将 DISP_FUNCTION_ID(GeoAtlas, "GetSafeArray", dispidGetSafeArray, GetSafeArray, VT_EMPTY, VT_SAFEARRAY) 更改为 DISP_FUNCTION_ID(GeoAtlas, "GetSafeArray", dispidGetSafeArray, GetSafeArray, VT_EMPTY, VT_PBSTR) 它会给出运行时错误, "试图读取或写入受保护的内存。这通常表明其他内存已损坏"
    • 抱歉应该是SAFEARRAY(BSTR)(没有额外的*)。我编辑了答案。我不知道另一个错误是什么。
    【解决方案3】:

    发送方看起来不错。在接收方试试这个。

    [id(1), helpstring("method SetArrayVar")] HRESULT SetArrayVar([in] VARIANT varMachineList);
    
    STDMETHODIMP GeoAtlas::SetArrayVar(VARIANT arr)
    {
        long lower, upper;
        SafeArrayGetLBound(pSafeArray, 1, &lower);
        SafeArrayGetUBound(pSafeArray, 1, &upper);
        DWORD dwItems = upper - lower + 1;
        resize(dwItems);
    
        SAFEARRAY* pSafeArray = arr.parray;
        BSTR* pBstr;
        if ( SUCCEEDED(SafeArrayAccessData(pSafeArray, (LPVOID*) &pBstr)) )
        {
            iterator it = begin();
            for ( long i=lower; i<=upper; i++, pBstr++, it++ )
            {
                USES_CONVERSION;
                *it = OLE2CT(*pBstr);
                // Here you gets array elements and use it
            }
        }
    
        // release the data block
        SafeArrayUnaccessData(pSafeArray);
    }
    

    【讨论】:

      【解决方案4】:

      不确定,但看起来您的 Unicode/MBCS 不匹配。

      托管部分创建一个 UTF-16 编码字符串数组,而非托管部分似乎是使用多字节字符集编译的。因此,在看到第一个空字符(实际上只是 UTF-16 字符的第二个字节)时,您的 MBCS 代码认为它已到达字符串的末尾。

      一种解决方案是将 C++ 项目中的字符集设置更改为 Unicode 并重新构建。

      还有一个是改代码:

      ...
      LPCWSTR * arrayAccess = NULL; // change LPCSTR -> LPCWSTR
      ...
      
      for(int iIndex = lStartBound; iIndex <= lEndBound; iIndex ++)
      {   
          bstr_t myString = arrayAccess[iIndex];
          AfxMessageBox(myString);        
      } 
      

      bstr_t 将使用 BSTR 正确初始化,但它也提供到 const char* 的转换,因此调用 AfxMessageBox 就可以了。

      【讨论】:

      • 我无法更改我的 c++ 项目中的字符集设置。另一种解决方案是给出相同的结果,即消息框中只显示一个字符
      • 您确定您使用的是bstr_t myString = (BSTR)arrayAccess[iIndex]; 而不是bstr_t myString = (LPCTSTR)arrayAccess[iIndex];?
      • 哦,我做到了,复制了你的代码。现在,它说“尝试读取或写入受保护的内存。这通常表明其他内存已损坏!
      • 在哪一行bstr_t myString = ... 或AfxMessageBox?调试器说什么?赋值后myString 的值是多少? arrayAccess[iIndex] 指向什么?我还对代码进行了一些编辑,以避免强制转换。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-07-22
      • 2015-05-03
      • 1970-01-01
      • 2014-09-23
      • 2020-05-25
      相关资源
      最近更新 更多