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