[RESOLVED] Program freezes on ConnectNamedPipe() from IDE but works correctly when compiled.
EDIT:
Some people appear to be missing the point of what I am trying to accomplish, so allow me to explicitly spell it out: The whole point of this thread is about exploring what named pipes specifically are and not about inter process communication in general.
The code below works when compiled but freezes when executed from inside the IDE:
Code:
'This module contains this program's core procedures.
Option Explicit
'Defines the Microsoft Windows API constants, functions, and structures used by this program.
Private Const INVALID_HANDLE_VALUE As Long = -1
Private Const PIPE_ACCESS_DUPLEX As Long = &H3&
Private Const PIPE_NOWAIT As Long = &H1&
Private Const PIPE_TYPE_MESSAGE As Long = &H4&
Private Const PIPE_WAIT As Long = &H0&
Private Const PIPE_UNLIMITED_INSTANCES As Long = &HFF&
Private Declare Function CloseHandle Lib "Kernel32.dll" (ByVal hObject As Long) As Long
Private Declare Function ConnectNamedPipe Lib "Kernel32.dll" (ByVal hNamedPipe As Long, lpOverlapped As Any) As Long
Private Declare Function CreateNamedPipeA Lib "Kernel32.dll" (ByVal lpName As String, ByVal dwOpenMode As Long, ByVal dwPipeMode As Long, ByVal nMaxInstances As Long, ByVal nOutBufferSize As Long, ByVal nInBufferSize As Long, ByVal nDefaultTimeOut As Long, lpSecurityAttributes As Any) As Long
Private Declare Function ReadFile Lib "Kernel32.dll" (ByVal hFile As Long, lpBuffer As Any, ByVal nNumberOfBytesToRead As Long, lpNumberOfBytesRead As Long, lpOverlapped As Any) As Long
Private Declare Function WriteFile Lib "Kernel32.dll" (ByVal hFile As Long, lpBuffer As Any, ByVal nNumberOfBytesToWrite As Long, lpNumberOfBytesWritten As Long, lpOverlapped As Any) As Long
'This procedure is executed when this program started.
Public Sub Main()
On Error GoTo ErrorTrap
Dim Buffer() As Byte
Dim BytesWritten As Long
Dim Message As String
Dim PipeH As Long
Message = InputBox$("Enter a message to be sent:", , "(message)")
PipeH = CheckForError(CreateNamedPipeA("\\.\pipe\namedpipe", PIPE_ACCESS_DUPLEX, PIPE_WAIT Or PIPE_TYPE_MESSAGE, PIPE_UNLIMITED_INSTANCES, CLng(&H400&), CLng(&H400&), CLng(30000), ByVal CLng(0)))
If Not PipeH = INVALID_HANDLE_VALUE Then
'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
'''Freezes right here, (and no, it isn't the error checking function that is causing it):
CheckForError ConnectNamedPipe(PipeH, ByVal CLng(0))
'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
Buffer() = Message
CheckForError WriteFile(PipeH, Buffer(0), UBound(Buffer()) - LBound(Buffer()), BytesWritten, ByVal CLng(0))
CheckForError CloseHandle(PipeH)
End If
EndRoutine:
Exit Sub
ErrorTrap:
MsgBox Err.Description & vbCr & "Error code: " & CStr(Err.Number), vbExclamation
Resume EndRoutine
End Sub
There is a tiny companion program that receives messages sent through the pipe created by this program and messages get though as expected. This is if both programs are executed as compiled *.exes.
Re: Program freezes on ConnectNamedPipe() from IDE but works correctly when compiled.
For the sake of completeness, here's the module with the error checking:
Code:
'This module contains API error handling procedures.
Option Explicit
'Defines the Microsoft Windows API constants, functions, and structures used.
Private Const ERROR_SUCCESS As Long = 0
Private Const FORMAT_MESSAGE_FROM_SYSTEM As Long = &H1000&
Private Declare Function FormatMessageA Lib "Kernel32.dll" (ByVal dwFlags As Long, lpSource As Long, ByVal dwMessageId As Long, ByVal dwLanguageId As Long, ByVal lpBuffer As String, ByVal nSize As Long, Arguments As Long) As Long
'Defines the constants used.
Private Const MAX_STRING As Long = 65535 'Defines the maximum length allowed for a string buffer.
'This procedure checks whether an error has occurred during the most recent Windows API call.
Public Function CheckForError(ReturnValue As Long) As Long
Dim Description As String
Dim ErrorCode As Long
Dim Length As Long
Dim Message As String
ErrorCode = Err.LastDllError
Err.Clear
If Not ErrorCode = ERROR_SUCCESS Then
Description = String$(MAX_STRING, vbNullChar)
Length = FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM, CLng(0), ErrorCode, CLng(0), Description, Len(Description), CLng(0))
If Length = 0 Then
Description = "No description."
ElseIf Length > 0 Then
Description = Left$(Description, Length - 1)
End If
Message = "API error code: " & CStr(ErrorCode) & " - " & Description
Message = Message & "Return value: " & CStr(ReturnValue)
MsgBox Message, vbExclamation
End If
CheckForError = ReturnValue
End Function
For debugging purposes you might as well remove the call and use Debug.Print Err.LastDll. I just think this is more user friendly.
Re: Program freezes on ConnectNamedPipe() from IDE but works correctly when compiled.
Here is the program that reads messages sent through the named pipe sent by the other:
Code:
'This module contains this program's core procedures.
Option Explicit
'Defines the Microsoft Windows API constants and functions used by this program.
Private Declare Function CallNamedPipeA Lib "Kernel32.dll" (ByVal lpNamedPipeName As String, lpInBuffer As Any, ByVal nInBufferSize As Long, lpOutBuffer As Any, ByVal nOutBufferSize As Long, lpBytesRead As Long, ByVal nTimeOut As Long) As Long
'This procedure is executed when this program started.
Public Sub Main()
On Error GoTo ErrorTrap
Dim BytesRead As Long
Dim InputBuffer() As Byte
Dim PipeName As String
ReDim InputBuffer(&H0& To &H100&) As Byte
PipeName = "\\.\pipe\namedpipe"
CheckForError CallNamedPipeA(PipeName, CLng(&H0&), CLng(&H0&), InputBuffer(0), UBound(InputBuffer()) - LBound(InputBuffer()), BytesRead, CLng(30000))
If BytesRead = &H0& Then
MsgBox "No message was received", vbExclamation
Else
ReDim Preserve InputBuffer(LBound(InputBuffer()) To BytesRead) As Byte
MsgBox "The following message was received: " & vbCr & """" & CStr(InputBuffer()) & ".""", vbInformation
End If
EndRoutine:
Exit Sub
ErrorTrap:
MsgBox Err.Description & vbCr & "Error code: " & CStr(Err.Number), vbExclamation
Resume EndRoutine
End Sub
And for anyone wondering, I checked using PipeList (SysInternals) to check whether the pipe created would linger after a message has been read. It appears to automatically be removed by the system once the buffer is empty.
PS:
The API error checking function is shared by the two programs. Hence the separate module.
Last edited by Peter Swinkels; Sep 17th, 2023 at 05:55 AM.
Reason: typo
Re: Program freezes on ConnectNamedPipe() from IDE but works correctly when compiled.
I dont have good experience with namedpipe.
and its not just IDE its compiled as well. people reporting they can not start the game "the 2nd time" even if I have the required closepipe is there.
when working with it, if something happens, like a crash. I need to restart windows.
better switch to mapped memory.
Re: Program freezes on ConnectNamedPipe() from IDE but works correctly when compiled.
exactly that is why I told u what to use instead. that or socket. maybe sendmessage if u fine with it.
for me it need to work 100% I can not have something that "it works 95%" of the time.
since its a game that +10k people play and I dont want people reporting bugs.
so, named pipe is to avoid like a plague.
sure, googling u can read that they are reliable. but most often they talk about the "linux" one. its not the same as the windows one.
better switch now instead of spending time with this.
I already spent enough time to understand its not reliable.
Re: Program freezes on ConnectNamedPipe() from IDE but works correctly when compiled.
@baka: Thank you, I am not interested in the alternatives in this case. I wanted to explore specifically what named pipes are. The programs at the start of this thread are merely an experiment and not an attempt at making two processes simply communicate with each other for a larger purpose.
Re: Program freezes on ConnectNamedPipe() from IDE but works correctly when compiled.
what they are?
we could say its memory-files.
like u create Z:\myfile.txt
u write to that "file" something.
now, when a client "reads" the content gets deleted. so its a one-time-thing.
a server writes to the "file" and now the client "reads", while doing that, the server is "waiting", when done, u can decide if the client will "respond" or simply close.
after that u need to repeat the procedure. but u can not read a namedpipe if the server has not created it. u need a procedure here. but the same thing is for mapped memory.
the problem with pipes is that u create a "handle"
u need that "handle" to use that "name".
if that namedpipe is not closed, u can not create a new one of the same name, u get an error.
if so, that name is not usable anymore.
I read somewhere windows will eventually "clean it", but Im not sure the time. I have noticed that after 10 minutes I still couldn't use it.
its annoying when u code, as u can not wait that long to continue working.
to create namedpipe to work without that send>wait method, it will be more difficult. but it seems u dont care about that.
the simple method is what Dil is using. his method works quite well.
Re: Program freezes on ConnectNamedPipe() from IDE but works correctly when compiled.
@dilettante: thank you for the example! :-)
Everyone else, relax, I got it, named pipes are impractical and it's unlikely I will use them for any serious purpose. It's just an experiment I found in my old projects I am trying to get working properly again.
Re: Program freezes on ConnectNamedPipe() from IDE but works correctly when compiled.
I did a lot of work with named pipes in VB a long time ago.
However the server vendor provided that end, along with a proper client ActiveX control with a worker thread inside to allow clients to run fine on Win9x.
Win9x doesn't support server pipes aside from the narrow case of anonymous pipes. So that's most likely why they never provided customers with a server component: NT was still very rare as a desktop OS back then.
Named pipes impractical? Not at all. We just don't have good support for them in VB6.
Re: Program freezes on ConnectNamedPipe() from IDE but works correctly when compiled.
dil, they are not impractical. quite easy to use.
both async and normal communication.
I did try different methods with its pros and cons.
ultimately the problem is the DisconnectNamedPipes & CloseHandle that not always work.
when that happens u can not run the executable anymore since the pipe is already there
and theres no way of using the named pipe if u don't create it, as u need the handle.
ConnectNamedPipe only work for a client so u are stuck.
this is not happening all the time, but it seems that if the pipe is not "empty" it will not release it or some other unknown error.
after several attempts to make it work I just gave up. always something with the creation of the pipes that messed the initialization.
can't have a method like that if the program require the pipe to be active to continue.
Re: Program freezes on ConnectNamedPipe() from IDE but works correctly when compiled.
Why should the fact it's VB6 matter at all for a pure API feature like this? There's nothing in the declares that's unsupported by the VB language one way or another.
Re: Program freezes on ConnectNamedPipe() from IDE but works correctly when compiled.
Named pipes has worked very well for me in one application. We use it for synchronous low-latency, low-throughput communication between two executables that have the same lifetime and run in the same context. But the VB-side is the "client" so it just uses WaitNamedPipe to check for existence and CallNamedPipe to send/poll for data.
Re: [RESOLVED] Program freezes on ConnectNamedPipe() from IDE but works correctly whe
Alright, I figured it out. PIPE_WAIT means that the program connecting to the pipe using that flag will freeze until the another program reads from it. So just launch the client in another vb6 instance and call the pipe using CallNamedPipeA to unfreeze the vb6 instance with the server. Also note, the compiled server will be running in the background unless the pipe is either called or the program terminated.