Cannot receive request in VSCode mode
- Start netcoredbg with arg: "--interpreter=vscode --server"
- My DapClient like this:
var endPoint = new IPEndPoint(IPAddress.Parse("127.0.0.1", 4711));var socket = new Socket(AdressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);socket.Connent(endPoint);var stream = new NetworkStream(socket);var options = new DebugAdapterClientOptions().WithInput(stream).Withoutput(stream);var client = DebugAdapterClinet.Create(options);await client.Initialize(System.Threading.CancellationToken.None); <----run to here and block !!! - In server side(vscodeprotocol.cpp)
at func
std::string VSCodeProtocol::ReadData(){...std::getline(cin, line);if(! cin.good()){//Always run to here, even if DapClinet is just connected, before sending the initialization command。}...}
Is there anything I missed? I am not good at English, I hope my description clears up my problem. Thanks.
@fenixjiang as I understand you write your own plugin for VSCode. According to source code you trying to pass null to NetCoreDbg which sets failbit in cin (check). You should pass VSCode protocol commands instead.
@viewizard could share where to look them?
@alpencolt Thank you for your reply!
Here is a Dap implementation include a DebugAdapterClient( https://github.com/OmniSharp/csharp-language-server-protocol).
I think as far as netcoredbg supports vscode mode, then it should be able to receive messages from dap Client. In fact, it did receive/respond the message from/to my DapClient, but it need to set a breakpoint on the socket connect, and wait for the DapClient send the initialize command. Without this breakpoint, the previous situation will occur.
I set a breakpoint on if(! cin.good()) at method std::string VSCodeProtocol::ReadData(), I can see my initialize request in the cin.

I don't know what to do next. Any suggestions?
I set a breakpoint on if(! cin.good()) at method std::string VSCodeProtocol::ReadData(), I can see my initialize request in the cin.
As I see, debugger execute code inside !cin.good() code block after you command received, that mean you work with cin in wrong way and this is not related to command you sent.
More you could read here: https://en.cppreference.com/w/cpp/io/basic_ios/good
@viewizard I don't know how to get that command in the cin.
I tried call cin.Ignore() cin.clear() before std::getline(). I use cin.seekg() to move the position. I make a endless loop to read buff from cin, but i can't get that command string.
Check what you send on plugin side, you send something that makes cin !good, probably it's null or EOF.
Also you can print line on debugger side to check what comes
I suggest to record communication between two parties by using tcpdump (wireshark, etc...) or strace. Devil might hide in the details.
Which file type is used for netcoredbg's stdin/stdout in your case? This is socket, named pipe, anonymous (unnamed) pipe, something other?
I suspect, we may have issue with unnamed pipes on windows: "Asynchronous (overlapped) read and write operations are not supported by anonymous pipes". (see https://docs.microsoft.com/en-us/windows/win32/ipc/anonymous-pipe-operations)
Can you switch to using of named pipes or sockets in place of stdin/stderr? See unnamed_pair function (in iosystem_win32.cpp) as an example, how to create pair of named pipes.
Try to set up breakpoints in iosystem_win32.cpp, in async_read function and check, that return {} never executes (this means an error). Also check, that Class::read function never returns error (ReadFile API call might return error).
Please rebuild netcoredbg in Debug mode and enable full logs (as described here: https://github.com/Samsung/netcoredbg). Then reproduce the issue, record the log and attach the log to this bug report. This is the first thing you should do. If some errors occurs within IORedirect and IOSystem, IOSystemTraits<T> classes, these errors must be logged.
@kfrolov I found the problem according to your suggestion. The file type is socket, overlapped I/O.
The Class::readmethod in iosystem_win32.cpp returnERROR_IO_PENGDING, and i didn'see where it was processed.
Because I don’t know where is the best place to processed with it, so i directly modified Class::Readthe method, call GetOverlappedResult while last error is ERROR_IO_PENDING.
Class::IOResult Class::read(const FileHandle& fh, void *buf, size_t count)
{
DWORD dwRead = 0;
OVERLAPPED ov = {};
if (!ReadFile(fh.handle, buf, (DWORD)count, &dwRead, &ov))
{
//return { (GetLastError() == ERROR_IO_PENDING ? IOResult::Pending : IOResult::Error), dwRead };
DWORD lastError = GetLastError();
if (lastError == ERROR_IO_PENDING)
{
if (!GetOverlappedResult(fh.handle, &ov, &dwRead, TRUE))
return { IOResult::Error, dwRead };
}
else
return { IOResult::Error, dwRead };
}
return { (dwRead == 0 ? IOResult::Eof : IOResult::Success), dwRead };
}
After this modification, netcoredbg can communicate with my Dap client.
Now there is a new problem. After sending and receiving more than 10 messages, the 'ReadFile' inClass::read return ERROR_WORKING_SET_QUOTA . The cout.flush() failed in VSCodeprotocol::EmitEvent(). I debug into flush in ostream:line548, const sentry _Ok(*this) is false.
I guess the default buffer size of StreamBufmay be too small, so I increased the buff to 1M, but the problem is still the same.
I am looking for the reason why flush failed.
Is my modification about ERROR_IO_PENDING correct? what is the best practice?
@fenixjiang you could find working C# example here - https://github.com/Samsung/netcoredbg/tree/master/test-suite Our test suite framework aimed to network and local interaction with debugger by VSCode and MI/GDB protocols. For example, VSCode network part looks like: https://github.com/Samsung/netcoredbg/blob/master/test-suite/NetcoreDbgTest/VSCode/VSCodeTcpDebuggerClient.cs
Hope this helps.
@fenixjiang, IOResult::Pending error is processed here: https://github.com/Samsung/netcoredbg/blob/2de336c9496f6b3e8817ed19c70a9d957b8afc43/src/utils/streams.cpp#L95 As you can see, in case of such error, code just loops until read opeation will be finished. So I not understood, why this error raises through InStreamBuf class up to std::streambuf and cin starts reporting an error.
Look strange, as ERROR_WORKING_SET_QUOTA error, which is caused by multiple calls to ReadFile without calling GetOverlappedResult (which you have added). I suspect, that GetOverlappedResult must be called every time, even if ReadFile returns True.
As I understood, IOSystemTraits<Win32PlatformTag>::read and write function call ReadFile and WriteFile with non NULL OVERLAPPED argument because of sockets: OVERLAPPED not needed for other file types, but for sockets it is needed, otherwise ReadFile or WriteFile will fail. This is why OVERLAPPED have non-null in synchronous read/write functions. I suspect, this is because WinSock2 library open sockets in asynchronous (with FILE_FLAG_OVERLAPPED` mode).
Microsoft's documentation says (https://docs.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-readfile), "The lpOverlapped parameter must not be NULL..." if file opened with FILE_FLAG_OVERLAPPED set.
And you a right, that GetOverlappedResult(..., bWait=1) must be called to wait for a result. And I suspect, that it must be called even if ReadFile returns True. Also microsoft documentation says, that lpNumberOfBytesRead must be set to NULL (when calling ReadFile) if you are using overlapped IO.
And I think, same is correct for WriteFile. So you must patch both functions, IOSystemTraits<Win32PlatformTag>::read and write.
I curious, why ERROR_IO_PENDING was never raised in our cases. Looks like you have very different Windows version, WinSock2 library, etc... Which exact windows version are you using? Can you reproduce the bug on regular Windows-10 version?
And last question, how are you running netcoredbg? The sockets for cin/cout was opened by netcoreddbg itself (by call to IOSystem::listen_socket, that happens if you are passing --server option to netcoredbg), or you create sockets by itself and pass opened sockets from your program to child process (which is netcoredbg) ?
flush function calls OutStreamBuf::sync(), which calls IOSystem::write, which in fact is IOSystemTraits<Win32PlatformTag>::write. I think the problem is same, win32 function WriteFile returns an error because you have not called GetOverlappedResult, but OVERLAPPED is not null.
Here is my test program with VSCodeTcpDebuggerClient
static void Main(string[] args)
{
Console.WriteLine("Hello World!");
var tcpClient = new VSCodeTcpDebuggerClient("127.0.0.1", 4711);
var debugger = new VSCodeDebugger(tcpClient);
//init
InitializeRequest initReq = new InitializeRequest();
initReq.arguments.clientID = "myTest";
initReq.arguments.clientName = "My Test";
initReq.arguments.adapterID = "coreclr";
//initReq.arguments.pathFormat = "path";
//initReq.arguments.linesStartAt1 = true;
//initReq.arguments.columnsStartAt1 = true;
initReq.arguments.supportsVariableType = true;
initReq.arguments.supportsVariablePaging = true;
initReq.arguments.supportsRunInTerminalRequest = true;
//initReq.arguments.supportsProgressReporting = true;
//initReq.arguments.supportsMemoryReferences = true;
//initReq.arguments.locale = "en-us";
var result = debugger.Request(initReq);
//breaks;
var bp = new SetBreakpointsRequest();
var file = @"D:\Github\Debugger\Test\ConsoleApp16\ConsoleApp2_2\Program.cs";
bp.arguments.source.path = file;
bp.arguments.source.name = System.IO.Path.GetFileName(file);
bp.arguments.breakpoints.Add(new SourceBreakpoint(11));
var bpRet = debugger.Request(bp);
//launch
LaunchRequest launchReq = new LaunchRequest();
//launchReq.arguments.name = "Test my console";
//launchReq.arguments.type = "coreclr";
//launchReq.arguments.preLaunchTask = "build";
launchReq.arguments.program = @"C:\Program Files\dotnet\dotnet.exe";
launchReq.arguments.cwd = @"D:\Github\Debugger\Test\ConsoleApp16\ConsoleApp2_2\bin\Debug\netcoreapp2.2";
launchReq.arguments.args = new System.Collections.Generic.List<string>() { "exec", "D:\\Github\\Debugger\\Test\\ConsoleApp16\\ConsoleApp2_2\\bin\\Debug\\netcoreapp2.2\\ConsoleApp2_2.dll", "AAAA", "BBB" };
launchReq.arguments.env = new System.Collections.Generic.Dictionary<string, string>();
//launchReq.arguments.console = "internalConsole";
//launchReq.arguments.stopAtEntry = true;
//launchReq.arguments.internalConsoleOptions = "openOnSessionStart";
//launchReq.arguments.__sessionId = Guid.NewGuid().ToString();
var r1 = debugger.Request(launchReq);
//configrationDone
var cfgDone = new ConfigurationDoneRequest();
var cfgRet = debugger.Request(cfgDone);
//Please ignore those, just to print the messages
while (true)
{
if (!debugger.IsEventReceived(OnEventReceived))
Task.Delay(500).Wait();
}
_ = Console.ReadLine();
}
And I get the same result. After netcoredbg sends a few messages, in my case it was 8, then vscodeprotocol.cpp/cout.flush fail and cout.eof() return true.
I thought there might be a bug here.
I modified this VSCodeProtocol::EmitEvent method, call cout.clear() after cout.flush(), and communication is normal now.
void VSCodeProtocol::EmitEvent(const std::string &name, const nlohmann::json &body)
{
std::lock_guard<std::mutex> lock(m_outMutex);
json response;
response["type"] = "event";
response["event"] = name;
response["body"] = body;
std::string output = response.dump();
output = VSCodeSeq(m_seqCounter) + output.substr(1);
++m_seqCounter;
cout << CONTENT_LENGTH << output.size() << TWO_CRLF << output;
cout.flush();
cout.clear(); //<-----Add this line!!!
Log(LOG_EVENT, output);
}
For now I have not found the reason why the eof status is set after cout.flush().
We definitely will not add some code just because this change behavior in the way you need. I don't see any reason for cout.clear(); line here. The point is - this could be another issue, that you suppress by this line, but not provide real fix. This issue must be investigated first in order to find out why only you have eof here.
@viewizard, I think you need to test netcoredbg running on Windows-7 and may be on Windows-Vista or Windows-XP. I guess, that all issues caused by overlapped IO which works differently on same previous Windows version.
cout.clear() works, because cout.flush() causes an error. In our case flush ends with call to WriteFile with non-NULL overlapped argument.
I think @fenixjiang uses some "non typical" windows version (installed libraries, other environment related things...) And this is why the bug was not meet in our cases.
@fenixjiang we cannot call clear() since it removes all flags from stream, but they are useful for case when IDE hangs. we must handle such situation.
What Windows version do you use?
Also could you disable all firewalls and antiviruses. If it doesn't help could you check passed data via WireShark or other sniffer.
Sorry for replying so late. My windows version is 10.0.18363.1916, and dotnet sdks version is 5.0.302.
I thought my client may be used incorrectly. I haven't seen other people having the same problem as mine in message transmission. Transmission is a very basic function, and there should not be such a problem. The preconceived ideas have kept me from finding the root of the problem. The changes I made before are probably just to solve the superficial problem.
@fenixjiang check latest release we've fixed some issues on windows platform
@alpencolt I had check the latest release, but my problem still exists.
I start netcoredbg with arguments "--interpreter=vscode --server", then connect it with a dap client (https://github.com/OmniSharp/csharp-language-server-protocol).
netcoredbg exit while init request is send. netcoredbg does not process any command.
GetLastError() is ERROR_IO_PENDING after call function ReadFile in Class::read in file iosystem_win32.cpp . ERROR_IO_PENDING is not considered as IOResult::Error. The loop in InStreamBuf::underflow in file streams.cpp can continued to call ReadFile,
after a while, GetLastError() after call ReadFile return ERROR_NOT_ENOUGH_QUOTA, this is considered as IOResult::Error that make InStreamBuf:::underflow return eof, then VSCodeprotocol::CommandLoop return.
During my debugging, I find it does not call GetOverlappedResult while the last error is ERROR_IO_PENDING as Microsoft's documentation says (https://docs.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-readfile).
I updated upstream sources, it should support Windows 10 x86 now. Could you please confirm, that you still have this issue with latest sources?
@viewizard
I have checked out the lastest sources, and build successfully under Win10 x86. The following problem occurred when experiencing the new features:
I started netcoredbg with --interpreter=cli --hot-reload ,then debug a simple console.
we got a assertion failed.
ncdb> file C:\Users\jz\source\repos\ConsoleApp1\ConsoleApp1\bin\Debug\net5.0\ConsoleApp1.exe
ncdb> b C:\Users\jz\source\repos\ConsoleApp1\ConsoleApp1\Program.cs:17
ncdb> run
Assertion failed: !read_lock, file C:\Work\netcoredbg_v78\src\utils\ioredirect.cpp, line 404
Then i try start netcoredbg directly from VS2019, still have above issue.
I will try this under Win10 x64 , and run netcoredbg in vscode mode later.
Note, we support Hot Reload feature for Tizen OS only, since it required custom runtime build + you will need generate IL/metadata/PDB deltas somehow, and even for Tizen OS it have WIP status.
Here is patch that fix issue with Assertion failed: !read_lock, file C:\Work\netcoredbg_v78\src\utils\ioredirect.cpp, line 404
From 28defb5d7130d1f7a6736c46e5f7eb177743c010 Mon Sep 17 00:00:00 2001
From: Mikhail Kurinnoi <[email protected]>
Date: Fri, 10 Jun 2022 18:01:42 +0300
Subject: [PATCH] Fix CLI work on Windows.
---
src/utils/iosystem_win32.cpp | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/utils/iosystem_win32.cpp b/src/utils/iosystem_win32.cpp
index d206c6c..dc2d4e9 100644
--- a/src/utils/iosystem_win32.cpp
+++ b/src/utils/iosystem_win32.cpp
@@ -525,7 +525,7 @@ Class::IOSystem::StdFiles Class::get_std_files()
std::max_align_t align_field;
char mem[sizeof(Handles)];
};
- mem_align_t mem_align_tmp;
+ static mem_align_t mem_align_tmp;
char * const mem = mem_align_tmp.mem;
Handles& handles = *new (mem) Handles {
--
2.25.1
will be in upstream at next sync.
@viewizard I tred run netcoredbg under vscode mode, and still has transmission issue. These are netcoredbg received and output:
-> (C) {"seq":1,"type":"request","command":"initialize","arguments":{"clientID":"netcoredbg ClientId","clientName":"netcoredbg Client","adapterID":"netcoredbg AdapterId","supportsVariableType":true,"supportsVariablePaging":true,"supportsRunInTerminalRequest":true,"supportsMemoryReferences":true,"supportsProgressReporting":true}}
<- (E) {"body":{"capabilities":{"exceptionBreakpointFilters":[{"filter":"all","label":"all"},{"filter":"user-unhandled","label":"user-unhandled"}],"supportTerminateDebuggee":true,"supportsCancelRequest":true,"supportsConditionalBreakpoints":true,"supportsConfigurationDoneRequest":true,"supportsExceptionFilterOptions":true,"supportsExceptionInfoRequest":true,"supportsExceptionOptions":false,"supportsFunctionBreakpoints":true,"supportsSetExpression":true,"supportsSetVariable":true,"supportsTerminateRequest":true}},"event":"capabilities","seq":"1","type":"event"}
<- (E) {"body":{},"event":"initialized","seq":"2","type":"event"}
<- (R) {"body":{"exceptionBreakpointFilters":[{"filter":"all","label":"all"},{"filter":"user-unhandled","label":"user-unhandled"}],"supportTerminateDebuggee":true,"supportsCancelRequest":true,"supportsConditionalBreakpoints":true,"supportsConfigurationDoneRequest":true,"supportsExceptionFilterOptions":true,"supportsExceptionInfoRequest":true,"supportsExceptionOptions":false,"supportsFunctionBreakpoints":true,"supportsSetExpression":true,"supportsSetVariable":true,"supportsTerminateRequest":true},"command":"initialize","request_seq":1,"seq":"3","success":true,"type":"response"}
At this time code runs to vscodeprotocol.cpp
void VSCodeProtocol::CommandLoop()
{
std::thread commandsWorker{&VSCodeProtocol::CommandsWorker, this};
m_exit = false;
while (!m_exit)
{
std::string requestText = ReadData(cin);
if (requestText.empty())
{
CommandQueueEntry queueEntry;
queueEntry.command = "ncdbg_disconnect";
std::lock_guard<std::mutex> guardCommandsMutex(m_commandsMutex);
m_commandsQueue.clear();
m_commandsQueue.emplace_back(std::move(queueEntry));
m_commandsCV.notify_one(); // notify_one with lock
break; <------------------------------HERE!!!-----------
}
....
and in iosystem_win32.cpp Class::IOResult Class::read(const FileHandle& fh, void *buf, size_t count) , the last error of ReadFile is ERROR_WORKING_SET_QUOTA.
Here are packages captured by wireshark
1 0.000000 kubernetes.docker.internal kubernetes.docker.internal TCP 56 11312 → trinity-dist(4711) [SYN] Seq=0 Win=65535 Len=0 MSS=65495 WS=256 SACK_PERM=1
2 0.000059 kubernetes.docker.internal kubernetes.docker.internal TCP 56 trinity-dist(4711) → 11312 [SYN, ACK] Seq=0 Ack=1 Win=65535 Len=0 MSS=65495 WS=256 SACK_PERM=1
3 0.000113 kubernetes.docker.internal kubernetes.docker.internal TCP 44 11312 → trinity-dist(4711) [ACK] Seq=1 Ack=1 Win=2619648 Len=0
4 0.011588 kubernetes.docker.internal kubernetes.docker.internal TCP 390 11312 → trinity-dist(4711) [PSH, ACK] Seq=1 Ack=1 Win=2619648 Len=346
5 0.011616 kubernetes.docker.internal kubernetes.docker.internal TCP 44 trinity-dist(4711) → 11312 [ACK] Seq=1 Ack=347 Win=2619648 Len=0
6 0.023814 kubernetes.docker.internal kubernetes.docker.internal TCP 626 trinity-dist(4711) → 11312 [PSH, ACK] Seq=1 Ack=347 Win=2619648 Len=582
7 0.023838 kubernetes.docker.internal kubernetes.docker.internal TCP 44 11312 → trinity-dist(4711) [ACK] Seq=347 Ack=583 Win=2619136 Len=0
8 0.025151 kubernetes.docker.internal kubernetes.docker.internal TCP 124 trinity-dist(4711) → 11312 [PSH, ACK] Seq=583 Ack=347 Win=2619648 Len=80
9 0.025171 kubernetes.docker.internal kubernetes.docker.internal TCP 44 11312 → trinity-dist(4711) [ACK] Seq=347 Ack=663 Win=2619136 Len=0
10 0.025626 kubernetes.docker.internal kubernetes.docker.internal TCP 643 trinity-dist(4711) → 11312 [PSH, ACK] Seq=663 Ack=347 Win=2619648 Len=599
11 0.025649 kubernetes.docker.internal kubernetes.docker.internal TCP 44 11312 → trinity-dist(4711) [ACK] Seq=347 Ack=1262 Win=2618368 Len=0
12 0.053768 kubernetes.docker.internal kubernetes.docker.internal TCP 400 11312 → trinity-dist(4711) [PSH, ACK] Seq=347 Ack=1262 Win=2618368 Len=356
13 0.053800 kubernetes.docker.internal kubernetes.docker.internal TCP 44 trinity-dist(4711) → 11312 [ACK] Seq=1262 Ack=703 Win=2619392 Len=0
14 0.058389 kubernetes.docker.internal kubernetes.docker.internal TCP 338 11312 → trinity-dist(4711) [PSH, ACK] Seq=703 Ack=1262 Win=2618368 Len=294
15 0.058415 kubernetes.docker.internal kubernetes.docker.internal TCP 44 trinity-dist(4711) → 11312 [ACK] Seq=1262 Ack=997 Win=2619136 Len=0
16 0.062129 kubernetes.docker.internal kubernetes.docker.internal TCP 486 11312 → trinity-dist(4711) [PSH, ACK] Seq=997 Ack=1262 Win=2618368 Len=442
17 0.062173 kubernetes.docker.internal kubernetes.docker.internal TCP 44 trinity-dist(4711) → 11312 [ACK] Seq=1262 Ack=1439 Win=2618624 Len=0
package No. 10 is the last response send from netcoredbg.
Content-Length: 576
{"body":{"exceptionBreakpointFilters":[{"filter":"all","label":"all"},{"filter":"user-unhandled","label":"user-unhandled"}],"supportTerminateDebuggee":true,"supportsCancelRequest":true,"supportsConditionalBreakpoints":true,"supportsConfigurationDoneRequest":true,"supportsExceptionFilterOptions":true,"supportsExceptionInfoRequest":true,"supportsExceptionOptions":false,"supportsFunctionBreakpoints":true,"supportsSetExpression":true,"supportsSetVariable":true,"supportsTerminateRequest":true},"command":"initialize","request_seq":1,"seq":"3","success":true,"type":"response"}
packages No.12, 14, 16 is not processed by netcoredbg. package details are below: No.12
Content-Length: 333
{"seq":2,"type":"request","command":"setBreakpoints","arguments":{"source":{"name":"CollectionTest.cs","path":"C:\\Users\\JiangZhen\\source\\repos\\ConsoleApp49\\ConsoleApp49\\CollectionTest.cs"},"breakpoints":[{"line":62,"column":17},{"line":90,"column":13},{"line":133,"column":9},{"line":155,"column":9},{"line":180,"column":3}]}}
No.14
Content-Length: 271
{"seq":3,"type":"request","command":"launch","arguments":{"program":"C:\\Users\\JiangZhen\\source\\repos\\ConsoleApp49\\ConsoleApp1\\bin\\Debug\\net6.0\\ConsoleApp1.exe","cwd":"C:\\Users\\JiangZhen\\source\\repos\\ConsoleApp49\\ConsoleApp1\\bin\\Debug\\net6.0","env":{}}}
No.16
Content-Length: 419
{"seq":4,"type":"request","command":"setExceptionBreakpoints","arguments":{"filters":["user-unhandled"],"filterOptions":[{"filterId":"all","condition":"System.NullReferenceException"},{"filterId":"all","condition":"System.Reflection.MissingMetadataException"},{"filterId":"all","condition":"System.Reflection.MissingRuntimeArtifactException"},{"filterId":"all","condition":"System.Windows.Markup.XamlParseException"}]}}
@fenixjiang command look right
I've found old discussion
https://alt.winsock.programming.narkive.com/dJgOGTYa/iocp-readfile-strange-error-error-working-set-quota
Most likely reason of ERROR_WORKING_SET_QUOTA is some limitation on the system.
Please take a look at this question on stackoverflow: https://stackoverflow.com/questions/3442385/calls-to-readfile-return-error-working-set-quota
The problem is clearly described above in my comment from Oct 2021: "Look strange, as ERROR_WORKING_SET_QUOTA error, which is caused by multiple calls to ReadFile without calling GetOverlappedResult (which you have added). I suspect, that GetOverlappedResult must be called every time, even if ReadFile returns True."
From the very beginning, I modified the code according to kfrolov's suggestion to solve the communication problem in VSCode mode, so far it is running well, but I don't know if these modifications are the best practice.
Hereis my modifications:
// Function perform reading from the file: it may read up to `count' bytes to `buf'.
Class::IOResult Class::read(const FileHandle& fh, void *buf, size_t count)
{
//DWORD dwRead = 0;
//OVERLAPPED ov = {};
//if (! ReadFile(fh.handle, buf, (DWORD)count, &dwRead, &ov))
//return { (GetLastError() == ERROR_IO_PENDING ? IOResult::Pending : IOResult::Error), dwRead };
//else
//return { (dwRead == 0 ? IOResult::Eof : IOResult::Success), dwRead };
DWORD dwRead = 0;
OVERLAPPED ov = {};
ov.hEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
if (!ReadFile(fh.handle, buf, (DWORD)count, 0, &ov))
{
if (GetLastError() == ERROR_IO_PENDING)
{
WaitForSingleObject(ov.hEvent, INFINITE);
CloseHandle(ov.hEvent);
if (GetOverlappedResult(fh.handle, &ov, &dwRead, TRUE))
{
DWORD err = GetLastError();
if ( err == ERROR_IO_PENDING
|| err == WAIT_TIMEOUT
|| err == ERROR_IO_INCOMPLETE)
{
return { dwRead == 0? IOResult::Pending : IOResult::Success, dwRead };
}
else
return { (dwRead == 0 ? IOResult::Eof : IOResult::Success), dwRead };
}
else
{
DWORD error = GetLastError();
return { ( error== ERROR_IO_PENDING || error == ERROR_IO_INCOMPLETE || error == WAIT_TIMEOUT ? IOResult::Pending : IOResult::Error), dwRead };
}
}
else
{
return { IOResult::Eof, dwRead };
}
}
else
{
return { (ov.InternalHigh == 0 ? IOResult::Eof : IOResult::Success), ov.InternalHigh };
}
}