代码之家  ›  专栏  ›  技术社区  ›  Eli

创建一个系统::从托管C++中的BSTR中获取String对象,这是个好主意吗?

  •  0
  • Eli  · 技术社区  · 16 年前

    RFC_PARAMETER aux;
    Object* target;
    RFC_UNICODE_TYPE_ELEMENT* elm;
    elm = &(m_coreObject->m_pStructMeta->m_typeElements[index]);
    aux.name = NULL;
    aux.nlen = 0;
    aux.type = elm->type;
    aux.leng = elm->c2_length;
    aux.addr = m_coreObject->m_rfcWa + elm->c2_offset;
    
    GlobalFunctions::CreateObjectForRFCField(target,aux,elm->decimals);
    GlobalFunctions::ReadRFCField(target,aux,elm->decimals);
    

    其中GlobalFunctions::CreateObjectForRFCField创建了一个System::String对象,该对象中填充了空格(用于填充)以达到非托管库规定的最大长度:

    static void CreateObjectForRFCField(Object*& object, RFC_PARAMETER& par, unsigned dec)
    {
        switch (par.type)
        {
            case TYPC:
                object = new String(' ',par.leng / sizeof(_TCHAR));
                break;
            // unimportant afterwards.
        }
    }
    

    static void ReadRFCField(String* target, RFC_PARAMETER& par)
    {
        int lngt;
        _TCHAR* srce;
        switch (par.type)
        {
            case TYPC:
            case TYPDATE:
            case TYPTIME:
            case TYPNUM:
                lngt = par.leng / sizeof(_TCHAR);
                srce = (_TCHAR*)par.addr;
                break;
    
            case RFCTYPE_STRING:
                lngt = (*(_TCHAR**)par.addr != NULL) ? (int)_tcslen(*(_TCHAR**)par.addr) : 0;
                srce = *(_TCHAR**)par.addr;
                break;
    
            default:
                throw new DotNet_Incomp_RFCType2;
        }
    
        if (lngt > target->Length) lngt = target->Length;
    
        GCHandle gh = GCHandle::Alloc(target,GCHandleType::Pinned);
        wchar_t* buff = reinterpret_cast<wchar_t*>(gh.AddrOfPinnedObject().ToPointer());
        _wcsnset(buff,' ',target->Length);
        _snwprintf(buff,lngt,_T2WFSP,srce);
        gh.Free();
    }
    

    是的, 我 错 这就是原因。

    伊莱。

    2 回复  |  直到 16 年前
        1
  •  1
  •   Daniel Earwicker    16 年前

    我很惊讶这似乎能奏效。如果我明白了,你就别针 String 对象,获取其地址,然后将其强制转换为字符缓冲区。它不是一个字符缓冲区。CLR对象以8字节的头开始(无论如何是32位)。您可能正在垃圾收集中破坏CLR使用的内部数据。

    std::vector<wchar_t> 最好)传递到本机API,然后从该缓冲区安全地构造一个CLR字符串?

    更新:

    好的,这里有一个参考资料: http://www.drdobbs.com/cpp/184403869

    一串 ,并知道如何查找和返回原始内部字符缓冲区。是的!

    最后一点很重要:在某些方面 这些例子,我展示了如何 可以使用pin_cast访问 托管字符串的专用数据缓冲区 态度。鉴于这些是密封式的, 不知道,假设你 别针。

    有趣的是 API documentation

        2
  •  0
  •   Eli    16 年前

    实际上,问题不在于.NET字符串作为输出缓冲区,而在于 而不是缓冲区。

    sprintf(“%s”)类函数(包括wsprintf等)将对字符串上的任何参数执行strlen类型的操作—即使是snwprintf—“n”部分仅限制写入字符串的数量,而不限制从输入缓冲区读取的字符。

    结果发现,输入缓冲区从来没有保证以null结尾。很多时候我们很幸运,因为如果返回的数据很小,它会在到达坏内存之前命中空值。

    但是,如果其中的数据足够大,它将转到内存页的末尾。当strlen继续运行时,它会离开页面,进入城市!

    我们将snwprintf改为wcsncpy()(当我们必须执行ANSI时,snwprintf是一个遗留操作->Unicode转换-为什么他不做MultiByteToWideChar(),我永远也不知道。

    无论如何谢谢你的建议。

    推荐文章