我在CloseHandle上获得了一个sigsegv(pipe_settings-> hPipe);我也在这个例子中使用线程,我不认为这与任何事情有关,因为管道是在同一个线程中打开和关闭的。
管道柄似乎也有效。类似的东西:0xcc。 事件句柄也正常关闭。
这是一个完全有效的例子,您应该可以将其放入CLion中,然后进行翻录。任何Windows安装都应该安全。
#include <stdio.h>
#include <windows.h>
#include <unistd.h>
#define UNICODE
#define PIPE_BUFFER_SIZE 4096
#define PIPE_TIMEOUT 10000
#define PIPE_MAX_CONNECT_TIMEOUT 10000
#define PIPE_CONNECT_FAIL_REPEAT_DELAY 1000
#define DUST_TEST_PIPE_NAME "\\\\.\\pipe\\DustTestPipe"
#define PIPE_TEST_TIMEOUT 100000
struct pipe_settings {
HANDLE hPipe;
OVERLAPPED ol;
LPCTSTR name;
DWORD pipe_timeout;
};
WINBOOL PipeClose(struct pipe_settings *pipe_settings)
{
//Dies on CloseHandle(pipe_settings->hPipe) but not on CloseHandle(pipe_settings->ol.hEvent)
return (CloseHandle(pipe_settings->ol.hEvent) && CloseHandle(pipe_settings->hPipe));
}
void InitializePipeSettings(struct pipe_settings *pipe_settings)
{
pipe_settings->hPipe = INVALID_HANDLE_VALUE;
pipe_settings->ol.hEvent = INVALID_HANDLE_VALUE;
pipe_settings->ol.Internal = 0;
pipe_settings->ol.InternalHigh = 0;
pipe_settings->ol.Offset = 0;
pipe_settings->ol.OffsetHigh = 0;
pipe_settings->ol.Pointer = NULL;
}
DWORD PipeConnectToClient(struct pipe_settings *pipe_settings)
{
HANDLE h;
DWORD err;
InitializePipeSettings(pipe_settings);
for(int x = 0; x < PIPE_MAX_CONNECT_TIMEOUT; x += PIPE_CONNECT_FAIL_REPEAT_DELAY)
{
h = CreateFile(
pipe_settings->name,
GENERIC_WRITE,
FILE_SHARE_READ | FILE_SHARE_WRITE,
NULL,
OPEN_EXISTING,
FILE_FLAG_OVERLAPPED,
NULL
);
err = GetLastError();
if (h != INVALID_HANDLE_VALUE)
break;
if(err == ERROR_FILE_NOT_FOUND) {
//The pipe might not be open yet
sleep(PIPE_CONNECT_FAIL_REPEAT_DELAY/1000);
continue;
}
else if (err != ERROR_PIPE_BUSY) {
return err;
}
if (!WaitNamedPipe(pipe_settings->name, (DWORD)PIPE_MAX_CONNECT_TIMEOUT - x))
{
return ERROR_PIPE_BUSY;
}
}
if(h == INVALID_HANDLE_VALUE)
return err;
pipe_settings->hPipe = h;
DWORD dwMode = PIPE_READMODE_BYTE;
if(!SetNamedPipeHandleState(h, &dwMode, NULL, NULL))
return GetLastError();
return ERROR_SUCCESS;
}
DWORD PipeListenForServerConnect(struct pipe_settings *pipe_settings)
{
InitializePipeSettings(pipe_settings);
HANDLE hPipe = CreateNamedPipe(
pipe_settings->name,
PIPE_ACCESS_INBOUND | // read/write access
FILE_FLAG_OVERLAPPED, // overlapped mode
PIPE_TYPE_BYTE | // message-type pipe
PIPE_READMODE_BYTE | // message-read mode
PIPE_WAIT,
1,
PIPE_BUFFER_SIZE,
PIPE_BUFFER_SIZE,
PIPE_TIMEOUT,
NULL
);
if (hPipe == INVALID_HANDLE_VALUE)
{
return GetLastError();
}
OVERLAPPED ol;
//DWORD dwWait;
ol.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
if(ol.hEvent == NULL)
{
return GetLastError();
}
if(ConnectNamedPipe(hPipe, &ol) == 0)
{
//error should be ERROR_IO_PENDING or ERROR_PIPE_CONNECTED
DWORD err = GetLastError();
//wait for the connection event
if (err != ERROR_IO_PENDING && err != ERROR_PIPE_CONNECTED) {
if (WaitForSingleObject(ol.hEvent, pipe_settings->pipe_timeout) != WAIT_OBJECT_0) {
CloseHandle(hPipe);
CloseHandle(ol.hEvent);
return err;
}
}
}
pipe_settings->hPipe = hPipe;
pipe_settings->ol.Pointer = ol.Pointer;
pipe_settings->ol.Offset = ol.Offset;
pipe_settings->ol.Internal = ol.Internal;
pipe_settings->ol.hEvent = ol.hEvent;
pipe_settings->ol.InternalHigh = ol.InternalHigh;
pipe_settings->ol.OffsetHigh = ol.OffsetHigh;
return ERROR_SUCCESS;
}
DWORD WINAPI ClientProc(LPVOID)
{
struct pipe_settings pipe_settings;
pipe_settings.name = TEXT(DUST_TEST_PIPE_NAME);
pipe_settings.pipe_timeout = PIPE_TEST_TIMEOUT;
DWORD err = PipeListenForServerConnect(&pipe_settings);
//EXPECT_EQ((DWORD)ERROR_SUCCESS, err);
WINBOOL pipe_close_success = PipeClose(&pipe_settings);
//EXPECT_NE(1, pipe_close_success);
return 0;
}
DWORD WINAPI ServerProc(LPVOID)
{
struct pipe_settings pipe_settings;
pipe_settings.name = TEXT(DUST_TEST_PIPE_NAME);
pipe_settings.pipe_timeout = PIPE_TEST_TIMEOUT;
DWORD err = PipeConnectToClient(&pipe_settings);
//EXPECT_EQ((DWORD)ERROR_SUCCESS, err);
WINBOOL pipe_close_success = PipeClose(&pipe_settings);
//EXPECT_NE(0, pipe_close_success);
return 0;
}
int main(void) {
DWORD dwThreadId1;
DWORD dwThreadId2;
HANDLE h1 = CreateThread(NULL, 0, ServerProc, NULL, 0, &dwThreadId1);
HANDLE h2 = CreateThread(NULL, 0, ClientProc, NULL, 0, &dwThreadId2);
WaitForSingleObject(h1, INFINITE);
WaitForSingleObject(h2, INFINITE);
// your code goes here
return 0;
}
答案 0 :(得分:1)
CreateEvent()
不使用INVALID_HANDLE_VALUE
来表示无效句柄,而是使用NULL
。因此,您需要InitializePipeSettings()
将ol.hEvent
初始化为NULL
:
void InitializePipeSettings(struct pipe_settings *pipe_settings)
{
pipe_settings->hPipe = INVALID_HANDLE_VALUE;
pipe_settings->ol.hEvent = NULL; // <-- here
pipe_settings->ol.Internal = 0;
pipe_settings->ol.InternalHigh = 0;
pipe_settings->ol.Offset = 0;
pipe_settings->ol.OffsetHigh = 0;
pipe_settings->ol.Pointer = NULL;
}
然后在PipeClose()
中,您需要先检查INVALID_HANDLE_VALUE
/ NULL
的每个句柄,然后再调用CloseHandle()
。并且您还应PipeClose()
重置其关闭的句柄,以便PipeClose()
可以安全地多次调用pipe_settings
:
WINBOOL PipeClose(struct pipe_settings *pipe_settings)
{
BOOL bResult = TRUE;
if (pipe_settings->ol.hEvent != NULL)
{
bResult = bResult && CloseHandle(pipe_settings->ol.hEvent);
pipe_settings->ol.hEvent = NULL;
}
if (pipe_settings->hPipe != INVALID_HANDLE_VALUE)
{
bResult = bResult && CloseHandle(pipe_settings->hPipe);
pipe_settings->hPipe = INVALID_HANDLE_VALUE;
}
return bResult;
}
答案 1 :(得分:0)
这是我的最终解决方案,但我不知道为什么。
WINBOOL PipeClose(struct pipe_settings *pipe_settings)
{
bool failed = false;
if(pipe_settings->ol.hEvent != NULL)
{
if(!CloseHandle(pipe_settings->ol.hEvent))
failed = true;
}
if(pipe_settings->hPipe != INVALID_HANDLE_VALUE)
{
if(!CloseHandle(pipe_settings->hPipe))
failed = true;
}
return failed ? 0 : 1;
}
void InitializePipeSettings(struct pipe_settings *pipe_settings)
{
pipe_settings->hPipe = INVALID_HANDLE_VALUE;
pipe_settings->ol.hEvent = NULL;
pipe_settings->ol.Internal = 0;
pipe_settings->ol.InternalHigh = 0;
pipe_settings->ol.Offset = 0;
pipe_settings->ol.OffsetHigh = 0;
pipe_settings->ol.Pointer = NULL;
}