【问题标题】:Cannot fix an "invalid handle" error in WinAPI when trying to do anything requiring it尝试执行任何需要它的操作时,无法修复 WinAPI 中的“无效句柄”错误
【发布时间】:2019-05-08 09:55:32
【问题描述】:

我正在尝试使用 WinAPI 来操作控制台,主要是能够在我想要的任何地方编写我想要的任何内容,而无需重写整个控制台。我记得我曾经让它更早地工作,但那是很久以前的事了,我似乎丢失了那个代码......哎呀。

无论如何,我记得,我成功的努力比现在要少得多。

我正在使用this MS Docs page 作为参考,我记得之前成功使用过它。

现在,我确实只有几行要开始工作:

#include <windows.h>
#include <iostream>

using namespace std;

int main()
{
    HANDLE hndl = GetStdHandle(STD_INPUT_HANDLE);
    if (hndl == INVALID_HANDLE_VALUE)
    {
        cout << "Invalid handle, error " << GetLastError();
        return 0;
    }
    long unsigned int *chars_written = new long unsigned int;
    if (!WriteConsoleOutputCharacter(hndl, "mystring", 8, {20, 30}, chars_written))
    {
        cout << "Could not write, error " << GetLastError();
        return 0;
    }
    return 0;
}

结果是控制台窗口显示“无法写入,错误 6”,然后结束应用程序。

错误6,根据System Error Codes是“句柄无效”。

我做错了什么?我一定是错过了什么。

我尝试在 Code::Blocks 中工作似乎很重要。

奖励:我尝试了带有完整 WinAPI SDK 的 MS Visual Studio(Code::Blocks 中似乎缺少一些重要部分),虽然主要问题是相同的,但 MS Visual Studio 中的功能似乎没有都符合我正在使用的官方参考,例如WriteConsoleOutputCharacter 需要一个 LPCWSTR 作为其第二个参数,而不是源代码中提到的 LPCSTR 和 Code::Blocks 中的作品。 Windows Data Types

编辑:我发现 WriteConsoleOutputCharacter 实际上是一个宏,并且在 Code::Blocks 和 MS Visual Studio 之间定义不同,因为两个不同的函数存在于两个版本中:WriteConsoleOutputCharacterA() 和 WriteConsoleOutputCharacterW(),可悲的是, MS Docs 中未提及。

提前谢谢你, 莫里斯。

【问题讨论】:

  • Win32API 有很多功能,实际上有两种风格——8 位字符风格和宽字符风格。 WriteConsoleOutputCharacter 实际上只是一个宏,它根据另一个特定的宏定义扩展为 WriteConsoleOutputCharacterAWriteConsoleOutputCharacterW
  • 是的,非常感谢,我稍早注意到了,但很高兴您已确认。这些宏也不一致,有时会导致 A 版本,有时会导致 W 版本。
  • 我个人更喜欢只使用函数(忽略宏),即明确使用AW 后缀标识符。 (实际上,我试图完全阻止 Win32 API,依赖于 C++ 标准库。但这并不总是有效,PC/Windows 是我们的主要交付平台。);-)
  • 当我收到你的回复时,我在谷歌上搜索并找到了这个:SO: WinAPI Unicode and ANSI functions

标签: c++ winapi codeblocks windows-console


【解决方案1】:

首先WriteConsoleOutputCharacter() 需要一个宽字符串作为参数,而您传递一个普通字符串"mystring" 作为参数。为了使它成为一个宽文本,你只需添加字母 L 作为前缀 - 例如:L"mystring"。程序给你一个错误,因为你正在检索的句柄是一个 输入 句柄 (STD_INPUT_HANDLE)。同时,如果您想通过句柄输出到控制台,则需要检索 输出 句柄 (STD_OUTPUT_HANDLE)。

【讨论】:

  • 我可以两者都做吗?另外,我读到所有 WriteConsoloeOutputCharacter() 函数需要的是 GENERIC_WRITE 属性,该属性始终由 GetStdHandle()
  • 是的,两者都可以,但您需要自己创建句柄。您可以通过使用 CreateConsoleScreenBuffer() 函数来做到这一点,它的第一个参数是 GENERIC_READ | GENERIC_WRITE,这将使您能够输入和输出。然后你必须使用 SetConsoleActiveScreenBuffer() 函数将其设置为活动控制台屏幕缓冲区。
  • 我理解正确吗,它会刷新我的控制台窗口并在一种“新层”中使用它,而不是创建一个新窗口?
  • 是的,它就是这样工作的。您可以有多个控制台屏幕缓冲区,但只有活动的一个才会显示在控制台中。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多