如何从dll获取没有垃圾的字符串?

时间:2017-03-17 04:12:14

标签: c++ vba dll

我想在VB中从dll获取一个字符串,所以我已经制作了一些代码,如下所示,

#include <windows.h> 
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <iostream>
#include <tchar.h>
#include <atlconv.h>
#include <atlcoll.h>  
#include <assert.h> 
#include <atlbase.h> 

using namespace std;

double _stdcall pll_dll(double* datain0, double* datain1, double* dataout0, double* dataout1, BSTR * str, int* str_len)
{
    char buff[128];
    char * str0;
    char str1[128];


    *dataout0 = *datain0 + 20;
    *dataout1 = *datain1 + 30;

    *str_len =  30;

    str0 = " Nice ";
    sprintf(buff, "Hi  %s  \n", str0);
    strcpy(str1, buff);

    char* p = str1;
    SysReAllocString(str, (OLECHAR*)p);



    return 0;
}

但是特别是,在这种情况下,当我证明s时,我有一个带有垃圾数据的字符串,如下所示。

那么如何在没有这些垃圾数据的情况下获取字符串呢?

  

:s:嗨好儆儆儆儆儆儆儆좄*:字符串

1 个答案:

答案 0 :(得分:1)

您滥用SysReAllocString()

您的缓冲区在声明时未初始化,因此它们最初包含堆栈中已存在的任何随机字节。 sprintf()strcpy()然后使用有效的8位数据填充缓冲区并使用null终止它们,这在使用8位字符串时很好。但它们不会覆盖空终止符之后的任何内存,因此那里仍然存在随机字节。

然后使用SysReAllocString()指向char*指针的简单类型转换,将最终的8位字符串数据按原样提供给wchar_t*,以保持编译器满意。但是你仍然指着8位数据。 SysReAllocString()需要一个正确的16位Unicode字符串,包括一个16位的空终止符号。由于您只有一个8位空终止符,因此该函数最终会通过空终止符复制到周围的内存中。

如果你摆脱了类型转换,代码将无法编译,并且有充分的理由。不要使用类型转换来避免编译器错误。

使用零预初始化缓冲区只会屏蔽问题,方法是确保最终缓冲区中有连续的空字节,当解释为16位数据时,它可以充当Unicode空终止符。但是你仍然在缓冲区中存储8位字符数据。

要正确解决此问题,必须先将输出字符串数据转换为Unicode,然后才能从中创建BSTR

您需要:

  • 使用MultiByteToWideChar()将您的最终char数据转换为wchar_t

    double _stdcall pll_dll(double* datain0, double* datain1, double* dataout0, double* dataout1, BSTR * str, int* str_len)
    {
        char c_buff[128] = {0};
        wchar_t w_buff[128] = {0};
        char * str0;
        int len;
    
        *dataout0 = *datain0 + 20;
        *dataout1 = *datain1 + 30;
    
        *str_len = 30;
    
        str0 = " Nice ";
        len = sprintf(c_buff, "Hi %s \n", str0);
    
        len = MultiByteToWideChar(CP_ACP, 0, c_buff, len, w_buff, 128);
    
        SysReAllocStringLen(str, w_buff, len);
    
        return 0;
    }
    
  • 重写代码以使用swprintf()代替sprintf()

    double _stdcall pll_dll(double* datain0, double* datain1, double* dataout0, double* dataout1, BSTR * str, int* str_len)
    {
        wchar_t buff[128] = {0};
        wchar_t * str0;
        int len;
    
        *dataout0 = *datain0 + 20;
        *dataout1 = *datain1 + 30;
    
        *str_len = 30;
    
        str0 = L" Nice ";
        len = swprintf(buff, L"Hi %s \n", str0);
    
        SysReAllocStringLen(str, buff, len);
    
        return 0;
    }