source: trunk/src/kernel32/hmmailslot.cpp@ 5655

Last change on this file since 5655 was 5587, checked in by sandervl, 24 years ago

added mailslot implemenation, named pipe fixes + FreeLibraryAndExitThread

File size: 19.3 KB
Line 
1/*
2 * Win32 mailslot APIs
3 *
4 * Copyright 2001 Sander van Leeuwen (sandervl@xs4all.nl)
5 *
6 * This is not a complete implementation. Just a partial implementation
7 * using named pipes.
8 *
9 * TODO: Doesn't work for remote mailslots (on other machines)
10 * TODO: Writing to multiple mailslot servers doesn't work (\\*\mailslot\xxx)
11 *
12 * Project Odin Software License can be found in LICENSE.TXT
13 *
14 */
15
16#include <os2win.h>
17#include <string.h>
18#include "HandleManager.h"
19#include "HMMailslot.h"
20
21#define DBG_LOCALLOG DBG_hmmailslot
22#include "dbglocal.h"
23
24HMMailSlotInfo::HMMailSlotInfo(LPCSTR lpszName, HANDLE hPipe, DWORD nMaxMessageSize,
25 DWORD lReadTimeout, BOOL fServer,
26 LPSECURITY_ATTRIBUTES lpSecurityAttributes)
27{
28 this->lpszName = (LPSTR)malloc(strlen(lpszName)+1);
29 if(!this->lpszName) {
30 DebugInt3();
31 }
32 strcpy(this->lpszName, lpszName);
33 this->lpSecurityAttributes = lpSecurityAttributes;
34 lpMessage = NULL;
35 dwMessageCount = 0;
36
37 this->nMaxMessageSize = nMaxMessageSize;
38 this->lReadTimeout = lReadTimeout;
39 this->fServer = fServer;
40 this->hPipe = hPipe;
41}
42
43HMMailSlotInfo::~HMMailSlotInfo()
44{
45 if(lpszName) free(lpszName);
46 if(hPipe) CloseHandle(hPipe);
47}
48
49
50HMMailslotClass::HMMailslotClass(LPCSTR lpDeviceName) : HMDeviceHandler(lpDeviceName)
51{
52 HMDeviceRegisterEx("\\\\.\\MAILSLOT", this, NULL);
53}
54
55/*****************************************************************************
56 * Name : HMMailslotClass::FindDevice
57 * Purpose : Checks if lpDeviceName belongs to this device class
58 * Parameters: LPCSTR lpClassDevName
59 * LPCSTR lpDeviceName
60 * int namelength
61 * Variables :
62 * Result : checks if name is for a drive of physical disk
63 * Remark :
64 * Status :
65 *
66 * Author : SvL
67 *****************************************************************************/
68BOOL HMMailslotClass::FindDevice(LPCSTR lpClassDevName, LPCSTR lpDeviceName, int namelength)
69{
70 //\\*\mailslot\ length 13
71 if((lstrncmpiA(lpDeviceName, "\\\\*\\mailslot\\", 13) == 0))
72 {
73 return TRUE;
74 }
75 if((lstrncmpiA(lpDeviceName, "\\\\.\\mailslot\\", 13) == 0))
76 {
77 return TRUE;
78 }
79 return FALSE;
80}
81
82/*****************************************************************************
83 * Name : HANDLE WIN32API CreateMailslotA
84 * Purpose : The CreateMailslot function creates a mailslot with the specified
85 * name and returns a handle that a mailslot server can use to
86 * perform operations on the mailslot. The mailslot is local to the
87 * computer that creates it. An error occurs if a mailslot with
88 * the specified name already exists.
89 * Parameters: LPCSTR lpName pointer to string for mailslot name
90 * DWORD nMaxMessageSize maximum message size
91 * DWORD lReadTimeout milliseconds before read time-out
92 * LPSECURITY_ATTRIBUTES lpSecurityAttributes pointer to security structure
93 * Variables :
94 * Result : If the function succeeds, the return value is a handle to
95 * the mailslot, for use in server mailslot operations.
96 * If the function fails, the return value is INVALID_HANDLE_VALUE.
97 * Remark :
98 * Status : UNTESTED STUB
99 *
100 * Author : SvL
101 *****************************************************************************/
102
103BOOL HMMailslotClass::CreateMailslotA(PHMHANDLEDATA pHMHandleData,
104 LPCSTR lpName, DWORD nMaxMessageSize,
105 DWORD lReadTimeout,
106 LPSECURITY_ATTRIBUTES lpSecurityAttributes)
107{
108 HMMailSlotInfo *mailslot;
109 HANDLE hPipe;
110
111 dprintf(("KERNEL32: CreateMailslotA(%s,%08x,%08x,%08x) partially implemented",
112 lpName, nMaxMessageSize, lReadTimeout, lpSecurityAttributes));
113
114
115 pHMHandleData->dwUserData = 0;
116
117 if(lpName == NULL) {
118 SetLastError(ERROR_PATH_NOT_FOUND);
119 return FALSE;
120 }
121
122 char *pipename = (char *)alloca(strlen(lpName)+16);
123 if(pipename == NULL) {
124 DebugInt3();
125 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
126 return FALSE;
127 }
128 strcpy(pipename, "\\\\.\\pipe\\");
129 strcat(pipename, lpName);
130 //TODO: lookup name and fail if exists
131 hPipe = CreateNamedPipeA(pipename, PIPE_ACCESS_INBOUND,
132 PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE | PIPE_NOWAIT,
133 PIPE_UNLIMITED_INSTANCES, MAILSLOT_SIZE,
134 (nMaxMessageSize) ? nMaxMessageSize : MAILSLOT_SIZE,
135 lReadTimeout, lpSecurityAttributes);
136
137 if(hPipe == INVALID_HANDLE_VALUE) {
138 dprintf(("CreateMailslotA: unable to create pipe %s", pipename));
139 return FALSE;
140 }
141 ::ConnectNamedPipe(hPipe, NULL);
142 SetLastError(0);
143 if(lReadTimeout == MAILSLOT_WAIT_FOREVER) {
144 DWORD mode = PIPE_READMODE_MESSAGE | PIPE_WAIT;
145 ::SetNamedPipeHandleState(hPipe, &mode, NULL, NULL);
146 }
147 else
148 if(lReadTimeout != 0) {
149 dprintf(("WARNING: timeout %x not supported", lReadTimeout));
150 }
151 mailslot = new HMMailSlotInfo(lpName, hPipe, nMaxMessageSize, lReadTimeout, TRUE, lpSecurityAttributes);
152 if(mailslot == NULL) {
153 DebugInt3();
154 return FALSE;
155 }
156 pHMHandleData->dwUserData = (DWORD)mailslot;
157 return TRUE;
158}
159
160/*****************************************************************************
161 * Name : DWORD HMMailslotClass::CreateFile
162 * Purpose : this is called from the handle manager if a CreateFile() is
163 * performed on a handle
164 * Parameters: LPCSTR lpFileName name of the file / device
165 * PHMHANDLEDATA pHMHandleData data of the NEW handle
166 * PVOID lpSecurityAttributes ignored
167 * PHMHANDLEDATA pHMHandleDataTemplate data of the template handle
168 * Variables :
169 * Result :
170 * Remark :
171 * Status : NO_ERROR - API succeeded
172 * other - what is to be set in SetLastError
173 *
174 * Author : SvL
175 *****************************************************************************/
176
177DWORD HMMailslotClass::CreateFile (LPCSTR lpFileName,
178 PHMHANDLEDATA pHMHandleData,
179 PVOID lpSecurityAttributes,
180 PHMHANDLEDATA pHMHandleDataTemplate)
181{
182 HMMailSlotInfo *mailslot;
183 HANDLE hPipe;
184
185 dprintf(("HMMailslotClass::CreateFile: %s", lpFileName));
186
187 pHMHandleData->dwUserData = 0;
188
189 char *pipename = (char *)alloca(strlen(lpFileName)+16);
190 if(pipename == NULL) {
191 DebugInt3();
192 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
193 return FALSE;
194 }
195 strcpy(pipename, "\\\\.\\pipe\\");
196 strcat(pipename, lpFileName);
197
198tryagain:
199 hPipe = ::CreateFileA(pipename, pHMHandleData->dwAccess,
200 pHMHandleData->dwShare, (LPSECURITY_ATTRIBUTES)lpSecurityAttributes,
201 pHMHandleData->dwCreation,
202 pHMHandleData->dwFlags, 0);
203
204 if(hPipe == INVALID_HANDLE_VALUE) {
205 if(pipename[11] == '*') {
206 dprintf(("pipename with asterix not supported; connect only to one mailslot"));
207 pipename[11] = '.';
208 goto tryagain;
209 }
210 dprintf(("CreateMailslotA: unable to create pipe %s", pipename));
211 return GetLastError();
212 }
213 //todo: lookup name and fail if exists
214 mailslot = new HMMailSlotInfo(lpFileName, hPipe, -1, 0, FALSE, (LPSECURITY_ATTRIBUTES)lpSecurityAttributes);
215 if(mailslot == NULL) {
216 DebugInt3();
217 return ERROR_NOT_ENOUGH_MEMORY;
218 }
219 pHMHandleData->dwUserData = (DWORD)mailslot;
220 return NO_ERROR;
221}
222/*****************************************************************************
223 * Name : DWORD HMMailslotClass::CloseHandle
224 * Purpose : close the handle
225 * Parameters: PHMHANDLEDATA pHMHandleData
226 * Variables :
227 * Result : API returncode
228 * Remark :
229 * Status :
230 *
231 * Author : SvL
232 *****************************************************************************/
233
234BOOL HMMailslotClass::CloseHandle(PHMHANDLEDATA pHMHandleData)
235{
236 HMMailSlotInfo *mailslot = (HMMailSlotInfo *)pHMHandleData->dwUserData;
237
238 dprintf(("KERNEL32: HMMailslotClass::CloseHandle(%08x)", pHMHandleData->hHMHandle));
239
240 if(mailslot) {
241 delete mailslot;
242 }
243 return TRUE;
244}
245
246/*****************************************************************************
247 * Name : BOOL GetMailslotInfo
248 * Purpose : The GetMailslotInfo function retrieves information about the
249 * specified mailslot.
250 * Parameters: HANDLE hMailslot mailslot handle
251 * LPDWORD lpMaxMessageSize address of maximum message size
252 * LPDWORD lpNextSize address of size of next message
253 * LPDWORD lpMessageCount address of number of messages
254 * LPDWORD lpReadTimeout address of read time-out
255 * Variables :
256 * Result : TRUE / FALSE
257 * Remark :
258 * Status : UNTESTED STUB
259 *
260 * Author : SvL
261 *****************************************************************************/
262
263BOOL HMMailslotClass::GetMailslotInfo(PHMHANDLEDATA pHMHandleData,
264 LPDWORD lpMaxMessageSize,
265 LPDWORD lpNextSize,
266 LPDWORD lpMessageCount,
267 LPDWORD lpReadTimeout)
268{
269 DWORD bytesread, bytesavail, msgsize;
270 HMMailSlotInfo *mailslot = (HMMailSlotInfo *)pHMHandleData->dwUserData;
271
272 dprintf(("KERNEL32: GetMailslotInfo(%08xh,%08xh,%08xh,%08xh,%08xh) partially implemented",
273 pHMHandleData->hHMHandle,
274 lpMaxMessageSize,
275 lpNextSize,
276 lpMessageCount,
277 lpReadTimeout));
278
279 if(mailslot == NULL) {
280 DebugInt3();
281 return FALSE;
282 }
283 if(mailslot->fServer == FALSE) {
284 dprintf(("GetMailslotInfo not allowed with client handle"));
285 SetLastError(ERROR_INVALID_FUNCTION);
286 return FALSE;
287 }
288 if(::PeekNamedPipe(mailslot->hPipe, NULL, 0, &bytesread, &bytesavail, &msgsize) == FALSE) {
289 dprintf(("ERROR: GetMailslotInfo: PeekNamedPipe failed!"));
290 return FALSE;
291 }
292 if(lpMaxMessageSize) *lpMaxMessageSize = mailslot->nMaxMessageSize;
293 if(lpReadTimeout) *lpReadTimeout = mailslot->lReadTimeout;
294
295 //TODO: get correct number of messages!
296 if(bytesavail) {
297 if(lpNextSize) *lpNextSize = msgsize;
298 if(lpMessageCount) *lpMessageCount = 1;
299 }
300 else {
301 if(lpNextSize) *lpNextSize = 0;
302 if(lpMessageCount) *lpMessageCount = 0;
303 }
304 return TRUE;
305}
306
307/*****************************************************************************
308 * Name : BOOL SetMailslotInfo
309 * Purpose : The SetMailslotInfo function sets the time-out value used by the
310 * specified mailslot for a read operation.
311 * Parameters: HANDLE hObject handle to a mailslot object
312 * DWORD dwReadTimeout read time-out
313 * Variables :
314 * Result : TRUE / FALSE
315 * Remark :
316 * Status : UNTESTED STUB
317 *
318 * Author : SvL
319 *****************************************************************************/
320BOOL HMMailslotClass::SetMailslotInfo(PHMHANDLEDATA pHMHandleData,
321 DWORD dwReadTimeout)
322{
323 HMMailSlotInfo *mailslot = (HMMailSlotInfo *)pHMHandleData->dwUserData;
324
325 dprintf(("KERNEL32: SetMailslotInfo(%08xh,%08xh) partially implemented",
326 pHMHandleData->hHMHandle, dwReadTimeout));
327
328 if(mailslot == NULL) {
329 DebugInt3();
330 return FALSE;
331 }
332 if(mailslot->fServer == FALSE) {
333 dprintf(("SetMailslotInfo not allowed with client handle"));
334 SetLastError(ERROR_INVALID_FUNCTION);
335 return FALSE;
336 }
337 mailslot->lReadTimeout = dwReadTimeout;
338 return(FALSE);
339}
340
341/*****************************************************************************
342 * Name : BOOL HMMailslotClass::ReadFile
343 * Purpose : read data from handle / device
344 * Parameters: PHMHANDLEDATA pHMHandleData,
345 * LPCVOID lpBuffer,
346 * DWORD nNumberOfBytesToRead,
347 * LPDWORD lpNumberOfBytesRead,
348 * LPOVERLAPPED lpOverlapped
349 * Variables :
350 * Result : Boolean
351 * Remark :
352 * Status :
353 *
354 * Author : Patrick Haller [Wed, 1998/02/11 20:44]
355 *****************************************************************************/
356
357BOOL HMMailslotClass::ReadFile(PHMHANDLEDATA pHMHandleData,
358 LPCVOID lpBuffer,
359 DWORD nNumberOfBytesToRead,
360 LPDWORD lpNumberOfBytesRead,
361 LPOVERLAPPED lpOverlapped)
362{
363 HMMailSlotInfo *mailslot = (HMMailSlotInfo *)pHMHandleData->dwUserData;
364 dprintf(("KERNEL32: HMMailslotClass::ReadFile %s(%08x,%08x,%08x,%08x,%08x)",
365 lpHMDeviceName, pHMHandleData, lpBuffer, nNumberOfBytesToRead,
366 lpNumberOfBytesRead, lpOverlapped));
367
368 if(lpNumberOfBytesRead)
369 *lpNumberOfBytesRead = 0;
370
371 if(mailslot == NULL) {
372 DebugInt3();
373 return FALSE;
374 }
375 if(mailslot->fServer == FALSE) {
376 dprintf(("ReadFile not allowed with client handle"));
377 SetLastError(ERROR_INVALID_FUNCTION); //TODO: right error?
378 return FALSE;
379 }
380 return ::ReadFile(mailslot->hPipe, (LPVOID)lpBuffer, nNumberOfBytesToRead,
381 lpNumberOfBytesRead, lpOverlapped);
382}
383
384/*****************************************************************************
385 * Name : BOOL ReadFileEx
386 * Purpose : The ReadFileEx function reads data from a file asynchronously.
387 * It is designed solely for asynchronous operation, unlike the
388 * ReadFile function, which is designed for both synchronous and
389 * asynchronous operation. ReadFileEx lets an application perform
390 * other processing during a file read operation.
391 * The ReadFileEx function reports its completion status asynchronously,
392 * calling a specified completion routine when reading is completed
393 * and the calling thread is in an alertable wait state.
394 * Parameters: HANDLE hFile handle of file to read
395 * LPVOID lpBuffer address of buffer
396 * DWORD nNumberOfBytesToRead number of bytes to read
397 * LPOVERLAPPED lpOverlapped address of offset
398 * LPOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine address of completion routine
399 * Variables :
400 * Result : TRUE / FALSE
401 * Remark :
402 * Status : UNTESTED STUB
403 *
404 * Author : Patrick Haller [Mon, 1998/06/15 08:00]
405 *****************************************************************************/
406BOOL HMMailslotClass::ReadFileEx(PHMHANDLEDATA pHMHandleData,
407 LPVOID lpBuffer,
408 DWORD nNumberOfBytesToRead,
409 LPOVERLAPPED lpOverlapped,
410 LPOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine)
411{
412 HMMailSlotInfo *mailslot = (HMMailSlotInfo *)pHMHandleData->dwUserData;
413
414 dprintf(("HMMailslotClass::ReadFileEx(%08xh,%08xh,%08xh,%08xh,%08xh)", pHMHandleData->hHMHandle,
415 lpBuffer, nNumberOfBytesToRead, lpOverlapped, lpCompletionRoutine));
416
417 if(mailslot == NULL) {
418 DebugInt3();
419 return FALSE;
420 }
421 if(mailslot->fServer == FALSE) {
422 dprintf(("ReadFile not allowed with client handle"));
423 SetLastError(ERROR_INVALID_FUNCTION); //TODO: right error?
424 return FALSE;
425 }
426 return ::ReadFileEx(mailslot->hPipe, lpBuffer, nNumberOfBytesToRead, lpOverlapped, lpCompletionRoutine);
427}
428
429
430/*****************************************************************************
431 * Name : BOOL HMMailslotClass::WriteFile
432 * Purpose : write data to handle / device
433 * Parameters: PHMHANDLEDATA pHMHandleData,
434 * LPCVOID lpBuffer,
435 * DWORD nNumberOfBytesToWrite,
436 * LPDWORD lpNumberOfBytesWritten,
437 * LPOVERLAPPED lpOverlapped
438 * Variables :
439 * Result : Boolean
440 * Remark :
441 * Status :
442 *
443 * Author : Patrick Haller [Wed, 1998/02/11 20:44]
444 *****************************************************************************/
445
446BOOL HMMailslotClass::WriteFile(PHMHANDLEDATA pHMHandleData,
447 LPCVOID lpBuffer,
448 DWORD nNumberOfBytesToWrite,
449 LPDWORD lpNumberOfBytesWritten,
450 LPOVERLAPPED lpOverlapped)
451{
452 HMMailSlotInfo *mailslot = (HMMailSlotInfo *)pHMHandleData->dwUserData;
453
454 dprintf(("KERNEL32: HMMailslotClass::WriteFile %s(%08x,%08x,%08x,%08x,%08x)",
455 lpHMDeviceName, pHMHandleData, lpBuffer, nNumberOfBytesToWrite,
456 lpNumberOfBytesWritten, lpOverlapped));
457
458 if(lpNumberOfBytesWritten)
459 *lpNumberOfBytesWritten = 0;
460
461 if(mailslot == NULL) {
462 DebugInt3();
463 return FALSE;
464 }
465 if(mailslot->fServer == TRUE) {
466 dprintf(("ReadFile not allowed with server handle"));
467 SetLastError(ERROR_INVALID_FUNCTION); //TODO: right error?
468 return FALSE;
469 }
470
471 return ::WriteFile(mailslot->hPipe, lpBuffer, nNumberOfBytesToWrite,
472 lpNumberOfBytesWritten, lpOverlapped);
473}
474
475/*****************************************************************************
476 * Name : BOOL WriteFileEx
477 * Purpose : The WriteFileEx function writes data to a file. It is designed
478 * solely for asynchronous operation, unlike WriteFile, which is
479 * designed for both synchronous and asynchronous operation.
480 * WriteFileEx reports its completion status asynchronously,
481 * calling a specified completion routine when writing is completed
482 * and the calling thread is in an alertable wait state.
483 * Parameters: HANDLE hFile handle of file to write
484 * LPVOID lpBuffer address of buffer
485 * DWORD nNumberOfBytesToRead number of bytes to write
486 * LPOVERLAPPED lpOverlapped address of offset
487 * LPOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine address of completion routine
488 * Variables :
489 * Result : TRUE / FALSE
490 * Remark :
491 * Status : UNTESTED STUB
492 *
493 * Author : Patrick Haller [Mon, 1998/06/15 08:00]
494 *****************************************************************************/
495
496BOOL HMMailslotClass::WriteFileEx(PHMHANDLEDATA pHMHandleData,
497 LPVOID lpBuffer,
498 DWORD nNumberOfBytesToWrite,
499 LPOVERLAPPED lpOverlapped,
500 LPOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine)
501{
502 HMMailSlotInfo *mailslot = (HMMailSlotInfo *)pHMHandleData->dwUserData;
503
504 dprintf(("HMMailslotClass::WriteFileEx(%08xh,%08xh,%08xh,%08xh,%08xh)",
505 pHMHandleData->hHMHandle, lpBuffer, nNumberOfBytesToWrite,
506 lpOverlapped,lpCompletionRoutine));
507
508 if(mailslot == NULL) {
509 DebugInt3();
510 return FALSE;
511 }
512 if(mailslot->fServer == TRUE) {
513 dprintf(("ReadFile not allowed with server handle"));
514 SetLastError(ERROR_INVALID_FUNCTION); //TODO: right error?
515 return FALSE;
516 }
517 return ::WriteFileEx(mailslot->hPipe, lpBuffer, nNumberOfBytesToWrite,lpOverlapped,lpCompletionRoutine);
518}
Note: See TracBrowser for help on using the repository browser.