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

How can I get a string without garbage from dll?

本文关键字:字符串 dll 获取      更新时间:2023-10-16

我想从 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 : 嗨尼斯儆儆

儆좄* : 字符串

您滥用了SysReAllocString()

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

然后,你把最终的8位字符串数据按原样提供给SysReAllocString(),使用一个简单的char*指针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;
    }