update for HEAD-2003021201
[reactos.git] / lib / psapi / misc / win32.c
1 /* $Id$
2  */
3 /*
4  * COPYRIGHT:   See COPYING in the top level directory
5  * LICENSE:     See LGPL.txt in the top level directory
6  * PROJECT:     ReactOS system libraries
7  * FILE:        reactos/lib/psapi/misc/win32.c
8  * PURPOSE:     Win32 interfaces for PSAPI
9  * PROGRAMMER:  KJK::Hyperion <noog@libero.it>
10  * UPDATE HISTORY:
11  *              10/06/2002: Created
12  */
13
14 #include <windows.h>
15 #include <psapi.h>
16 #include <stddef.h>
17 #include <stdlib.h>
18 #include <string.h>
19 #include <ddk/ntddk.h>
20 #include <internal/psapi.h>
21
22 /* EmptyWorkingSet */
23 BOOL STDCALL EmptyWorkingSet(HANDLE hProcess)
24 {
25  NTSTATUS nErrCode;
26  QUOTA_LIMITS qlProcessQuota;
27
28  /* query the working set */
29  nErrCode = NtQueryInformationProcess
30  (
31   hProcess,
32   ProcessQuotaLimits,
33   &qlProcessQuota,
34   sizeof(qlProcessQuota),
35   NULL
36  );
37
38  /* failure */
39  if(!NT_SUCCESS(nErrCode))
40   goto fail;
41
42  /* empty the working set */
43  qlProcessQuota.MinimumWorkingSetSize = -1;
44  qlProcessQuota.MaximumWorkingSetSize = -1;
45
46  /* set the working set */
47  nErrCode = NtSetInformationProcess
48  (
49   hProcess,
50   ProcessQuotaLimits,
51   &qlProcessQuota,
52   sizeof(qlProcessQuota)
53  );
54
55  /* success */
56  if(NT_SUCCESS(nErrCode))
57   return (TRUE);
58
59 fail:
60  /* failure */
61  SetLastError(RtlNtStatusToDosError(nErrCode));
62  return (FALSE);
63 }
64
65 /* EnumDeviceDrivers */
66 /* callback context */
67 typedef struct _ENUM_DEVICE_DRIVERS_CONTEXT
68 {
69  LPVOID *lpImageBase;
70  DWORD nCount;
71 } ENUM_DEVICE_DRIVERS_CONTEXT, *PENUM_DEVICE_DRIVERS_CONTEXT;
72
73 /* callback routine */
74 NTSTATUS STDCALL EnumDeviceDriversCallback
75 (
76  IN ULONG ModuleCount,
77  IN PSYSTEM_MODULE_ENTRY CurrentModule,
78  IN OUT PVOID CallbackContext
79 )
80 {
81  register PENUM_DEVICE_DRIVERS_CONTEXT peddcContext =
82   (PENUM_DEVICE_DRIVERS_CONTEXT)CallbackContext;
83
84  /* no more buffer space */
85  if(peddcContext->nCount == 0)
86   return STATUS_INFO_LENGTH_MISMATCH;
87
88  /* return current module */
89  *(peddcContext->lpImageBase) = CurrentModule->BaseAddress;
90
91  /* go to next array slot */
92  (peddcContext->lpImageBase) ++;
93  (peddcContext->nCount) --;
94
95  return STATUS_SUCCESS;
96 }
97
98 /* exported interface */
99 BOOL STDCALL EnumDeviceDrivers
100 (
101  LPVOID *lpImageBase,
102  DWORD cb,
103  LPDWORD lpcbNeeded
104 )
105 {
106  register NTSTATUS nErrCode;
107  ENUM_DEVICE_DRIVERS_CONTEXT eddcContext = {lpImageBase, cb / sizeof(PVOID)};
108
109  cb /= sizeof(PVOID);
110
111  /* do nothing if the buffer is empty */
112  if(cb == 0 || lpImageBase == NULL)
113  {
114   *lpcbNeeded = 0;
115   return (TRUE);
116  }
117
118  /* enumerate the system modules */
119  nErrCode = PsaEnumerateSystemModules(&EnumDeviceDriversCallback, &eddcContext);
120
121  /* return the count of bytes returned */
122  *lpcbNeeded = (cb - eddcContext.nCount) * sizeof(PVOID);
123
124  /* success */
125  if(NT_SUCCESS(nErrCode) || nErrCode == STATUS_INFO_LENGTH_MISMATCH)
126   return (TRUE);
127  else
128  {
129   /* failure */
130   SetLastError(RtlNtStatusToDosError(nErrCode));
131   return (FALSE);
132  }
133 }
134
135 /* EnumProcesses */
136 /* callback context */
137 typedef struct _ENUM_PROCESSES_CONTEXT
138 {
139  DWORD *lpidProcess;
140  DWORD nCount;
141 } ENUM_PROCESSES_CONTEXT, *PENUM_PROCESSES_CONTEXT;
142
143 /* callback routine */
144 NTSTATUS STDCALL EnumProcessesCallback
145 (
146  IN PSYSTEM_PROCESS_INFORMATION CurrentProcess,
147  IN OUT PVOID CallbackContext
148 )
149 {
150  register PENUM_PROCESSES_CONTEXT pepcContext =
151   (PENUM_PROCESSES_CONTEXT)CallbackContext;
152
153  /* no more buffer space */
154  if(pepcContext->nCount == 0)
155   return STATUS_INFO_LENGTH_MISMATCH;
156
157  /* return current process */
158  *(pepcContext->lpidProcess) = CurrentProcess->ProcessId;
159
160  /* go to next array slot */
161  (pepcContext->lpidProcess) ++;
162  (pepcContext->nCount) --;
163
164  return STATUS_SUCCESS;
165 }
166
167 /* exported interface */
168 /*
169  @brief Enumerate the process identifiers of the currently active processes
170
171  @param lpidProcess Array that receives the list of process identifiers
172  @param cb          Size of the @p lpidProcess array, in bytes
173  @param lpcbNeeded  Number of bytes returned in the @p lpidProcess array
174
175  @return [standard]
176  */
177 BOOL STDCALL EnumProcesses
178 (
179  DWORD *lpidProcess,
180  DWORD cb,
181  LPDWORD lpcbNeeded
182 )
183 {
184  register NTSTATUS nErrCode;
185  ENUM_PROCESSES_CONTEXT epcContext = {lpidProcess, cb / sizeof(DWORD)};
186
187  cb /= sizeof(DWORD);
188
189  /* do nothing if the buffer is empty */
190  if(cb == 0 || lpidProcess == NULL)
191  {
192   *lpcbNeeded = 0;
193   return (TRUE);
194  }
195
196  /* enumerate the process ids */
197  nErrCode = PsaEnumerateProcesses(&EnumProcessesCallback, &epcContext);
198
199  *lpcbNeeded = (cb - epcContext.nCount) * sizeof(DWORD);
200
201  /* success */
202  if(NT_SUCCESS(nErrCode) || nErrCode == STATUS_INFO_LENGTH_MISMATCH)
203   return (TRUE);
204  else
205  {
206   /* failure */
207   SetLastError(RtlNtStatusToDosError(nErrCode));
208   return (FALSE);
209  }
210 }
211
212 /* EnumProcessModules */
213 /* callback context */
214 typedef struct _ENUM_PROCESS_MODULES_CONTEXT
215 {
216  HMODULE *lphModule;
217  DWORD nCount;
218 } ENUM_PROCESS_MODULES_CONTEXT, *PENUM_PROCESS_MODULES_CONTEXT;
219
220 /* callback routine */
221 NTSTATUS STDCALL EnumProcessModulesCallback
222 (
223  IN HANDLE ProcessHandle,
224  IN PLDR_MODULE CurrentModule,
225  IN OUT PVOID CallbackContext
226 )
227 {
228  register PENUM_PROCESS_MODULES_CONTEXT pepmcContext =
229   (PENUM_PROCESS_MODULES_CONTEXT)CallbackContext;
230
231  /* no more buffer space */
232  if(pepmcContext->nCount == 0)
233   return STATUS_INFO_LENGTH_MISMATCH;
234
235  /* return current process */
236  *(pepmcContext->lphModule) = CurrentModule->BaseAddress;
237
238  /* go to next array slot */
239  (pepmcContext->lphModule) ++;
240  (pepmcContext->nCount) --;
241
242  return STATUS_SUCCESS;
243 }
244
245 /* exported interface */
246 BOOL STDCALL EnumProcessModules(
247   HANDLE hProcess,
248   HMODULE *lphModule,
249   DWORD cb,
250   LPDWORD lpcbNeeded
251 )
252 {
253  register NTSTATUS nErrCode;
254  ENUM_PROCESS_MODULES_CONTEXT epmcContext = {lphModule, cb / sizeof(HMODULE)};
255
256  cb /= sizeof(DWORD);
257
258  /* do nothing if the buffer is empty */
259  if(cb == 0 || lphModule == NULL)
260  {
261   *lpcbNeeded = 0;
262   return (TRUE);
263  }
264
265  /* enumerate the process modules */
266  nErrCode = PsaEnumerateProcessModules
267  (
268   hProcess,
269   &EnumProcessModulesCallback,
270   &epmcContext
271  );
272
273  *lpcbNeeded = (cb - epmcContext.nCount) * sizeof(DWORD);
274
275  /* success */
276  if(NT_SUCCESS(nErrCode) || nErrCode == STATUS_INFO_LENGTH_MISMATCH)
277   return (TRUE);
278  else
279  {
280   /* failure */
281   SetLastError(RtlNtStatusToDosError(nErrCode));
282   return (FALSE);
283  }
284 }
285
286 /* GetDeviceDriverBase/FileName */
287 /* common callback context */
288 typedef struct _GET_DEVICE_DRIVER_NAME_CONTEXT
289 {
290  LPVOID ImageBase;
291  struct
292  {
293   ULONG bFullName:sizeof(ULONG) * 8 / 2;
294   ULONG bUnicode:sizeof(ULONG) * 8 / 2;
295  };
296  DWORD nSize;
297  union
298  {
299   LPVOID lpName;
300   LPSTR lpAnsiName;
301   LPWSTR lpUnicodeName;
302  };
303 } GET_DEVICE_DRIVER_NAME_CONTEXT, *PGET_DEVICE_DRIVER_NAME_CONTEXT;
304
305 /* common callback routine */
306 NTSTATUS STDCALL GetDeviceDriverNameCallback
307 (
308  IN ULONG ModuleCount,
309  IN PSYSTEM_MODULE_ENTRY CurrentModule,
310  IN OUT PVOID CallbackContext
311 )
312 {
313  register PGET_DEVICE_DRIVER_NAME_CONTEXT pgddncContext =
314   (PGET_DEVICE_DRIVER_NAME_CONTEXT) CallbackContext;
315
316  /* module found */
317  if(pgddncContext->ImageBase == CurrentModule->BaseAddress)
318  {
319   register PCHAR pcModuleName;
320   register ULONG l;
321
322   /* get the full name or just the filename part */
323   if(pgddncContext->bFullName)
324    pcModuleName = &CurrentModule->Name[0];
325   else
326    pcModuleName = &CurrentModule->Name[CurrentModule->PathLength];
327
328   /* get the length of the name */
329   l = strlen(pcModuleName);
330
331   /* if user buffer smaller than the name */
332   if(pgddncContext->nSize <= l)
333    /* use the user buffer's length */
334    l = pgddncContext->nSize;
335   /* if user buffer larger than the name */
336   else
337   {
338    /* enough space for the null terminator */
339    l ++;
340    pgddncContext->nSize = l;
341   }
342
343   /* copy the string */
344   if(pgddncContext->bUnicode)
345   {
346    /* Unicode: convert and copy */
347    ANSI_STRING strAnsi = {l, l, pcModuleName};
348    UNICODE_STRING wstrUnicode =
349    {
350      0,
351      l * sizeof(WCHAR),
352      pgddncContext->lpUnicodeName
353    };
354    /* driver names should always be in language-neutral ASCII, so we don't
355       bother calling AreFileApisANSI() */
356    RtlAnsiStringToUnicodeString(&wstrUnicode, &strAnsi, FALSE);
357   }
358   else
359    /* ANSI/OEM: direct copy */
360    memcpy(pgddncContext->lpAnsiName, pcModuleName, l);
361
362   /* terminate the enumeration */
363   return STATUS_NO_MORE_FILES;
364  }
365  /* continue searching */
366  else
367   return STATUS_SUCCESS;
368 }
369
370 /* common internal implementation */
371 DWORD FASTCALL internalGetDeviceDriverName(
372   BOOLEAN bUnicode,
373   BOOLEAN bFullName,
374   LPVOID ImageBase,
375   LPVOID lpName,
376   DWORD nSize
377 )
378 {
379  register NTSTATUS nErrCode;
380  GET_DEVICE_DRIVER_NAME_CONTEXT gddncContext =
381  {
382   ImageBase,
383   { bFullName, bUnicode },
384   nSize,
385   { lpName }
386  };
387
388  /* empty buffer */
389  if(lpName == NULL || nSize == 0)
390   return 0;
391
392  /* invalid image base */
393  if(ImageBase == NULL)
394  {
395   SetLastError(ERROR_INVALID_HANDLE);
396   return 0;
397  }
398
399  /* start the enumeration */
400  nErrCode = PsaEnumerateSystemModules
401  (
402   &GetDeviceDriverNameCallback,
403   &gddncContext
404  );
405
406  if(nErrCode == STATUS_NO_MORE_FILES)
407   /* module was found, return string size */
408   return gddncContext.nSize;
409  else
410  {
411   if(NT_SUCCESS(nErrCode))
412    /* module was not found */
413    SetLastError(ERROR_INVALID_HANDLE);
414   else
415    /* an error occurred */
416    SetLastError(RtlNtStatusToDosError(nErrCode));
417
418   /* failure */
419   return 0;
420  }
421 }
422
423 /* exported interfaces */
424 /*
425  NOTES:
426   - nSize is not, as stated by Microsoft's documentation, the byte size, but the
427     count of characters in the buffer
428   - the return value is the count of characters copied into the buffer
429   - the functions don't attempt to null-terminate the string
430  */
431 DWORD STDCALL GetDeviceDriverBaseNameA(
432   LPVOID ImageBase,
433   LPSTR lpBaseName,
434   DWORD nSize
435 )
436 {
437  return internalGetDeviceDriverName(FALSE, FALSE, ImageBase, lpBaseName, nSize);
438 }
439
440 DWORD STDCALL GetDeviceDriverFileNameA(
441   LPVOID ImageBase,
442   LPSTR lpFilename,
443   DWORD nSize
444 )
445 {
446  return internalGetDeviceDriverName(FALSE, TRUE, ImageBase, lpFilename, nSize);
447 }
448
449 DWORD STDCALL GetDeviceDriverBaseNameW(
450   LPVOID ImageBase,
451   LPWSTR lpBaseName,
452   DWORD nSize
453 )
454 {
455  return internalGetDeviceDriverName(TRUE, FALSE, ImageBase, lpBaseName, nSize);
456 }
457
458 DWORD STDCALL GetDeviceDriverFileNameW(
459   LPVOID ImageBase,
460   LPWSTR lpFilename,
461   DWORD nSize
462 )
463 {
464  return internalGetDeviceDriverName(TRUE, TRUE, ImageBase, lpFilename, nSize);
465 }
466
467 /* GetMappedFileName */
468 /* common internal implementation */
469 DWORD FASTCALL internalGetMappedFileName(
470   BOOLEAN bUnicode,
471   HANDLE hProcess,    
472   LPVOID lpv,         
473   LPVOID lpName,   
474   DWORD nSize         
475 )
476 {
477  register NTSTATUS nErrCode;
478  register ULONG nBufSize;
479  PMEMORY_SECTION_NAME pmsnName;
480
481  /* empty buffer */
482  if(nSize == 0 || (LPSTR)lpName == NULL)
483   return 0;
484
485  if(nSize > (0xFFFF / sizeof(WCHAR)))
486   /* if the user buffer contains more characters than would fit in an
487      UNICODE_STRING, limit the buffer size. RATIONALE: we don't limit buffer
488      size elsewhere because here superfluous buffer size will mean a larger
489      temporary buffer */
490   nBufSize = 0xFFFF / sizeof(WCHAR);
491  else
492   nBufSize = nSize * sizeof(WCHAR);
493  
494  /* allocate the memory */
495  pmsnName = malloc(nBufSize + offsetof(MEMORY_SECTION_NAME, NameBuffer));
496  
497  if(pmsnName == NULL)
498  {
499   /* failure */
500   SetLastError(ERROR_OUTOFMEMORY);
501   return 0;
502  }
503
504  /* initialize the destination buffer */
505  pmsnName->SectionFileName.Length = 0;
506  pmsnName->SectionFileName.Length = nBufSize;
507
508 #if 0
509  __try
510  {
511 #endif
512   /* query the name */
513   nErrCode = NtQueryVirtualMemory
514   (
515    hProcess,
516    lpv,
517    MemorySectionName,
518    pmsnName,
519    nBufSize,
520    NULL
521   );
522   
523   if(!NT_SUCCESS(nErrCode))
524   {
525    /* failure */
526    SetLastError(RtlNtStatusToDosError(nErrCode));
527 #if 0
528 #else
529    /* free the buffer */
530    free(pmsnName);
531 #endif
532    return 0;
533   }
534   
535   /* copy the name */
536   if(bUnicode)
537   {
538    /* destination is an Unicode string: direct copy */
539    memcpy
540    (
541     (LPWSTR)lpName,
542     pmsnName->NameBuffer,
543     pmsnName->SectionFileName.Length
544    );
545    
546 #if 0
547 #else
548    /* free the buffer */
549    free(pmsnName);
550 #endif
551    
552    if(pmsnName->SectionFileName.Length < nSize)
553    {
554     /* null-terminate the string */
555     ((LPWSTR)lpName)[pmsnName->SectionFileName.Length] = 0;
556     return pmsnName->SectionFileName.Length + 1;
557    }
558    
559    return pmsnName->SectionFileName.Length;
560   }
561   else
562   {
563    ANSI_STRING strAnsi = {0, nSize, (LPSTR)lpName};
564
565    if(AreFileApisANSI())
566     /* destination is an ANSI string: convert and copy */
567     RtlUnicodeStringToAnsiString(&strAnsi, &pmsnName->SectionFileName, FALSE);
568    else
569     /* destination is an OEM string: convert and copy */
570     RtlUnicodeStringToOemString(&strAnsi, &pmsnName->SectionFileName, FALSE);
571
572 #if 0
573 #else
574    /* free the buffer */
575    free(pmsnName);
576 #endif
577
578    if(strAnsi.Length < nSize)
579    {
580     /* null-terminate the string */
581     ((LPSTR)lpName)[strAnsi.Length] = 0;
582     return strAnsi.Length + 1;
583    }
584
585    return strAnsi.Length;
586   }
587
588 #if 0
589  }
590  __finally
591  {
592   free(pmsnName);
593  }
594 #endif
595 }
596
597 /* exported interfaces */
598 DWORD STDCALL GetMappedFileNameA(
599   HANDLE hProcess,    
600   LPVOID lpv,         
601   LPSTR lpFilename,   
602   DWORD nSize         
603 )
604 {
605  return internalGetMappedFileName(FALSE, hProcess, lpv, lpFilename, nSize);
606 }
607
608 DWORD STDCALL GetMappedFileNameW(
609   HANDLE hProcess,    
610   LPVOID lpv,         
611   LPWSTR lpFilename,  
612   DWORD nSize         
613 )
614 {
615  return internalGetMappedFileName(TRUE, hProcess, lpv, lpFilename, nSize);
616 }
617
618 /* GetModuleInformation */
619 /* common callback context */
620 typedef struct _GET_MODULE_INFORMATION_FLAGS
621 {
622  ULONG bWantName:sizeof(ULONG) * 8 / 4;
623  ULONG bUnicode:sizeof(ULONG) * 8 / 4;
624  ULONG bFullName:sizeof(ULONG) * 8 / 4;
625 } GET_MODULE_INFORMATION_FLAGS, *PGET_MODULE_INFORMATION_FLAGS;
626
627 typedef struct _GET_MODULE_INFORMATION_CONTEXT
628 {
629  HMODULE hModule;
630  GET_MODULE_INFORMATION_FLAGS Flags;
631  DWORD nBufSize;
632  union
633  {
634   LPWSTR lpUnicodeName;
635   LPSTR lpAnsiName;
636   LPMODULEINFO lpmodinfo;
637   LPVOID lpBuffer;
638  };
639 } GET_MODULE_INFORMATION_CONTEXT, *PGET_MODULE_INFORMATION_CONTEXT;
640
641 /* common callback */
642 NTSTATUS STDCALL GetModuleInformationCallback
643 (
644  IN HANDLE ProcessHandle,
645  IN PLDR_MODULE CurrentModule,
646  IN OUT PVOID CallbackContext
647 )
648 {
649  register PGET_MODULE_INFORMATION_CONTEXT pgmicContext =
650   (PGET_MODULE_INFORMATION_CONTEXT)CallbackContext;
651
652  /* found the module we were looking for */
653  if(CurrentModule->BaseAddress == pgmicContext->hModule)
654  {
655   /* we want the module name */
656   if(pgmicContext->Flags.bWantName)
657   {
658    register NTSTATUS nErrCode;
659    register PUNICODE_STRING pwstrSource;
660    register ULONG l;
661    
662    if(pgmicContext->Flags.bFullName)
663     /* full name */
664     pwstrSource = &(CurrentModule->FullDllName);
665    else
666     /* base name only */
667     pwstrSource = &(CurrentModule->BaseDllName);
668    
669    /* paranoia */
670    pwstrSource->Length -= pwstrSource->Length % sizeof(WCHAR);
671    
672    /* l is the byte size of the user buffer */
673    l = pgmicContext->nBufSize * sizeof(WCHAR);
674    
675    /* if the user buffer has room for the string and a null terminator */
676    if(l >= (pwstrSource->Length + sizeof(WCHAR)))
677    {
678     /* limit the buffer size */
679     l = pwstrSource->Length;
680     
681     /* null-terminate the string */
682     if(pgmicContext->Flags.bUnicode)
683      pgmicContext->lpUnicodeName[l / sizeof(WCHAR)] = 0;
684     else
685      pgmicContext->lpAnsiName[l / sizeof(WCHAR)] = 0;
686    }
687
688    if(pgmicContext->Flags.bUnicode)
689    {
690     /* Unicode: direct copy */
691     /* NOTE: I've chosen not to check for ProcessHandle == NtCurrentProcess(),
692        this function is complicated enough as it is */
693     nErrCode = NtReadVirtualMemory
694     (
695      ProcessHandle,
696      pwstrSource->Buffer,
697      pgmicContext->lpUnicodeName,
698      l,
699      NULL
700     );
701
702     if(NT_SUCCESS(nErrCode))
703      pgmicContext->nBufSize = l / sizeof(WCHAR);
704     else
705     {
706      pgmicContext->nBufSize = 0;
707      return nErrCode;
708     }
709    }
710    else
711    {
712     /* ANSI/OEM: convert and copy */
713     register LPWSTR pwcUnicodeBuf;
714     ANSI_STRING strAnsi = {0, pgmicContext->nBufSize, pgmicContext->lpAnsiName};
715     UNICODE_STRING wstrUnicodeBuf;
716     
717     /* allocate the local buffer */
718     pwcUnicodeBuf = malloc(pwstrSource->Length);
719
720 #if 0
721     __try
722     {
723 #endif
724      if(pwcUnicodeBuf == NULL)
725       /* failure */
726 #if 0
727       return STATUS_NO_MEMORY;
728 #else
729      {
730       nErrCode = STATUS_NO_MEMORY;
731       goto exitWithStatus;
732      }
733 #endif
734  
735      /* copy the string in the local buffer */
736      nErrCode = NtReadVirtualMemory
737      (
738       ProcessHandle,
739       pwstrSource->Buffer,
740       pwcUnicodeBuf,
741       l,
742       NULL
743      );
744  
745      if(!NT_SUCCESS(nErrCode))
746       /* failure */
747 #if 0
748       return nErrCode;
749 #else
750       goto exitWithStatus;
751 #endif
752      
753      /* initialize Unicode string buffer */
754      wstrUnicodeBuf.Length = wstrUnicodeBuf.MaximumLength = l;
755      wstrUnicodeBuf.Buffer = pwcUnicodeBuf;
756      
757      /* convert and copy */
758      if(AreFileApisANSI())
759       RtlUnicodeStringToAnsiString(&strAnsi, &wstrUnicodeBuf, FALSE);
760      else
761       RtlUnicodeStringToOemString(&strAnsi, &wstrUnicodeBuf, FALSE);
762      
763      /* return the string size */
764      pgmicContext->nBufSize = strAnsi.Length;
765 #if 0
766     }
767     __finally
768     {
769      /* free the buffer */
770      free(pwcUnicodeBuf);
771     }
772 #else
773      /* success */
774      nErrCode = STATUS_NO_MORE_FILES;
775
776 exitWithStatus:
777      /* free the buffer */
778      free(pwcUnicodeBuf);
779      return nErrCode;
780 #endif
781    }
782    
783   }
784   /* we want other module information */
785   else
786   {
787    register ULONG nSize = pgmicContext->nBufSize;
788    
789    /* base address */
790    if(nSize >= sizeof(CurrentModule->BaseAddress))
791    {
792     pgmicContext->lpmodinfo->lpBaseOfDll = CurrentModule->BaseAddress;
793     nSize -= sizeof(CurrentModule->BaseAddress);
794    }
795    
796    /* image size */
797    if(nSize >= sizeof(CurrentModule->SizeOfImage))
798    {
799     pgmicContext->lpmodinfo->SizeOfImage = CurrentModule->SizeOfImage;
800     nSize -= sizeof(CurrentModule->SizeOfImage);
801    }
802    
803    /* entry point */
804    if(nSize >= sizeof(CurrentModule->EntryPoint))
805     /* ??? FIXME? is "EntryPoint" just the offset, or the real address? */
806     pgmicContext->lpmodinfo->EntryPoint = (PVOID)CurrentModule->EntryPoint;
807    
808    pgmicContext->nBufSize = TRUE;
809   }
810   
811   return STATUS_NO_MORE_FILES;
812  }
813
814  return STATUS_SUCCESS;
815 }
816
817 /* common internal implementation */
818 DWORD FASTCALL internalGetModuleInformation(
819   HANDLE hProcess,
820   HMODULE hModule,
821   GET_MODULE_INFORMATION_FLAGS Flags,
822   LPVOID lpBuffer,
823   DWORD nBufSize
824 )
825 {
826  register NTSTATUS nErrCode;
827  GET_MODULE_INFORMATION_CONTEXT gmicContext =
828  {
829   hModule,
830   Flags,
831   nBufSize,
832   {lpBuffer}
833  };
834
835
836  nErrCode = PsaEnumerateProcessModules
837  (
838   hProcess,
839   &GetModuleInformationCallback,
840   &gmicContext
841  );
842
843  if(nErrCode == STATUS_NO_MORE_FILES)
844   return gmicContext.nBufSize;
845  else
846  {
847   if(NT_SUCCESS(nErrCode))
848    SetLastError(ERROR_INVALID_HANDLE);
849   else
850    SetLastError(RtlNtStatusToDosError(nErrCode));
851
852   return 0;
853  }
854 }
855
856 /* exported interfaces */
857 DWORD STDCALL GetModuleBaseNameA(
858   HANDLE hProcess,    // handle to process
859   HMODULE hModule,    // handle to module
860   LPSTR lpBaseName,   // base name buffer
861   DWORD nSize         // maximum characters to retrieve
862 )
863 {
864  register GET_MODULE_INFORMATION_FLAGS Flags = {TRUE, FALSE, FALSE};
865  return internalGetModuleInformation
866  (
867   hProcess,
868   hModule,
869   Flags,
870   lpBaseName,
871   nSize
872  );
873 }
874
875 DWORD STDCALL GetModuleBaseNameW(
876   HANDLE hProcess,    // handle to process
877   HMODULE hModule,    // handle to module
878   LPWSTR lpBaseName,  // base name buffer
879   DWORD nSize         // maximum characters to retrieve
880 )
881 {
882  register GET_MODULE_INFORMATION_FLAGS Flags = {TRUE, TRUE, FALSE};
883  return internalGetModuleInformation
884  (
885   hProcess,
886   hModule,
887   Flags,
888   lpBaseName,
889   nSize
890  );
891 }
892
893 DWORD STDCALL GetModuleFileNameExA(
894   HANDLE hProcess,    // handle to process
895   HMODULE hModule,    // handle to module
896   LPSTR lpFilename,   // path buffer
897   DWORD nSize         // maximum characters to retrieve
898 )
899 {
900  register GET_MODULE_INFORMATION_FLAGS Flags = {TRUE, FALSE, TRUE};
901  return internalGetModuleInformation
902  (
903   hProcess,
904   hModule,
905   Flags,
906   lpFilename,
907   nSize
908  );
909 }
910
911 DWORD STDCALL GetModuleFileNameExW(
912   HANDLE hProcess,    // handle to process
913   HMODULE hModule,    // handle to module
914   LPWSTR lpFilename,  // path buffer
915   DWORD nSize         // maximum characters to retrieve
916 )
917 {
918  register GET_MODULE_INFORMATION_FLAGS Flags = {TRUE, TRUE, TRUE};
919  return internalGetModuleInformation
920  (
921   hProcess,
922   hModule,
923   Flags,
924   lpFilename,
925   nSize
926  );
927 }
928
929 BOOL STDCALL GetModuleInformation(
930   HANDLE hProcess,         // handle to process
931   HMODULE hModule,         // handle to module
932   LPMODULEINFO lpmodinfo,  // information buffer
933   DWORD cb                 // size of buffer
934 )
935 {
936  register GET_MODULE_INFORMATION_FLAGS Flags = {FALSE, FALSE, FALSE};
937  return (BOOL)internalGetModuleInformation
938  (
939   hProcess,
940   hModule,
941   Flags,
942   lpmodinfo,
943   cb
944  );
945 }
946 /* EOF */
947