ReactOS 0.4.15-dev-7788-g1ad9096
memory.c
Go to the documentation of this file.
1/*
2 * COPYRIGHT: GPL - See COPYING in the top level directory
3 * PROJECT: ReactOS Virtual DOS Machine
4 * FILE: subsystems/mvdm/ntvdm/dos/dos32krnl/memory.c
5 * PURPOSE: DOS32 Memory Manager
6 * PROGRAMMERS: Aleksandar Andrejevic <theflash AT sdf DOT lonestar DOT org>
7 * Hermes Belusca-Maito (hermes.belusca@sfr.fr)
8 */
9
10/* INCLUDES *******************************************************************/
11
12#include "ntvdm.h"
13
14#define NDEBUG
15#include <debug.h>
16
17#include "emulator.h"
18
19#include "bios/umamgr.h" // HACK until we correctly call XMS services for UMBs.
20
21#include "dos.h"
22#include "dos/dem.h"
23#include "memory.h"
24#include "process.h"
25#include "himem.h"
26
27// FIXME: Should be dynamically initialized!
28#define FIRST_MCB_SEGMENT (SYSTEM_ENV_BLOCK + 0x200) // old value: 0x1000
29#define USER_MEMORY_SIZE (0x9FFE - FIRST_MCB_SEGMENT)
30
31/*
32 * Activate this line if you want run-time DOS memory arena integrity validation
33 * (useful to know whether this is an application, or DOS kernel itself, which
34 * messes up the DOS memory arena).
35 */
36// #define DBG_MEMORY
37
38/* PRIVATE VARIABLES **********************************************************/
39
40/* PUBLIC VARIABLES ***********************************************************/
41
42/* PRIVATE FUNCTIONS **********************************************************/
43
45{
46 return (Mcb->BlockType == 'M' || Mcb->BlockType == 'Z');
47}
48
49/*
50 * This is a helper function to help us detecting
51 * when the DOS arena starts to become corrupted.
52 */
53#ifdef DBG_MEMORY
55{
56 WORD PrevSegment, Segment = SysVars->FirstMcb;
57 PDOS_MCB CurrentMcb;
58
59 PrevSegment = Segment;
60 while (TRUE)
61 {
62 /* Get a pointer to the MCB */
63 CurrentMcb = SEGMENT_TO_MCB(Segment);
64
65 /* Make sure it's valid */
66 if (!ValidateMcb(CurrentMcb))
67 {
68 DPRINT1("The DOS memory arena is corrupted! (CurrentMcb = 0x%04X; PreviousMcb = 0x%04X)\n", Segment, PrevSegment);
69 return;
70 }
71
72 PrevSegment = Segment;
73
74 /* If this was the last MCB in the chain, quit */
75 if (CurrentMcb->BlockType == 'Z') return;
76
77 /* Otherwise, update the segment and continue */
78 Segment += CurrentMcb->Size + 1;
79 }
80}
81#else
82#define DosMemValidate()
83#endif
84
85static VOID DosCombineFreeBlocks(WORD StartBlock)
86{
87 /* NOTE: This function is always called with valid MCB blocks */
88
89 PDOS_MCB CurrentMcb = SEGMENT_TO_MCB(StartBlock), NextMcb;
90
91 /* If the block is not free, quit */
92 if (CurrentMcb->OwnerPsp != 0) return;
93
94 /*
95 * Loop while the current block is not the last one. It can happen
96 * that the block is not the last one at the beginning, but becomes
97 * the last one at the end of the process. This happens in the case
98 * where its next following blocks are free but not combined yet,
99 * and they are terminated by a free last block. During the process
100 * all the blocks are combined together and we end up in the situation
101 * where the current (free) block is followed by the last (free) block.
102 * At the last step of the algorithm the current block becomes the
103 * last one.
104 */
105 while (CurrentMcb->BlockType != 'Z')
106 {
107 /* Get a pointer to the next MCB */
108 NextMcb = SEGMENT_TO_MCB(StartBlock + CurrentMcb->Size + 1);
109
110 /* Make sure it's valid */
111 if (!ValidateMcb(NextMcb))
112 {
113 DPRINT1("The DOS memory arena is corrupted!\n");
115 return;
116 }
117
118 /* Check if the next MCB is free */
119 if (NextMcb->OwnerPsp == 0)
120 {
121 /* Combine them */
122 CurrentMcb->Size += NextMcb->Size + 1;
123 CurrentMcb->BlockType = NextMcb->BlockType;
124 NextMcb->BlockType = 'I';
125 }
126 else
127 {
128 /* No more adjoining free blocks */
129 break;
130 }
131 }
132}
133
134/* PUBLIC FUNCTIONS ***********************************************************/
135
137{
138 WORD Result = 0, Segment = SysVars->FirstMcb, MaxSize = 0;
139 PDOS_MCB CurrentMcb;
140 BOOLEAN SearchUmb = FALSE;
141
142 DPRINT("DosAllocateMemory: Size 0x%04X\n", Size);
143
145
146 if (SysVars->UmbLinked && SysVars->UmbChainStart != 0xFFFF &&
148 {
149 /* Search UMB first */
151 SearchUmb = TRUE;
152 }
153
154 while (TRUE)
155 {
156 /* Get a pointer to the MCB */
157 CurrentMcb = SEGMENT_TO_MCB(Segment);
158
159 /* Make sure it's valid */
160 if (!ValidateMcb(CurrentMcb))
161 {
162 DPRINT1("The DOS memory arena is corrupted!\n");
164 return 0;
165 }
166
167 /* Only check free blocks */
168 if (CurrentMcb->OwnerPsp != 0) goto Next;
169
170 /* Combine this free block with adjoining free blocks */
172
173 /* Update the maximum block size */
174 if (CurrentMcb->Size > MaxSize) MaxSize = CurrentMcb->Size;
175
176 /* Check if this block is big enough */
177 if (CurrentMcb->Size < Size) goto Next;
178
180 {
182 {
183 /* For first fit, stop immediately */
184 Result = Segment;
185 goto Done;
186 }
187
189 {
190 /* For best fit, update the smallest block found so far */
191 if ((Result == 0) || (CurrentMcb->Size < SEGMENT_TO_MCB(Result)->Size))
192 {
193 Result = Segment;
194 }
195
196 break;
197 }
198
200 {
201 /* For last fit, make the current block the result, but keep searching */
202 Result = Segment;
203 break;
204 }
205 }
206
207Next:
208 /* If this was the last MCB in the chain, quit */
209 if (CurrentMcb->BlockType == 'Z')
210 {
211 /* Check if nothing was found while searching through UMBs */
212 if ((Result == 0) && SearchUmb && (Sda->AllocStrategy & DOS_ALLOC_HIGH_LOW))
213 {
214 /* Search low memory */
216 SearchUmb = FALSE;
217 continue;
218 }
219
220 break;
221 }
222
223 /* Otherwise, update the segment and continue */
224 Segment += CurrentMcb->Size + 1;
225 }
226
227Done:
229
230 /* If we didn't find a free block, bail out */
231 if (Result == 0)
232 {
233 DPRINT("DosAllocateMemory FAILED. Maximum available: 0x%04X\n", MaxSize);
235 if (MaxAvailable) *MaxAvailable = MaxSize;
236 return 0;
237 }
238
239 /* Get a pointer to the MCB */
240 CurrentMcb = SEGMENT_TO_MCB(Result);
241
242 /* Check if the block is larger than requested */
243 if (CurrentMcb->Size > Size)
244 {
245 /* It is, split it into two blocks */
247 {
248 PDOS_MCB NextMcb = SEGMENT_TO_MCB(Result + Size + 1);
249
250 /* Initialize the new MCB structure */
251 NextMcb->BlockType = CurrentMcb->BlockType;
252 NextMcb->Size = CurrentMcb->Size - Size - 1;
253 NextMcb->OwnerPsp = 0;
254
255 /* Update the current block */
256 CurrentMcb->BlockType = 'M';
257 CurrentMcb->Size = Size;
258 }
259 else
260 {
261 /* Save the location of the current MCB */
262 PDOS_MCB PreviousMcb = CurrentMcb;
263
264 /* Move the current MCB higher */
265 Result += CurrentMcb->Size - Size;
266 CurrentMcb = SEGMENT_TO_MCB(Result);
267
268 /* Initialize the new MCB structure */
269 CurrentMcb->BlockType = PreviousMcb->BlockType;
270 CurrentMcb->Size = Size;
271 CurrentMcb->OwnerPsp = 0;
272
273 /* Update the previous block */
274 PreviousMcb->BlockType = 'M';
275 PreviousMcb->Size -= Size + 1;
276 }
277 }
278
279 /* Take ownership of the block */
280 CurrentMcb->OwnerPsp = Sda->CurrentPsp;
281 RtlCopyMemory(CurrentMcb->Name, SEGMENT_TO_MCB(Sda->CurrentPsp - 1)->Name, sizeof(CurrentMcb->Name));
282
284
285 /* Return the segment of the data portion of the block */
286 return Result + 1;
287}
288
289BOOLEAN DosResizeMemory(WORD BlockData, WORD NewSize, WORD *MaxAvailable)
290{
292 WORD Segment = BlockData - 1, ReturnSize = 0, NextSegment;
294
295 DPRINT("DosResizeMemory: BlockData 0x%04X, NewSize 0x%04X\n",
296 BlockData, NewSize);
297
299
300 /* Make sure this is a valid and allocated block */
301 if (BlockData == 0 || !ValidateMcb(Mcb) || Mcb->OwnerPsp == 0)
302 {
304 Success = FALSE;
305 goto Done;
306 }
307
308 ReturnSize = Mcb->Size;
309
310 /* Check if we need to expand or contract the block */
311 if (NewSize > Mcb->Size)
312 {
313 /* We can't expand the last block */
314 if (Mcb->BlockType == 'Z')
315 {
316 DPRINT("Cannot expand memory block 0x%04X: this is the last block (size 0x%04X)!\n", Segment, Mcb->Size);
318 Success = FALSE;
319 goto Done;
320 }
321
322 /* Get the pointer and segment of the next MCB */
323 NextSegment = Segment + Mcb->Size + 1;
324 NextMcb = SEGMENT_TO_MCB(NextSegment);
325
326 /* Make sure it's valid */
327 if (!ValidateMcb(NextMcb))
328 {
329 DPRINT1("The DOS memory arena is corrupted!\n");
331 return FALSE;
332 }
333
334 /* Make sure the next segment is free */
335 if (NextMcb->OwnerPsp != 0)
336 {
337 DPRINT("Cannot expand memory block 0x%04X: next segment is not free!\n", Segment);
339 Success = FALSE;
340 goto Done;
341 }
342
343 /* Combine this free block with adjoining free blocks */
344 DosCombineFreeBlocks(NextSegment);
345
346 /* Set the maximum possible size of the block */
347 ReturnSize += NextMcb->Size + 1;
348
349 if (ReturnSize < NewSize)
350 {
351 DPRINT("Cannot expand memory block 0x%04X: insufficient free segments available!\n", Segment);
353 Success = FALSE;
354 goto Done;
355 }
356
357 /* Maximize the current block */
358 Mcb->Size = ReturnSize;
359 Mcb->BlockType = NextMcb->BlockType;
360
361 /* Invalidate the next block */
362 NextMcb->BlockType = 'I';
363
364 /* Check if the block is larger than requested */
365 if (Mcb->Size > NewSize)
366 {
367 DPRINT("Block too large, reducing size from 0x%04X to 0x%04X\n",
368 Mcb->Size, NewSize);
369
370 /* It is, split it into two blocks */
371 NextMcb = SEGMENT_TO_MCB(Segment + NewSize + 1);
372
373 /* Initialize the new MCB structure */
374 NextMcb->BlockType = Mcb->BlockType;
375 NextMcb->Size = Mcb->Size - NewSize - 1;
376 NextMcb->OwnerPsp = 0;
377
378 /* Update the current block */
379 Mcb->BlockType = 'M';
380 Mcb->Size = NewSize;
381 }
382 }
383 else if (NewSize < Mcb->Size)
384 {
385 DPRINT("Shrinking block from 0x%04X to 0x%04X\n",
386 Mcb->Size, NewSize);
387
388 /* Just split the block */
389 NextSegment = Segment + NewSize + 1;
390 NextMcb = SEGMENT_TO_MCB(NextSegment);
391 NextMcb->BlockType = Mcb->BlockType;
392 NextMcb->Size = Mcb->Size - NewSize - 1;
393 NextMcb->OwnerPsp = 0;
394
395 /* Update the MCB */
396 Mcb->BlockType = 'M';
397 Mcb->Size = NewSize;
398
399 /* Combine this free block with adjoining free blocks */
400 DosCombineFreeBlocks(NextSegment);
401 }
402
403Done:
404 /* Check if the operation failed */
405 if (!Success)
406 {
407 DPRINT("DosResizeMemory FAILED. Maximum available: 0x%04X\n", ReturnSize);
408
409 /* Return the maximum possible size */
410 if (MaxAvailable) *MaxAvailable = ReturnSize;
411 }
412
414
415 return Success;
416}
417
419{
420 PDOS_MCB Mcb = SEGMENT_TO_MCB(BlockData - 1);
421
422 DPRINT("DosFreeMemory: BlockData 0x%04X\n", BlockData);
423
424 if (BlockData == 0)
425 {
427 return FALSE;
428 }
429
431
432 /* Make sure the MCB is valid */
433 if (!ValidateMcb(Mcb))
434 {
435 DPRINT("MCB block type '%c' not valid!\n", Mcb->BlockType);
437 return FALSE;
438 }
439
440 /* Mark the block as free */
441 Mcb->OwnerPsp = 0;
442
443 return TRUE;
444}
445
447{
450
451 DPRINT("Linking UMB\n");
452
453 /* Check if UMBs are initialized and already linked */
454 if (SysVars->UmbChainStart == 0xFFFF) return FALSE;
455 if (SysVars->UmbLinked) return TRUE;
456
458
459 /* Find the last block before the start of the UMB chain */
460 while (Segment < SysVars->UmbChainStart)
461 {
462 /* Get a pointer to the MCB */
464
465 /* Make sure it's valid */
466 if (!ValidateMcb(Mcb))
467 {
468 DPRINT1("The DOS memory arena is corrupted!\n");
470 return FALSE;
471 }
472
473 /* If this was the last MCB in the chain, quit */
474 if (Mcb->BlockType == 'Z') break;
475
476 /* Otherwise, update the segment and continue */
477 Segment += Mcb->Size + 1;
478 }
479
480 /* Make sure it's valid */
481 if (Mcb->BlockType != 'Z') return FALSE;
482
483 /* Connect the MCB with the UMB chain */
484 Mcb->BlockType = 'M';
485
487
489 return TRUE;
490}
491
493{
496
497 DPRINT("Unlinking UMB\n");
498
499 /* Check if UMBs are initialized and already unlinked */
500 if (SysVars->UmbChainStart == 0xFFFF) return FALSE;
501 if (!SysVars->UmbLinked) return TRUE;
502
504
505 /* Find the last block before the start of the UMB chain */
506 while (Segment < SysVars->UmbChainStart)
507 {
508 /* Get a pointer to the MCB */
510
511 /* Make sure it's valid */
512 if (!ValidateMcb(Mcb))
513 {
514 DPRINT1("The DOS memory arena is corrupted!\n");
516 return FALSE;
517 }
518
519 /* Advance to the next MCB */
520 Segment += Mcb->Size + 1;
521 }
522
523 /* Mark the MCB as the last MCB */
524 Mcb->BlockType = 'Z';
525
527
529 return TRUE;
530}
531
533{
535 Mcb->OwnerPsp = NewOwner;
536}
537
538/*
539 * Some information about DOS UMBs:
540 * http://textfiles.com/virus/datut010.txt
541 * http://www.asmcommunity.net/forums/topic/?id=30884
542 */
543
545{
546 PDOS_MCB CurrentMcb;
547 WORD Segment, PrevSegment = 0; // FIXME: or use UmbChainStart ??
548
549 if (SysVars->UmbChainStart == 0xFFFF)
550 return 0;
551
552 /* Start scanning the UMB chain */
554 while (TRUE)
555 {
556 /* Get a pointer to the MCB */
557 CurrentMcb = SEGMENT_TO_MCB(Segment);
558
559 /* Make sure it's valid */
560 if (!ValidateMcb(CurrentMcb))
561 {
562 DPRINT1("The UMB DOS memory arena is corrupted!\n");
564 return 0;
565 }
566
567 /* We went over the UMB segment, quit */
568 if (Segment >= UmbSegment) break;
569
570 PrevSegment = Segment;
571
572 /* If this was the last MCB in the chain, quit */
573 if (CurrentMcb->BlockType == 'Z') break;
574
575 /* Otherwise, update the segment and continue */
576 Segment += CurrentMcb->Size + 1;
577 }
578
579 return PrevSegment;
580}
581
583{
585 USHORT UmbSegment = 0x0000, PrevSegment;
586 USHORT Size;
587 PDOS_MCB Mcb, PrevMcb;
588
589 ASSERT(SysVars->UmbChainStart == 0xFFFF);
590
591 // SysVars->UmbLinked = FALSE;
592
593 /* Try to allocate all the UMBs */
594 while (TRUE)
595 {
596 /* Find the maximum amount of memory that can be allocated */
597 Size = 0xFFFF;
598 Result = UmaDescReserve(&UmbSegment, &Size);
599
600 /* If we are out of UMBs, bail out */
601 if (!Result && Size == 0) // XMS_STATUS_OUT_OF_UMBS
602 break;
603
604 /* We should not have succeeded! */
605 ASSERT(!Result);
606
607 /* 'Size' now contains the size of the biggest UMB block. Request it. */
608 Result = UmaDescReserve(&UmbSegment, &Size);
609 ASSERT(Result); // XMS_STATUS_SUCCESS
610
611 /* If this is our first UMB block, initialize the UMB chain */
612 if (SysVars->UmbChainStart == 0xFFFF)
613 {
614 /* Initialize the link MCB to the UMB area */
615 // NOTE: We use the fact that UmbChainStart is still == 0xFFFF
616 // so that we initialize this block from 9FFF:0000 up to FFFF:000F.
617 // It will be splitted as needed just below.
618 Mcb = SEGMENT_TO_MCB(SysVars->FirstMcb + USER_MEMORY_SIZE + 1); // '+1': Readjust the fact that USER_MEMORY_SIZE is based using 0x9FFE instead of 0x9FFF
619 Mcb->BlockType = 'Z'; // At the moment it is really the last block
620 Mcb->Size = (SysVars->UmbChainStart /* UmbSegment */ - SysVars->FirstMcb - USER_MEMORY_SIZE - 2) + 1;
621 Mcb->OwnerPsp = SYSTEM_PSP;
622 RtlCopyMemory(Mcb->Name, "SC ", sizeof("SC ")-1);
623
624#if 0 // Keep here for reference; this will be deleted as soon as it becomes unneeded.
625 /* Initialize the UMB area */
627 Mcb->Size = UMB_END_SEGMENT - SysVars->UmbChainStart;
628#endif
629
630 // FIXME: We should adjust the size of the previous block!!
631
632 /* Initialize the start of the UMB chain */
634 }
635
636 /* Split the block */
637
638 /* Get the previous block */
639 PrevSegment = DosGetPreviousUmb(UmbSegment);
640 PrevMcb = SEGMENT_TO_MCB(PrevSegment);
641
642 /* Initialize the next block */
643 Mcb = SEGMENT_TO_MCB(UmbSegment + /*Mcb->Size*/(Size - 1) + 0);
644 // Mcb->BlockType = 'Z'; // FIXME: What if this block happens to be the last one??
645 Mcb->BlockType = PrevMcb->BlockType;
646 Mcb->Size = PrevMcb->Size - (UmbSegment + Size - PrevSegment) + 1;
647 Mcb->OwnerPsp = PrevMcb->OwnerPsp;
648 RtlCopyMemory(Mcb->Name, PrevMcb->Name, sizeof(PrevMcb->Name));
649
650 /* The previous block is not the latest one anymore */
651 PrevMcb->BlockType = 'M';
652 PrevMcb->Size = UmbSegment - PrevSegment - 1;
653
654 /* Initialize the new UMB block */
655 Mcb = SEGMENT_TO_MCB(UmbSegment);
656 Mcb->BlockType = 'M'; // 'Z' // FIXME: What if this block happens to be the last one??
657 Mcb->Size = Size - 1 - 1; // minus 2 because we need to have one arena at the beginning and one at the end.
658 Mcb->OwnerPsp = 0;
659 // FIXME: Which MCB name should we use? I need to explore more the docs!
660 RtlCopyMemory(Mcb->Name, "UMB ", sizeof("UMB ")-1);
661 // RtlCopyMemory(Mcb->Name, "SM ", sizeof("SM ")-1);
662 }
663}
664
666{
668
669 /* Set the initial allocation strategy to "best fit" */
671
672 /* Initialize conventional memory; we don't have UMBs yet */
673 SysVars->FirstMcb = FIRST_MCB_SEGMENT; // The Arena Head
675 SysVars->UmbChainStart = 0xFFFF;
676
678
679 /* Initialize the MCB */
680 Mcb->BlockType = 'Z';
681 Mcb->Size = USER_MEMORY_SIZE;
682 Mcb->OwnerPsp = 0;
683}
684
685/* EOF */
unsigned char BOOLEAN
#define DPRINT1
Definition: precomp.h:8
#define ERROR_NOT_ENOUGH_MEMORY
Definition: dderror.h:7
#define TRUE
Definition: types.h:120
#define FALSE
Definition: types.h:117
PDOS_SYSVARS SysVars
Definition: dos.c:47
PDOS_SDA Sda
Definition: dos.c:48
@ Success
Definition: eventcreate.c:712
IN PVCB IN ULONG IN OUT PULONG IN BOOLEAN OUT PLARGE_MCB Mcb
Definition: fatprocs.h:348
unsigned long DWORD
Definition: ntddk_ex.h:95
unsigned short WORD
Definition: ntddk_ex.h:93
_Must_inspect_result_ _In_ USHORT NewSize
Definition: fltkernel.h:975
#define ASSERT(a)
Definition: mode.c:44
unsigned short USHORT
Definition: pedump.c:61
#define DPRINT
Definition: sndvol32.h:71
CHAR BlockType
Definition: memory.h:30
WORD Size
Definition: memory.h:32
CHAR Name[8]
Definition: memory.h:34
WORD OwnerPsp
Definition: memory.h:31
WORD LastErrorCode
Definition: dos.h:160
WORD CurrentPsp
Definition: dos.h:165
BYTE AllocStrategy
Definition: dos.h:152
WORD FirstMcb
Definition: dos.h:77
WORD UmbChainStart
Definition: dos.h:102
BYTE UmbLinked
Definition: dos.h:100
#define SYSTEM_PSP
Definition: dos.h:39
BOOLEAN DosResizeMemory(WORD BlockData, WORD NewSize, WORD *MaxAvailable)
Definition: memory.c:289
#define USER_MEMORY_SIZE
Definition: memory.c:29
WORD DosAllocateMemory(WORD Size, WORD *MaxAvailable)
Definition: memory.c:136
VOID DosInitializeUmb(VOID)
Definition: memory.c:582
BOOLEAN DosUnlinkUmb(VOID)
Definition: memory.c:492
VOID DosInitializeMemory(VOID)
Definition: memory.c:665
#define FIRST_MCB_SEGMENT
Definition: memory.c:28
WORD DosGetPreviousUmb(WORD UmbSegment)
Definition: memory.c:544
VOID DosChangeMemoryOwner(WORD Segment, WORD NewOwner)
Definition: memory.c:532
BOOLEAN DosLinkUmb(VOID)
Definition: memory.c:446
static VOID DosCombineFreeBlocks(WORD StartBlock)
Definition: memory.c:85
BOOLEAN DosFreeMemory(WORD BlockData)
Definition: memory.c:418
#define DosMemValidate()
Definition: memory.c:82
static BOOLEAN ValidateMcb(PDOS_MCB Mcb)
Definition: memory.c:44
#define DOS_ALLOC_HIGH_LOW
Definition: memory.h:18
#define SEGMENT_TO_MCB(seg)
Definition: memory.h:15
#define DOS_ALLOC_HIGH
Definition: memory.h:17
@ DOS_ALLOC_LAST_FIT
Definition: memory.h:24
@ DOS_ALLOC_BEST_FIT
Definition: memory.h:23
@ DOS_ALLOC_FIRST_FIT
Definition: memory.h:22
#define RtlCopyMemory(Destination, Source, Length)
Definition: typedefs.h:263
BOOLEAN UmaDescReserve(IN OUT PUSHORT Segment, IN OUT PUSHORT Size)
Definition: umamgr.c:84
_Must_inspect_result_ _In_ WDFDEVICE _In_ PWDF_DEVICE_PROPERTY_DATA _In_ DEVPROPTYPE _In_ ULONG Size
Definition: wdfdevice.h:4533
#define ERROR_INVALID_BLOCK
Definition: winerror.h:112
#define ERROR_ARENA_TRASHED
Definition: winerror.h:110
_At_(*)(_In_ PWSK_CLIENT Client, _In_opt_ PUNICODE_STRING NodeName, _In_opt_ PUNICODE_STRING ServiceName, _In_opt_ ULONG NameSpace, _In_opt_ GUID *Provider, _In_opt_ PADDRINFOEXW Hints, _Outptr_ PADDRINFOEXW *Result, _In_opt_ PEPROCESS OwningProcess, _In_opt_ PETHREAD OwningThread, _Inout_ PIRP Irp Result)(Mem)) NTSTATUS(WSKAPI *PFN_WSK_GET_ADDRESS_INFO
Definition: wsk.h:409
_Inout_ PVOID Segment
Definition: exfuncs.h:1101