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

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

preliminary work on overlapped serial comm IO

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