【问题标题】:Converting std::string to a const WCHAR *string required by a GDI+ parameter将 std::string 转换为 GDI+ 参数所需的 const WCHAR *string
【发布时间】:2014-11-19 12:32:23
【问题描述】:

短版我使用的是 unicode。我正在尝试将 std::string 用于需要 const WCHAR string; 的函数。 DrawString(const WCHAR, ...

我用 GCC 编译。一切都是 unicode,我已经指定了。

我一直在尝试将字符串转换为 wchar_t*。目的是让我可以使用 GDI+ 函数输出,它的参数需要它。

这是我输出字符串文字的方式,没有问题,调试正常,工作正常。 http://msdn.microsoft.com/en-us/library/ms535991%28v=vs.85%29.aspx 参考原因:

// works fine
wchar_t* wcBuff;
wcBuff = (wchar_t*)L"Some text here.\0"; 
AddString(wcBuff, wcslen(wcBuff), &gFontFamilyInfo, FontStyleBold, 20, ptOrg_Controls, &strFormat_Info);

现在这是我一整天都在尝试的方法,附带说明:我的转换函数工作正常,这不是问题,也不是创建问题。

// problems
string s = "Level " + convert::intToString(6) + "\0"; 

// try 1 - Segfault
wchar_t* wcBuff = new wchar_t[s.length() + 1]; 
copy(s.begin(), s.end(), wcBuff);

// random tries, compiles, but access violations (my conversion function here has worked other places, do not know for sure here.
wchar_t* wcBuff;
wstring wstr = convert::stringToWideChar(s);
wstring strvalue = convert::stringToWideChar(s);           
wcBuff = (wchar_t*)strvalue.c_str(); 
wcBuff = (wchar_t*)wstr.c_str();

wstring foo;
foo.assign(s.begin(), s.end());
wcBuff = (wchar_t*)foo.c_str();

一切都会编译,但随后会出现问题。一旦达到该点,就会出现一些运行时错误。其他人访问违规和段错误。有些编译调试没问题,但是输出的字符串会随着随机字符不断变化。

有什么想法吗?

【问题讨论】:

  • 我实际上阅读了该主题,并尝试了所有示例,但没有一个有效。我没有使用 Visual Studio,所以我没有包含的头文件。 @Potatoswatter 的两个示例都导致随机字符串输出。
  • 你的std::string的编码是什么? (我不知道)GDI+ 函数期望的编码是什么? (也许是 UTF-16?)顺便说一句,(wchar_t*)L"Some text here.\0" 很危险。
  • 什么是convert::stringToWideChar,您认为它为什么有效?为什么要手动为空终止字符串?为什么你是 C 风格的铸造?停止那个:这是危险的,你做错了。当你在几行之前newed 它时,为什么你在指针上使用=?您应该参加 C++ 入门课程并了解指针的工作原理,您使用错了。这是谷歌上关于该主题的第二次点击:cprogramming.com/tutorial/lesson1.html

标签: c++ gdi+


【解决方案1】:

(这不是一个真正的答案,但对于评论来说太大了)

尝试 1:您没有对字符串进行空终止

尝试2:看不到转换函数就不能评论。移除石膏。

尝试 3:移除石膏,应该没问题。

在所有情况下都使用wchar_t const *wcBuff。如果“尝试 3”失败,则意味着您的代码中的其他地方有错误,这会显示在这里。尝试生成MCVE。您应该能够将其减少到大约 10-20 行。

即使您设法为您的意图编写了正确的代码,这也是一个相当幼稚的转换,因为它不能正确处理 0-127 范围之外的字符。您需要考虑这是否是您想要的,或者您是否想要进行 UTF-8 转换等。

在 Windows 中,您可以使用 MultiByteToWideChar。

【讨论】:

  • 感谢大家的意见。但是,我进行了更多搜索,并且在每次使用“Path.AddString()”时,GDI+ 示例都使用了字符串文字。由于这个原因,我相信这是不可能的。一些有效的版本,行为随机。 GDI+ 有一个带有合理参数的 DrawString() 函数,代价是对其外观的控制较少。
  • @EvanCarslake 生成一个 MCVE 并再次发布(或提交错误报告)
  • 我现在已经完全参与其中。我想不出创建 MCVE 的方法。 pastebin.com/rQnVPPyA 它有效,我只需要一种将变量文本分配给“n”的方法。我手动定义了第一个字符只是为了测试它。
  • 制作MCVE,删除一些与问题无关的代码,看看问题是否依然存在。重复此过程,直到您的代码尽可能小,或者您找到导致问题的原因。
  • 我试图制作一个 MCVE,但是代码太多。有所有 Win32 的东西、GDI+ 调用、HDC、字符串和数据类型。我想在普通的普通控制台中做一个小例子,但被难住了。 pastebin.com/2KCdt959 我更新了一些内容,并将其置于更好的实施环境中。目前编译器没有引发错误,没有警告,调试没有错误,访问冲突,段错误......等等。只有一个问题,绘制时似乎有一个额外的(随机)字符,无法用长度修复 - 1.Thanks
【解决方案2】:
#include <string>

int main() {

   // Can use convenient wstring
   std::wstring wstr = L"My wide string";

   // When you need a whar_t* just do this
   const wchar_t* s = wstr.c_str();

  // unicode form of strcpy
  wchar_t buf[100] = {0};
  wcscpy (buf,s);

  // And if you want to convert from string to wstring
  std::string thin = "I only take up one byte per character!";
  std::wstring wide(thin.begin(), thin.end());

   return 0;
}

【讨论】:

    【解决方案3】:

    我首先将我的数据放入一个 wstring 中。像这样:

    (从字符串转换):

      std::string sString = "This is my string text";
      std::wstring str1(sString.begin(), sString.end());
    

    (从 int 转换):

    wstring str1 = std::to_wstring(BirthDate);
    

    然后,我在 GDI+ 命令中使用它是这样的:

    graphics.DrawString(str1.c_str(), -1,
        &font, PointF(10, 5), &st);
    

    【讨论】:

      【解决方案4】:

      第一件事。 GDI+ 是一个 C++ 库。它使用 Microsoft C++ ABI。 Microsoft C++ ABI 与gcc 完全不兼容,因此您可能会忘记使用它。您可以尝试使用 WinAPI 或任何其他使用 C 调用约定的库。

      现在是wstring 问题。 wchar_t 在 gcc 中是 32 位宽,但 Windows API 要求它是 16 位宽。您不能使用任何需要wchar_t 的本机Windows 调用。

      您可以在gcc 中使用-fshort-wchar 命令行选项,这将使wchar_t 宽为16 位,您将重新获得与Windows API 的兼容性,但失去与libc 的兼容性,因此没有库函数可作用于wchar_t 给你。 std::wstring 可能仅作为标题工作,但 wprintf 或 wscpy 或所有其他编译的东西都不会。

      在编译时没有检测到这些,因为gcc 看到的唯一内容是头文件。它无法判断对应的库是用 16 位 wchar_t 还是 32 位 wchar_t 编译的。

      当您需要将wchar_t 的数组传递给Windows 函数时,您可以使用uint16_t。如果您可以使用 C++11,那么您也可以使用 char16_t。下面是一个适用于基本多语言平面字符的示例:

      std::wstring myLittleNiceWstring; 
      ...
      std::vector<uint16_t> myUglyCompatibilityString;
      std::copy(myLittleNiceWstring.begin(),
                myLittleNiceWstring.end(),
                std::back_inserter(myUglyCompatibilityString));
      myUglyCompatibilityString.push_back(0);
      
      UglyWindowsAPI(static_cast<WCHAR*>(myUglyCompatibilityString.data());
      

      如果您有非 BMP 字符,则需要将 UTF32 转换为 UTF16,而不仅仅是使用 std::copy 复制字符。您可以为此使用libiconv 或自己编写一个转换例程(这很简单),或者只是从互联网上借一些代码。

      我认为,由于这个问题和其他问题,使用 GCC 进行以 Windows 为中心的开发相当困难。只要您坚持使用 POSIX 风格的 API,您就可以使用 gcc。

      【讨论】:

      • 如果这是怎么回事,那么对 GDI 函数的调用应该会给出一个编译错误。到目前为止,OP 还没有提到这一点
      • @MattMcNabb 不会出现编译错误。 Windows API 使用 WCHAR,它的类型定义为 wchar_t。通过查看函数声明,您无法分辨 ABI 是什么。将更新答案。
      猜你喜欢
      • 2012-04-29
      • 1970-01-01
      • 2017-04-08
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2010-10-25
      • 2012-12-27
      相关资源
      最近更新 更多