5b206c2a90e94973b8b32c8a5facf1a00f30a322
[reactos.git] / reactos / lib / msafd / misc / dllmain.c
1 /*
2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS Ancillary Function Driver DLL
4 * FILE: misc/dllmain.c
5 * PURPOSE: DLL entry point
6 * PROGRAMMERS: Casper S. Hornstrup (chorns@users.sourceforge.net)
7 * REVISIONS:
8 * CSH 01/09-2000 Created
9 */
10 #include <msafd.h>
11 #include <helpers.h>
12
13 #ifdef DBG
14
15 /* See debug.h for debug/trace constants */
16 DWORD DebugTraceLevel = MIN_TRACE;
17 //DWORD DebugTraceLevel = DEBUG_ULTRA;
18
19 #endif /* DBG */
20
21 /* To make the linker happy */
22 VOID STDCALL KeBugCheck (ULONG BugCheckCode) {}
23
24
25 HANDLE GlobalHeap;
26 WSPUPCALLTABLE Upcalls;
27 LPWPUCOMPLETEOVERLAPPEDREQUEST lpWPUCompleteOverlappedRequest;
28 CRITICAL_SECTION InitCriticalSection;
29 DWORD StartupCount = 0;
30 HANDLE CommandChannel;
31
32
33 NTSTATUS OpenSocket(
34 SOCKET *Socket,
35 INT AddressFamily,
36 INT SocketType,
37 INT Protocol,
38 PVOID HelperContext,
39 DWORD NotificationEvents,
40 PUNICODE_STRING TdiDeviceName)
41 /*
42 * FUNCTION: Opens a socket
43 * ARGUMENTS:
44 * Socket = Address of buffer to place socket descriptor
45 * AddressFamily = Address family
46 * SocketType = Type of socket
47 * Protocol = Protocol type
48 * HelperContext = Pointer to context information for helper DLL
49 * NotificationEvents = Events for which helper DLL is to be notified
50 * TdiDeviceName = Pointer to name of TDI device to use
51 * RETURNS:
52 * Status of operation
53 */
54 {
55 OBJECT_ATTRIBUTES ObjectAttributes;
56 PAFD_SOCKET_INFORMATION SocketInfo;
57 PFILE_FULL_EA_INFORMATION EaInfo;
58 UNICODE_STRING DeviceName;
59 IO_STATUS_BLOCK Iosb;
60 HANDLE FileHandle;
61 NTSTATUS Status;
62 ULONG EaLength;
63 ULONG EaShort;
64
65 AFD_DbgPrint(MAX_TRACE, ("Socket (0x%X) TdiDeviceName (%wZ)\n",
66 Socket, TdiDeviceName));
67
68 AFD_DbgPrint(MAX_TRACE, ("Socket2 (0x%X) TdiDeviceName (%S)\n",
69 Socket, TdiDeviceName->Buffer));
70
71 EaShort = sizeof(FILE_FULL_EA_INFORMATION) +
72 AFD_SOCKET_LENGTH +
73 sizeof(AFD_SOCKET_INFORMATION);
74
75 EaLength = EaShort + TdiDeviceName->Length + sizeof(WCHAR);
76
77 EaInfo = (PFILE_FULL_EA_INFORMATION)HeapAlloc(GlobalHeap, 0, EaLength);
78 if (!EaInfo) {
79 return STATUS_INSUFFICIENT_RESOURCES;
80 }
81
82 RtlZeroMemory(EaInfo, EaLength);
83 EaInfo->EaNameLength = AFD_SOCKET_LENGTH;
84 RtlCopyMemory(EaInfo->EaName,
85 AfdSocket,
86 AFD_SOCKET_LENGTH);
87 EaInfo->EaValueLength = sizeof(AFD_SOCKET_INFORMATION);
88
89 SocketInfo = (PAFD_SOCKET_INFORMATION)(EaInfo->EaName + AFD_SOCKET_LENGTH);
90 SocketInfo->CommandChannel = FALSE;
91 SocketInfo->AddressFamily = AddressFamily;
92 SocketInfo->SocketType = SocketType;
93 SocketInfo->Protocol = Protocol;
94 SocketInfo->HelperContext = HelperContext;
95 SocketInfo->NotificationEvents = NotificationEvents;
96 /* Zeroed above so initialized to a wildcard address if a raw socket */
97 SocketInfo->Name.sa_family = AddressFamily;
98
99 /* Store TDI device name last in buffer */
100 SocketInfo->TdiDeviceName.Buffer = (PWCHAR)(EaInfo + EaShort);
101 SocketInfo->TdiDeviceName.MaximumLength = TdiDeviceName->Length + sizeof(WCHAR);
102 RtlCopyUnicodeString(&SocketInfo->TdiDeviceName, TdiDeviceName);
103
104 AFD_DbgPrint(MAX_TRACE, ("EaInfo at (0x%X) EaLength is (%d).\n", (UINT)EaInfo, (INT)EaLength));
105
106 RtlInitUnicodeString(&DeviceName, L"\\Device\\Afd");
107 InitializeObjectAttributes(
108 &ObjectAttributes,
109 &DeviceName,
110 0,
111 NULL,
112 NULL);
113
114 Status = NtCreateFile(
115 &FileHandle,
116 FILE_GENERIC_READ | FILE_GENERIC_WRITE,
117 &ObjectAttributes,
118 &Iosb,
119 NULL,
120 0,
121 0,
122 FILE_OPEN,
123 FILE_SYNCHRONOUS_IO_ALERT,
124 EaInfo,
125 EaLength);
126
127 HeapFree(GlobalHeap, 0, EaInfo);
128
129 if (!NT_SUCCESS(Status)) {
130 AFD_DbgPrint(MIN_TRACE, ("Error opening device (Status 0x%X).\n",
131 (UINT)Status));
132 return STATUS_INSUFFICIENT_RESOURCES;
133 }
134
135 *Socket = (SOCKET)FileHandle;
136
137 return STATUS_SUCCESS;
138 }
139
140
141 SOCKET
142 WSPAPI
143 WSPSocket(
144 IN INT af,
145 IN INT type,
146 IN INT protocol,
147 IN LPWSAPROTOCOL_INFOW lpProtocolInfo,
148 IN GROUP g,
149 IN DWORD dwFlags,
150 OUT LPINT lpErrno)
151 /*
152 * FUNCTION: Creates a new socket
153 * ARGUMENTS:
154 * af = Address family
155 * type = Socket type
156 * protocol = Protocol type
157 * lpProtocolInfo = Pointer to protocol information
158 * g = Reserved
159 * dwFlags = Socket flags
160 * lpErrno = Address of buffer for error information
161 * RETURNS:
162 * Created socket, or INVALID_SOCKET if it could not be created
163 */
164 {
165 WSAPROTOCOL_INFOW ProtocolInfo;
166 UNICODE_STRING TdiDeviceName;
167 DWORD NotificationEvents;
168 PWSHELPER_DLL HelperDLL;
169 PVOID HelperContext;
170 INT AddressFamily;
171 NTSTATUS NtStatus;
172 INT SocketType;
173 SOCKET Socket2;
174 SOCKET Socket;
175 INT Protocol;
176 INT Status;
177
178 AFD_DbgPrint(MAX_TRACE, ("af (%d) type (%d) protocol (%d).\n",
179 af, type, protocol));
180
181 if (!lpProtocolInfo) {
182 lpProtocolInfo = &ProtocolInfo;
183 ZeroMemory(&ProtocolInfo, sizeof(WSAPROTOCOL_INFOW));
184
185 ProtocolInfo.iAddressFamily = af;
186 ProtocolInfo.iSocketType = type;
187 ProtocolInfo.iProtocol = protocol;
188 }
189
190 HelperDLL = LocateHelperDLL(lpProtocolInfo);
191 if (!HelperDLL) {
192 *lpErrno = WSAEAFNOSUPPORT;
193 return INVALID_SOCKET;
194 }
195
196 AddressFamily = lpProtocolInfo->iAddressFamily;
197 SocketType = lpProtocolInfo->iSocketType;
198 Protocol = lpProtocolInfo->iProtocol;
199
200 Status = HelperDLL->EntryTable.lpWSHOpenSocket2(
201 &AddressFamily,
202 &SocketType,
203 &Protocol,
204 0,
205 0,
206 &TdiDeviceName,
207 &HelperContext,
208 &NotificationEvents);
209 if (Status != NO_ERROR) {
210 *lpErrno = Status;
211 return INVALID_SOCKET;
212 }
213
214 NtStatus = OpenSocket(&Socket,
215 AddressFamily,
216 SocketType,
217 Protocol,
218 HelperContext,
219 NotificationEvents,
220 &TdiDeviceName);
221
222 RtlFreeUnicodeString(&TdiDeviceName);
223 if (!NT_SUCCESS(NtStatus)) {
224 *lpErrno = RtlNtStatusToDosError(Status);
225 return INVALID_SOCKET;
226 }
227
228 /* FIXME: Assumes catalog entry id to be 1 */
229 Socket2 = Upcalls.lpWPUModifyIFSHandle(1, Socket, lpErrno);
230
231 if (Socket2 == INVALID_SOCKET) {
232 /* FIXME: Cleanup */
233 AFD_DbgPrint(MIN_TRACE, ("FIXME: Cleanup.\n"));
234 return INVALID_SOCKET;
235 }
236
237 *lpErrno = NO_ERROR;
238
239 AFD_DbgPrint(MID_TRACE, ("Returning socket descriptor (0x%X).\n", Socket2));
240
241 return Socket2;
242 }
243
244
245 INT
246 WSPAPI
247 WSPCloseSocket(
248 IN SOCKET s,
249 OUT LPINT lpErrno)
250 /*
251 * FUNCTION: Closes an open socket
252 * ARGUMENTS:
253 * s = Socket descriptor
254 * lpErrno = Address of buffer for error information
255 * RETURNS:
256 * NO_ERROR, or SOCKET_ERROR if the socket could not be closed
257 */
258 {
259 NTSTATUS Status;
260
261 AFD_DbgPrint(MAX_TRACE, ("s (0x%X).\n", s));
262
263 Status = NtClose((HANDLE)s);
264
265 if (NT_SUCCESS(Status)) {
266 *lpErrno = NO_ERROR;
267 return NO_ERROR;
268 }
269
270 *lpErrno = WSAENOTSOCK;
271 return SOCKET_ERROR;
272 }
273
274
275 INT
276 WSPAPI
277 WSPBind(
278 IN SOCKET s,
279 IN CONST LPSOCKADDR name,
280 IN INT namelen,
281 OUT LPINT lpErrno)
282 /*
283 * FUNCTION: Associates a local address with a socket
284 * ARGUMENTS:
285 * s = Socket descriptor
286 * name = Pointer to local address
287 * namelen = Length of name
288 * lpErrno = Address of buffer for error information
289 * RETURNS:
290 * 0, or SOCKET_ERROR if the socket could not be bound
291 */
292 {
293 AFD_DbgPrint(MAX_TRACE, ("s (0x%X) name (0x%X) namelen (%d).\n", s, name, namelen));
294
295 #if 0
296 FILE_REQUEST_BIND Request;
297 FILE_REPLY_BIND Reply;
298 IO_STATUS_BLOCK Iosb;
299 NTSTATUS Status;
300
301 RtlCopyMemory(&Request.Name, name, sizeof(SOCKADDR));
302
303 Status = NtDeviceIoControlFile(
304 (HANDLE)s,
305 NULL,
306 NULL,
307 NULL,
308 &Iosb,
309 IOCTL_AFD_BIND,
310 &Request,
311 sizeof(FILE_REQUEST_BIND),
312 &Reply,
313 sizeof(FILE_REPLY_BIND));
314
315 if (Status == STATUS_PENDING) {
316 if (!NT_SUCCESS(NtWaitForSingleObject((HANDLE)s, FALSE, NULL))) {
317 /* FIXME: What error code should be returned? */
318 *lpErrno = WSAENOBUFS;
319 return SOCKET_ERROR;
320 }
321 }
322
323 if (!NT_SUCCESS(Status)) {
324 *lpErrno = WSAENOBUFS;
325 return SOCKET_ERROR;
326 }
327 #endif
328 return 0;
329 }
330
331
332 INT
333 WSPAPI
334 WSPSelect(
335 IN INT nfds,
336 IN OUT LPFD_SET readfds,
337 IN OUT LPFD_SET writefds,
338 IN OUT LPFD_SET exceptfds,
339 IN CONST LPTIMEVAL timeout,
340 OUT LPINT lpErrno)
341 /*
342 * FUNCTION: Returns status of one or more sockets
343 * ARGUMENTS:
344 * nfds = Always ignored
345 * readfds = Pointer to socket set to be checked for readability (optional)
346 * writefds = Pointer to socket set to be checked for writability (optional)
347 * exceptfds = Pointer to socket set to be checked for errors (optional)
348 * timeout = Pointer to a TIMEVAL structure indicating maximum wait time
349 * (NULL means wait forever)
350 * lpErrno = Address of buffer for error information
351 * RETURNS:
352 * Number of ready socket descriptors, or SOCKET_ERROR if an error ocurred
353 */
354 {
355 PFILE_REQUEST_SELECT Request;
356 FILE_REPLY_SELECT Reply;
357 IO_STATUS_BLOCK Iosb;
358 NTSTATUS Status;
359 DWORD Size;
360 DWORD ReadSize;
361 DWORD WriteSize;
362 DWORD ExceptSize;
363 PVOID Current;
364
365 AFD_DbgPrint(MAX_TRACE, ("readfds (0x%X) writefds (0x%X) exceptfds (0x%X).\n",
366 readfds, writefds, exceptfds));
367 #if 0
368 /* FIXME: For now, all reads are timed out immediately */
369 if (readfds != NULL) {
370 AFD_DbgPrint(MID_TRACE, ("Timing out read query.\n"));
371 *lpErrno = WSAETIMEDOUT;
372 return SOCKET_ERROR;
373 }
374
375 /* FIXME: For now, always allow write */
376 if (writefds != NULL) {
377 AFD_DbgPrint(MID_TRACE, ("Setting one socket writeable.\n"));
378 *lpErrno = NO_ERROR;
379 return 1;
380 }
381 #endif
382
383 ReadSize = 0;
384 if ((readfds != NULL) && (readfds->fd_count > 0)) {
385 ReadSize = (readfds->fd_count * sizeof(SOCKET)) + sizeof(UINT);
386 }
387
388 WriteSize = 0;
389 if ((writefds != NULL) && (writefds->fd_count > 0)) {
390 WriteSize = (writefds->fd_count * sizeof(SOCKET)) + sizeof(UINT);
391 }
392
393 ExceptSize = 0;
394 if ((exceptfds != NULL) && (exceptfds->fd_count > 0)) {
395 ExceptSize = (exceptfds->fd_count * sizeof(SOCKET)) + sizeof(UINT);
396 }
397
398 Size = ReadSize + WriteSize + ExceptSize;
399
400 Request = (PFILE_REQUEST_SELECT)HeapAlloc(
401 GlobalHeap, 0, sizeof(FILE_REQUEST_SELECT) + Size);
402 if (!Request) {
403 *lpErrno = WSAENOBUFS;
404 return SOCKET_ERROR;
405 }
406
407 /* Put FD SETs after request structure */
408 Current = (Request + 1);
409
410 if (ReadSize > 0) {
411 Request->ReadFDSet = (LPFD_SET)Current;
412 Current += ReadSize;
413 RtlCopyMemory(Request->ReadFDSet, readfds, ReadSize);
414 } else {
415 Request->ReadFDSet = NULL;
416 }
417
418 if (WriteSize > 0) {
419 Request->WriteFDSet = (LPFD_SET)Current;
420 Current += WriteSize;
421 RtlCopyMemory(Request->WriteFDSet, writefds, WriteSize);
422 } else {
423 Request->WriteFDSet = NULL;
424 }
425
426 if (ExceptSize > 0) {
427 Request->ExceptFDSet = (LPFD_SET)Current;
428 RtlCopyMemory(Request->ExceptFDSet, exceptfds, ExceptSize);
429 } else {
430 Request->ExceptFDSet = NULL;
431 }
432
433 AFD_DbgPrint(MAX_TRACE, ("R1 (0x%X) W1 (0x%X).\n", Request->ReadFDSet, Request->WriteFDSet));
434
435 Status = NtDeviceIoControlFile(
436 CommandChannel,
437 NULL,
438 NULL,
439 NULL,
440 &Iosb,
441 IOCTL_AFD_SELECT,
442 Request,
443 sizeof(FILE_REQUEST_SELECT) + Size,
444 &Reply,
445 sizeof(FILE_REPLY_SELECT));
446
447 HeapFree(GlobalHeap, 0, Request);
448
449 if (Status == STATUS_PENDING) {
450 AFD_DbgPrint(MAX_TRACE, ("Waiting on transport.\n"));
451 /* FIXME: Wait only for blocking sockets */
452 Status = NtWaitForSingleObject(CommandChannel, FALSE, NULL);
453 }
454
455 if (!NT_SUCCESS(Status)) {
456 AFD_DbgPrint(MAX_TRACE, ("Status (0x%X).\n", Status));
457 *lpErrno = WSAENOBUFS;
458 return SOCKET_ERROR;
459 }
460
461 AFD_DbgPrint(MAX_TRACE, ("Select successful. Status (0x%X) Count (0x%X).\n",
462 Reply.Status, Reply.SocketCount));
463
464 *lpErrno = Reply.Status;
465
466 return Reply.SocketCount;
467 }
468
469
470 NTSTATUS OpenCommandChannel(
471 VOID)
472 /*
473 * FUNCTION: Opens a command channel to afd.sys
474 * ARGUMENTS:
475 * None
476 * RETURNS:
477 * Status of operation
478 */
479 {
480 OBJECT_ATTRIBUTES ObjectAttributes;
481 PAFD_SOCKET_INFORMATION SocketInfo;
482 PFILE_FULL_EA_INFORMATION EaInfo;
483 UNICODE_STRING DeviceName;
484 IO_STATUS_BLOCK Iosb;
485 HANDLE FileHandle;
486 NTSTATUS Status;
487 ULONG EaLength;
488 ULONG EaShort;
489
490 AFD_DbgPrint(MAX_TRACE, ("Called\n"));
491
492 EaShort = sizeof(FILE_FULL_EA_INFORMATION) +
493 AFD_SOCKET_LENGTH +
494 sizeof(AFD_SOCKET_INFORMATION);
495
496 EaLength = EaShort;
497
498 EaInfo = (PFILE_FULL_EA_INFORMATION)HeapAlloc(GlobalHeap, 0, EaLength);
499 if (!EaInfo) {
500 return STATUS_INSUFFICIENT_RESOURCES;
501 }
502
503 RtlZeroMemory(EaInfo, EaLength);
504 EaInfo->EaNameLength = AFD_SOCKET_LENGTH;
505 RtlCopyMemory(EaInfo->EaName,
506 AfdSocket,
507 AFD_SOCKET_LENGTH);
508 EaInfo->EaValueLength = sizeof(AFD_SOCKET_INFORMATION);
509
510 SocketInfo = (PAFD_SOCKET_INFORMATION)(EaInfo->EaName + AFD_SOCKET_LENGTH);
511 SocketInfo->CommandChannel = TRUE;
512
513 RtlInitUnicodeString(&DeviceName, L"\\Device\\Afd");
514 InitializeObjectAttributes(
515 &ObjectAttributes,
516 &DeviceName,
517 0,
518 NULL,
519 NULL);
520
521 Status = NtCreateFile(
522 &FileHandle,
523 FILE_GENERIC_READ | FILE_GENERIC_WRITE,
524 &ObjectAttributes,
525 &Iosb,
526 NULL,
527 0,
528 0,
529 FILE_OPEN,
530 FILE_SYNCHRONOUS_IO_ALERT,
531 EaInfo,
532 EaLength);
533
534 if (!NT_SUCCESS(Status)) {
535 AFD_DbgPrint(MIN_TRACE, ("Error opening device (Status 0x%X).\n",
536 (UINT)Status));
537 return Status;
538 }
539
540 CommandChannel = FileHandle;
541
542 return STATUS_SUCCESS;
543 }
544
545
546 NTSTATUS CloseCommandChannel(
547 VOID)
548 /*
549 * FUNCTION: Closes command channel to afd.sys
550 * ARGUMENTS:
551 * None
552 * RETURNS:
553 * Status of operation
554 */
555 {
556 AFD_DbgPrint(MAX_TRACE, ("Called.\n"));
557
558 return NtClose(CommandChannel);
559 }
560
561
562 INT
563 WSPAPI
564 WSPStartup(
565 IN WORD wVersionRequested,
566 OUT LPWSPDATA lpWSPData,
567 IN LPWSAPROTOCOL_INFOW lpProtocolInfo,
568 IN WSPUPCALLTABLE UpcallTable,
569 OUT LPWSPPROC_TABLE lpProcTable)
570 /*
571 * FUNCTION: Initialize service provider for a client
572 * ARGUMENTS:
573 * wVersionRequested = Highest WinSock SPI version that the caller can use
574 * lpWSPData = Address of WSPDATA structure to initialize
575 * lpProtocolInfo = Pointer to structure that defines the desired protocol
576 * UpcallTable = Pointer to upcall table of the WinSock DLL
577 * lpProcTable = Address of procedure table to initialize
578 * RETURNS:
579 * Status of operation
580 */
581 {
582 HMODULE hWS2_32;
583 INT Status;
584
585 AFD_DbgPrint(MAX_TRACE, ("wVersionRequested (0x%X) \n", wVersionRequested));
586
587 EnterCriticalSection(&InitCriticalSection);
588
589 Upcalls = UpcallTable;
590
591 if (StartupCount == 0) {
592 /* First time called */
593
594 Status = WSAVERNOTSUPPORTED;
595
596 Status = OpenCommandChannel();
597 if (NT_SUCCESS(Status)) {
598 hWS2_32 = GetModuleHandle(L"ws2_32.dll");
599 if (hWS2_32 != NULL) {
600 lpWPUCompleteOverlappedRequest = (LPWPUCOMPLETEOVERLAPPEDREQUEST)
601 GetProcAddress(hWS2_32, "WPUCompleteOverlappedRequest");
602 if (lpWPUCompleteOverlappedRequest != NULL) {
603 Status = NO_ERROR;
604 StartupCount++;
605 }
606 } else {
607 AFD_DbgPrint(MIN_TRACE, ("GetModuleHandle() failed for ws2_32.dll\n"));
608 }
609 } else {
610 AFD_DbgPrint(MIN_TRACE, ("Cannot open afd.sys\n"));
611 }
612 } else {
613 Status = NO_ERROR;
614 StartupCount++;
615 }
616
617 LeaveCriticalSection(&InitCriticalSection);
618
619 if (Status == NO_ERROR) {
620 lpProcTable->lpWSPAccept = WSPAccept;
621 lpProcTable->lpWSPAddressToString = WSPAddressToString;
622 lpProcTable->lpWSPAsyncSelect = WSPAsyncSelect;
623 lpProcTable->lpWSPBind = WSPBind;
624 lpProcTable->lpWSPCancelBlockingCall = WSPCancelBlockingCall;
625 lpProcTable->lpWSPCleanup = WSPCleanup;
626 lpProcTable->lpWSPCloseSocket = WSPCloseSocket;
627 lpProcTable->lpWSPConnect = WSPConnect;
628 lpProcTable->lpWSPDuplicateSocket = WSPDuplicateSocket;
629 lpProcTable->lpWSPEnumNetworkEvents = WSPEnumNetworkEvents;
630 lpProcTable->lpWSPEventSelect = WSPEventSelect;
631 lpProcTable->lpWSPGetOverlappedResult = WSPGetOverlappedResult;
632 lpProcTable->lpWSPGetPeerName = WSPGetPeerName;
633 lpProcTable->lpWSPGetSockName = WSPGetSockName;
634 lpProcTable->lpWSPGetSockOpt = WSPGetSockOpt;
635 lpProcTable->lpWSPGetQOSByName = WSPGetQOSByName;
636 lpProcTable->lpWSPIoctl = WSPIoctl;
637 lpProcTable->lpWSPJoinLeaf = WSPJoinLeaf;
638 lpProcTable->lpWSPListen = WSPListen;
639 lpProcTable->lpWSPRecv = WSPRecv;
640 lpProcTable->lpWSPRecvDisconnect = WSPRecvDisconnect;
641 lpProcTable->lpWSPRecvFrom = WSPRecvFrom;
642 lpProcTable->lpWSPSelect = WSPSelect;
643 lpProcTable->lpWSPSend = WSPSend;
644 lpProcTable->lpWSPSendDisconnect = WSPSendDisconnect;
645 lpProcTable->lpWSPSendTo = WSPSendTo;
646 lpProcTable->lpWSPSetSockOpt = WSPSetSockOpt;
647 lpProcTable->lpWSPShutdown = WSPShutdown;
648 lpProcTable->lpWSPSocket = WSPSocket;
649 lpProcTable->lpWSPStringToAddress = WSPStringToAddress;
650
651 lpWSPData->wVersion = MAKEWORD(2, 2);
652 lpWSPData->wHighVersion = MAKEWORD(2, 2);
653 }
654
655 AFD_DbgPrint(MAX_TRACE, ("Status (%d).\n", Status));
656
657 return Status;
658 }
659
660
661 INT
662 WSPAPI
663 WSPCleanup(
664 OUT LPINT lpErrno)
665 /*
666 * FUNCTION: Cleans up service provider for a client
667 * ARGUMENTS:
668 * lpErrno = Address of buffer for error information
669 * RETURNS:
670 * 0 if successful, or SOCKET_ERROR if not
671 */
672 {
673 AFD_DbgPrint(MAX_TRACE, ("\n"));
674
675 EnterCriticalSection(&InitCriticalSection);
676
677 if (StartupCount > 0) {
678 StartupCount--;
679
680 if (StartupCount == 0) {
681 AFD_DbgPrint(MAX_TRACE, ("Cleaning up msafd.dll.\n"));
682
683 CloseCommandChannel();
684 }
685 }
686
687 LeaveCriticalSection(&InitCriticalSection);
688
689 *lpErrno = NO_ERROR;
690
691 return 0;
692 }
693
694
695 BOOL
696 STDCALL
697 DllMain(HANDLE hInstDll,
698 ULONG dwReason,
699 PVOID Reserved)
700 {
701 AFD_DbgPrint(MAX_TRACE, ("DllMain of msafd.dll\n"));
702
703 switch (dwReason) {
704 case DLL_PROCESS_ATTACH:
705 /* Don't need thread attach notifications
706 so disable them to improve performance */
707 DisableThreadLibraryCalls(hInstDll);
708
709 InitializeCriticalSection(&InitCriticalSection);
710
711 GlobalHeap = GetProcessHeap();
712
713 CreateHelperDLLDatabase();
714 break;
715
716 case DLL_THREAD_ATTACH:
717 break;
718
719 case DLL_THREAD_DETACH:
720 break;
721
722 case DLL_PROCESS_DETACH:
723 DestroyHelperDLLDatabase();
724
725 DeleteCriticalSection(&InitCriticalSection);
726 break;
727 }
728
729 AFD_DbgPrint(MAX_TRACE, ("DllMain of msafd.dll (leaving)\n"));
730
731 return TRUE;
732 }
733
734 /* EOF */