we have a Windows Service (WS) written in C. The WS listens on a port for incoming requests. One of the requests is to start a child process and pass the SOCKET on to it so that the Requesting Application Server (RAS) continues talking to the Child Process afterwards. The Child Process Executable (CPE) is written in C too.
This is the (simplified) code of the WS:
...
HANDLE curr_channel // is the SOCKET our WS got from accepting an incoming connection attempt
HANDLE process_h = GetCurrentProcess();
HANDLE new_channel;
DuplicateHandle(process_h, curr_channel, process_h, &new_channel, 0, TRUE, DUPLICATE_SAME_ACCESS); // note that bInheritHandles is set to TRUE (1)
char command_line[2048];
sprintf(command_line, "<path to executable to be started as child process> %Iu", (unsigned __int64)new_channel);
PROCESS_INFORMATION process_info;
memset(&process_info, 0, sizeof(PROCESS_INFORMATION));
STARTUPINFO startup;
memset(&startup, 0, sizeof(STARTUPINFO));
startup.cb = sizeof(STARTUPINFO);
CreateProcess(NULL, command_line, NULL, NULL, TRUE, 0, NULL, NULL, &startup, &process_info); // note that bInheritHandles is set to TRUE (1)
CloseHandle(process_info.hThread);
CloseHandle(process_info.hProcess);
CloseHandle(new_channel);
...
This is the (simplified) code of the CPE:
...
int pipeFd = atoi(argv[1]);
char *outBuf = ... // the message to be sent to the RAS as this is waiting for a (synchronous) response
int size = ... // length of this message
int cnt = send(pipeFd, outBuf, size, 0);
...
This all has been working like a charm for years. Now we would like to replace the CPE by a program written in C#, let's call it CPE.NET. The WS should stay as it is (written in C).
This is the (simplified) code of the CPE.NET:
class Program {
[DllImport("ws2_32.dll")]
extern static int send([In] IntPtr socketHandle, [In] IntPtr buffer, [In] int count, [In] SocketFlags socketFlags);
public static int Send(IntPtr socketHandle, byte[] buffer, int offset, int size, SocketFlags socketFlags) {
unsafe {
fixed (byte* pData = buffer) {
return send(socketHandle, new IntPtr(pData + offset), size, socketFlags);
}
}
}
static void Main(string[] args) {
int socketHandle;
if (!int.TryParse(args[1], out socketHandle))
return;
byte[] data = new byte[] { ... }; // the message to be sent to the RAS as this is waiting for a (synchronous) response
int retSendWithDotNet = Send(new IntPtr(socketHandle), data, 0, data.Length, 0);
...
The issue now is that retSendWithDotNet is always -1. Any idea why this is this way?
Thanks, Michael
"You need to call WSAGetLastError to get more information. My guess is that sockets are not initialized (see WSAStartup)."
Simple, but effective. Calling WSAStartup() did the trick. Thank you very much.