【问题标题】:L prefix for strings in C++C++中字符串的L前缀
【发布时间】:2011-05-04 11:06:15
【问题描述】:

我有一个静态库。该库定义了以下函数

int WriteData(LPTSTR s)

调用函数的示例是

LPTSTR s = (LPTSTR) L"Test Data";   
int n = WriteData(s);

WriteData 成功返回 0,失败返回 -1。

我正在编写一个动态 DLL 来导出这个函数。

int TestFun(LPTSTR lpData)
{
   return  WriteData(lpData);
}

C++ 测试应用结果

LPTSTR s = (LPTSTR) L"Test Data";   
TestFun(s);  //OK  return 0

LPTSTR s = (LPTSTR) "Test Data";    
TestFun(s);  //Fail  return -1

我必须从 C# 应用程序中调用它。我假设我的 DLL-Import 签名是:

        [DllImport("Test.dll")]
        private static extern int TestFun(String s);

我的问题很简单如何从.Net 调用它? 如您所见,我可以控制

TestFun(LPTSTR lpData)

但无法控制

WriteData(LPTSTR s)

感谢大家的意见。到目前为止,我被困在铸造上。我认为当我能够从用户那里获取输入并编写 2 行以代替以下行进行转换时,我的问题将得到解决。

   LPTSTR s = (LPTSTR) L"Test Data"); //<= How can ii take input from user and 
    TestFun(s);  //OK  return 0

【问题讨论】:

  • 在 10 年前使用 TCHAR 是有意义的。没有了,没有您必须支持的非 Unicode 操作系统了。让一切都变成 wchar_t 并继续前进。
  • 将 lpData 传递给 WriteData 函数时,什么“不起作用”?
  • 静态库接口中究竟有什么功能? you 在你的包装 DLL 中写的是什么部分?您希望提供什么接口?
  • lib 函数在成功时返回 0,在失败时返回 -1。我根据函数的输出来判断成功和失败。
  • 如果您不向我们展示该功能,我们如何告诉您您的功能存在什么问题?

标签: c# .net c++ interop marshalling


【解决方案1】:

L 前缀使字符串成为 wchar_t 字符串。 您可以使用 Windows API 函数MultiByteToWideChar 将 ANSI 字符串转换为 wchar_t 字符串。

【讨论】:

  • @Manjoor:您应该真正解释为什么它不起作用。这些人试图免费帮助你,对他们没有任何好处,而你却在忽视他们的努力,让他们觉得他们在浪费时间,因为你太懒了,无法确切地告诉他们为什么他们的解决方案不起作用不适合你。
  • @Platinum Azure 我没那么懒:)。我告诉它不起作用,因为它不起作用。问题解决了。
  • @Manjoor:不,这还不够好。如果您希望人们花时间做您的工作而不付钱给他们,那么您应该向他们描述到底出了什么问题,您的预期输出是什么,您的实际输出是什么,尤其是在您回复答案时。
【解决方案2】:

执行 L 前缀的特定“函数”是宏 TEXT()_T()。 (TEXT 由 Windows SDK 定义,_T 是 Microsoft C Runtime 的扩展)。

当您的项目使用 unicode 支持构建时,这些函数会自动添加 L 前缀(这是现在大多数 MS 开发环境中新项目的默认设置) - 或者为非 unicode(或 ansi)配置的项目保留它。

不要这样做:

LPTSTR s = (LPTSTR) L"ABC";   // Working fine
     WriteData(s);

如果项目曾经配置为非 Unicode,那么 L"ABC" 仍将是一个宽字符数组,但 LPTSTR 将成为一个指向 8 位字符数组的指针。

这是正确地将字符串分配给 Ansi、Unicode 或“文本”字符串的方法。 (文本可以是 Ansi 或 Unicode,具体取决于项目设置)(我省略了 L,因为它是多余的,并添加了一个 C,因为字符串文字应该是常量)。

PCSTR p1 = "ABC";
PCWSTR p2 = L"ABC";
PCTSTR p3 = TEXT("ABC");

【讨论】:

  • 你告诉他什么是行不通的,而不是让他猜测?他会抽出时间来免费回答你的问题。你至少可以给他一些信息。
【解决方案3】:

我认为您很困惑,因为您的功能应该可以正常工作:

int TestFun(LPTSTR lpData)
{
   return  WriteData(lpData); // Should be happy
}

但是当你调用你的函数时,你必须小心:

TestFun((LPTSTR) L"ABC"); // Will work fine
TestFun((LPTSTR) "ABC");  // Will not work

这是因为“ABC”和L“ABC”是两个不同的东西。如果您在内存中查看它们:

"ABC"  | 65 66 67 00
L"ABC" | 65 00 66 00 67 00 00 00

编辑添加:

.Net 中没有 L 前缀

这是错误的。我刚刚在VisualStudio中打开了“New Project->C++->CLR Console”,第一行是:

Console::WriteLine(L"Hello World");

【讨论】:

  • 正如我在问题中提到的,这将是动态 dll。此 dll 将从 .Net 应用程序中调用。 .Net 中没有 L 前缀
  • DLL 导出函数“TestFun”。你能告诉我如何从 C# 应用程序中调用它吗?这是 dll-import [DllImport("Test.dll")] private static extern int TestFun(String s);
  • 感谢您的努力,但我是从 C# 调用它进行测试,它需要从 easylanguage 调用,所以我不能使用 L.
【解决方案4】:

试试:

[DllImport("Test.dll")]
private static extern int TestFun([MarshalAs(UnmanagedType.LPTStr)] string s);

有关使用 MSDN 上的 MarshalAsAttribute 进行封送处理的更多信息。

【讨论】:

    【解决方案5】:

    我会将您的字符串包装在 _T(...) 宏中。这样它就可以在 ANSI 和 UNICODE 构建之间移植。

    请注意,您使用的是可移植字符串类型 - LPTSTR - 请注意 T。它将根据构建设置在 ANSI 和 UNICODE 之间切换。

    【讨论】:

    • 注意:_T 宏是 Microsoft 特定的,而不是通用 C++,如 LPTSTR。并不是说两者都很难重新实现。
    猜你喜欢
    • 2016-04-28
    • 2019-09-10
    • 2012-10-16
    • 2011-09-17
    • 1970-01-01
    • 1970-01-01
    • 2021-06-08
    • 2017-04-29
    • 1970-01-01
    相关资源
    最近更新 更多