如何检查HANDLE是否有效?

发布于 2024-10-31 10:57:59 字数 169 浏览 5 评论 0原文

在 C++ 中,我打开了一个具有 HANDLE 的串行端口。由于端口可能会被外部应用程序关闭,因此在读取数据之前如何验证HANDLE仍然有效?

我认为可以通过根据合适的 API 函数检查 HANDLE 来完成,但是哪个呢? 谢谢。

In C++, I have opened a serial port that has a HANDLE. Since the port may close by an external application, how can I verify that the HANDLE is still valid before reading data?

I think it can be done by checking the HANDLE against a suitable API function, but which?
Thank you.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(8

幽梦紫曦~ 2024-11-07 10:57:59

检查句柄是否“有效”是一个错误。您需要有更好的方法来处理这个问题。

问题是,一旦关闭一个句柄,重新打开不同的东西就可以生成相同的句柄值,并且您的测试可能会说该句柄有效,但您并没有对您认为的文件进行操作。

例如,考虑以下序列:

  1. 句柄已打开,实际值为 0x1234
  2. 使用句柄并传递值
  3. 句柄已关闭。
  4. 程序的其他部分打开一个文件,获取句柄值 0x1234
  5. 原始句柄值被“检查有效性”,并通过。
  6. 使用了句柄,操作了错误的文件。

因此,如果这是您的进程,您需要跟踪哪些句柄有效,哪些句柄无效。如果您从其他进程获取了句柄,则会使用 DuplicateHandle() 将其放入您的进程中。在这种情况下,您应该管理句柄的生命周期,而源进程不应该为您执行此操作。如果您的句柄从另一个进程中关闭,我认为您就是这样做的人,并且您需要处理簿记。

Checking to see whether a handle is "valid" is a mistake. You need to have a better way of dealing with this.

The problem is that once a handle has been closed, the same handle value can be generated by a new open of something different, and your test might say the handle is valid, but you are not operating on the file you think you are.

For example, consider this sequence:

  1. Handle is opened, actual value is 0x1234
  2. Handle is used and the value is passed around
  3. Handle is closed.
  4. Some other part of the program opens a file, gets handle value 0x1234
  5. The original handle value is "checked for validity", and passes.
  6. The handle is used, operating on the wrong file.

So, if it is your process, you need to keep track of which handles are valid and which ones are not. If you got the handle from some other process, it will have been put into your process using DuplicateHandle(). In that case, you should manage the lifetime of the handle and the source process shouldn't do that for you. If your handles are being closed from another process, I assume that you are the one doing that, and you need to deal with the book keeping.

五里雾 2024-11-07 10:57:59

即使将有效句柄传递给某些 WinAPI 函数,某些 WinAPI 函数也会返回无意义的 ERROR_INVALID_PARAMETER,因此存在实际用例来检查句柄的有效性。

GetHandleInformation 函数完成以下工作:
http://msdn.microsoft.com/en -us/library/ms724329%28v=vs.85%29.aspx

Some WinAPI functions return meaningless ERROR_INVALID_PARAMETER even if valid handles are passed to them, so there is a real use case to check handles for validity.

GetHandleInformation function does the job:
http://msdn.microsoft.com/en-us/library/ms724329%28v=vs.85%29.aspx

甜嗑 2024-11-07 10:57:59

因为端口可能会被外部应用程序关闭

这是不可能的,外部应用程序无法获取正确的句柄值来传递给 CloseHandle()。打开端口后,任何其他尝试获取该端口句柄的进程都将被 AccessDenied。

也就是说,有一些垃圾软件通过掌握存储进程句柄的未记录的内核结构的秘密知识来绕过这一限制。你对他们无能为力,不要犯同样的错误来参加这场战斗。你会输的。如果顾客对此抱怨,请向他们提供我的医生建议:“如果疼痛,就不要这样做”。

as the port may close by a external application

This is not possible, an external application cannot obtain the proper handle value to pass to CloseHandle(). Once you have the port opened, any other process trying to get a handle to the port will get AccessDenied.

That said, there's crapware out there that hacks around this restriction by having secret knowledge of the undocumented kernel structures that stores handles for a process. You are powerless against them, don't make the mistake of taking on this battle by doing the same. You will lose. If a customer complains about this then give them my doctor's advice: "if it hurts then don't do it".

疏忽 2024-11-07 10:57:59

如果您得到一个HANDLE并且只是想查明它是否确实是一个打开的文件句柄,可以使用Windows API函数GetFileInformationByHandle 为此。

根据您的句柄授予您的文件权限,您还可以尝试使用 SetFilePointer,使用 ReadFile,或执行使用 WriteFilenNumberOfBytesToWrite 设置为 0。

If you are given a HANDLE and simply want to find out whether it is indeed an open file handle, there is the Windows API function GetFileInformationByHandle for that.

Depending on the permissions your handle grants you for the file, you can also try to move the file pointer using SetFilePointer, read some data from it using ReadFile, or perform a null write operation using WriteFile with nNumberOfBytesToWrite set to 0.

姐不稀罕 2024-11-07 10:57:59

可能你在windows下使用ReadFile来读取数据。检查它的唯一方法是尝试阅读。如果 HANDLE 无效,它将返回一个错误代码(使用 GetLastEror() 查看它是哪一个),可能是 ERROR_HANDLE_INVALID

Probably you are under windows and using ReadFile to read the data. The only way to check it is trying to read. If the HANDLE is invalid it'll return an error code (use GetLastEror() to see which one it is) which will probably be ERROR_HANDLE_INVALID.

烟雨凡馨 2024-11-07 10:57:59

我知道有点晚了,但我有一个与您类似的问题,如何检查管道(我使用 CreateFile 创建的管道)是否仍然打开(也许另一端关闭连接)并且可以读取,如果实在不行,再打开一次。我按照@Felix Dombek 的建议进行操作,并使用 WriteFile 来检查连接。如果它返回 1,则意味着管道已打开,否则我再次使用 CreateFile 打开它。这意味着您的管道是双工的。这是创建文件:
hPipe2 = CreateFile(lpszPipename2, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_ALWAYS, FILE_FLAG_WRITE_THROUGH, NULL);
这是我检查连接的方法:

while(1)
{   
    bool MessageSent = WriteFile(hPipe2, "Test", 0, &cbWritten, NULL);
    if (!(MessageSent))
    {
        LogsOut("Read pipe has been disconnected");
        //Call method to start the pipe again
        break;
    }
    Sleep(200); // I need this because it is a thread
}

这对我来说工作得很好:)

I know that it's a little bit late but I had a similar question to you, how to check if a pipe (a pipe I created using CreateFile) is still open (maybe the other end shut down the connection) and can read, and if it is not, to open it again. I did what @Felix Dombek suggested, and I used the WriteFile to check the connection. If it returned 1 it means the pipe is open, else I opened it using the CreateFile again. This implies that your pipe is duplex. Here's the CreateFile:
hPipe2 = CreateFile(lpszPipename2, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_ALWAYS, FILE_FLAG_WRITE_THROUGH, NULL);
and here is how I checked for the connection:

while(1)
{   
    bool MessageSent = WriteFile(hPipe2, "Test", 0, &cbWritten, NULL);
    if (!(MessageSent))
    {
        LogsOut("Read pipe has been disconnected");
        //Call method to start the pipe again
        break;
    }
    Sleep(200); // I need this because it is a thread
}

This is working just fine for me :)

ま昔日黯然 2024-11-07 10:57:59

您可以使用DuplicateHandle来测试句柄有效性。

第一种方法:您可以尝试复制要检查有效性的句柄。基本上,无效句柄不能重复。

第二种方法:DuplicateHandle 函数从头开始搜索 Win32 句柄描述符表以查找空记录以重用它,从而为其分配一个重复的句柄。您可以仅测试重复的句柄地址值是否大于您的句柄地址,如果它更大,则该句柄不会被视为无效,因此不会被重用。但这种方法非常具体和有限,并且只有当您要测试的句柄值地址上方不再有空或无效句柄记录时,它才起作用。

但是,只有当您跟踪您这边的所有句柄创建和复制时,上面所说的所有内容才有效。

Windows 7的示例

方法#1

// check stdin on validity

HANDLE stdin_handle_dup = INVALID_HANDLE_VALUE;
const bool is_stdin_handle_dup = !!DuplicateHandle(GetCurrentProcess(), GetStdHandle(STD_INPUT_HANDLE), GetCurrentProcess(), &stdin_handle_dup, 0, FALSE, DUPLICATE_SAME_ACCESS);
if (is_stdin_handle_dup && stdin_handle_dup != INVALID_HANDLE_VALUE) {
    CloseHandle(stdin_handle_dup);
    stdin_handle_dup = INVALID_HANDLE_VALUE;
}

方法#2

// Assume `0x03` address has a valid stdin handle, then the `0x07` address can be tested on validity (in Windows 7 basically stdin=0x03, stdout=0x07, stderr=0x0b).
// So you can duplicate `0x03` to test `0x07`.

bool is_stdout_handle_default_address_valid = false;
HANDLE stdin_handle_dup = INVALID_HANDLE_VALUE;
const bool is_stdin_handle_dup = !!DuplicateHandle(GetCurrentProcess(), (HANDLE)0x03, GetCurrentProcess(), &stdin_handle_dup, 0, FALSE, DUPLICATE_SAME_ACCESS);
if (is_stdin_handle_dup && stdin_handle_dup != INVALID_HANDLE_VALUE) {
    if (stdin_handle_dup > (HANDLE)0x07) {
        is_stdout_handle_default_address_valid = true; // duplicated into address higher than 0x07, so 0x07 contains a valid handle
    }
    CloseHandle(stdin_handle_dup);
    stdin_handle_dup = INVALID_HANDLE_VALUE;
}

You can use DuplicateHandle to test handle validity.

First method: You can try to duplicate the handle you want to check on validity. Basically, invalid handles can not be duplicated.

Second method: The DuplicateHandle function does search the Win32 handle descriptor table from beginning for an empty record to reuse it and so assign into it a duplicated handle. You can just test the duplicated handle address value on value greater than yours handle address and if it is greater, then the handle is not treated as invalid and so is not reused. But this method is very specific and limited, and it does only work, when there is no more empty or invalid handle records above the handle value address you want to test.

But all this just said above is valid only if you track all handles creation and duplication on your side.

Examples for Windows 7:

Method #1

// check stdin on validity

HANDLE stdin_handle_dup = INVALID_HANDLE_VALUE;
const bool is_stdin_handle_dup = !!DuplicateHandle(GetCurrentProcess(), GetStdHandle(STD_INPUT_HANDLE), GetCurrentProcess(), &stdin_handle_dup, 0, FALSE, DUPLICATE_SAME_ACCESS);
if (is_stdin_handle_dup && stdin_handle_dup != INVALID_HANDLE_VALUE) {
    CloseHandle(stdin_handle_dup);
    stdin_handle_dup = INVALID_HANDLE_VALUE;
}

Method #2

// Assume `0x03` address has a valid stdin handle, then the `0x07` address can be tested on validity (in Windows 7 basically stdin=0x03, stdout=0x07, stderr=0x0b).
// So you can duplicate `0x03` to test `0x07`.

bool is_stdout_handle_default_address_valid = false;
HANDLE stdin_handle_dup = INVALID_HANDLE_VALUE;
const bool is_stdin_handle_dup = !!DuplicateHandle(GetCurrentProcess(), (HANDLE)0x03, GetCurrentProcess(), &stdin_handle_dup, 0, FALSE, DUPLICATE_SAME_ACCESS);
if (is_stdin_handle_dup && stdin_handle_dup != INVALID_HANDLE_VALUE) {
    if (stdin_handle_dup > (HANDLE)0x07) {
        is_stdout_handle_default_address_valid = true; // duplicated into address higher than 0x07, so 0x07 contains a valid handle
    }
    CloseHandle(stdin_handle_dup);
    stdin_handle_dup = INVALID_HANDLE_VALUE;
}
灵芸 2024-11-07 10:57:59

为了检查句柄,首先我们需要知道我们的句柄是什么,(对于文件/端口/窗口,...),然后找到一个合适的函数来检查它(感谢@janm的帮助)。请注意,该功能的职责可能专门针对该目的地,也可能不是。在我的例子中,我通过 CreateFile() 打开了一个串行端口,我可以通过 GetCommState() API 函数来检查 COM 状态,该函数填充我们的 COM 信息结构。如果端口不再打开或无法访问,该函数将返回 0,并且如果您立即调用 GetLastError(),您将获得 ERROR_INVALID_HANDLE 值。感谢大家的帮助。

In order to check the handle , first we need to know what is our HANDLE for, (for a File/Port/Window, ...), Then find an appropriate function to check it (thanks @janm for help). Note that the function's duty may be specially for this destination or not. In my case that iv'e opened a Serial port by CreateFile() , i can check the COM status by GetCommState() API function that fills our COM info struct. If the port is not open anymore or inaccessible the function returns 0 and if you call GetLastError() immediately, you`ll get the ERROR_INVALID_HANDLE value. Thanks everyone for helps.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文