source: trunk/src/helpers/procstat.c@ 212

Last change on this file since 212 was 207, checked in by umoeller, 23 years ago

Watchdog.

  • Property svn:eol-style set to CRLF
  • Property svn:keywords set to Author Date Id Revision
File size: 22.8 KB
Line 
1
2/*
3 *@@sourcefile procstat.c:
4 * functions for querying process information.
5 * This is an easy-to-use interface to the
6 * messy 16-bit DosQProcStatus function.
7 *
8 * Usage: All OS/2 programs.
9 *
10 * Function prefixes (new with V0.81):
11 * -- prc* Query Process helper functions
12 *
13 * Based on Kai Uwe Rommel's "dosqproc" package
14 * available at Hobbes:
15 * Kai Uwe Rommel - Wed 25-Mar-1992
16 * Sat 13-Aug-1994
17 *
18 * Note: If you link against procstat.obj, you
19 * need to import the following in your .DEF file:
20 *
21 + IMPORTS
22 + DOSQPROCSTATUS = DOSCALLS.154
23 + DosQuerySysState = DOSCALLS.368
24 *
25 * or linking will fail.
26 *
27 * Note: Version numbering in this file relates to XWorkplace version
28 * numbering.
29 *
30 *@@header "helpers\procstat.h"
31 */
32
33/*
34 * Copyright (C) 1992-1994 Kai Uwe Rommel.
35 * Copyright (C) 1998-2000 Ulrich M”ller.
36 * This file is part of the "XWorkplace helpers" source package.
37 * This is free software; you can redistribute it and/or modify
38 * it under the terms of the GNU General Public License as published
39 * by the Free Software Foundation, in version 2 as it comes in the
40 * "COPYING" file of the XWorkplace main distribution.
41 * This program is distributed in the hope that it will be useful,
42 * but WITHOUT ANY WARRANTY; without even the implied warranty of
43 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
44 * GNU General Public License for more details.
45 */
46
47#define OS2EMX_PLAIN_CHAR
48 // this is needed for "os2emx.h"; if this is defined,
49 // emx will define PSZ as _signed_ char, otherwise
50 // as unsigned char
51
52#define INCL_DOSMODULEMGR
53#define INCL_DOSERRORS
54#include <os2.h>
55
56#include <stdlib.h> // already #include'd
57#include <string.h> // already #include'd
58#include <stdio.h>
59
60#include "setup.h" // code generation and debugging options
61
62#include "helpers\procstat.h"
63
64#pragma hdrstop
65
66/*
67 *@@category: Helpers\Control program helpers\Process status\16-bit DosQProcStat
68 */
69
70/********************************************************************
71 *
72 * DosQProcStat (16-bit) interface
73 *
74 ********************************************************************/
75
76/*
77 *@@ prc16GetInfo:
78 * nifty interface to DosQProcStat (16-bit).
79 * This returns the head of a newly
80 * allocated buffer which has plenty
81 * of pointers for subsequent browsing.
82 *
83 * Use prc16FreeInfo to free the buffer.
84 *
85 *@@added V0.9.3 (2000-05-05) [umoeller]
86 *@@changed V0.9.10 (2001-04-08) [umoeller]: this returned != NULL even though item was freed, fixed
87 *@@changed V0.9.10 (2001-04-08) [umoeller]: now using DosAllocMem, raised bufsize, changed prototype
88 */
89
90APIRET prc16GetInfo(PQPROCSTAT16 *ppps) // out: error, ptr can be NULL
91{
92 APIRET arc = NO_ERROR;
93 PQPROCSTAT16 pps = NULL;
94
95 /* PQPROCSTAT16 pps = (PQPROCSTAT16)malloc(0x8000);
96 if (!pps)
97 arc = ERROR_NOT_ENOUGH_MEMORY;
98 else */
99
100 if (!ppps)
101 return (ERROR_INVALID_PARAMETER);
102
103 // changed allocation V0.9.10 (2001-04-08) [umoeller]:
104 // malloc didn't guarantee that the object did not
105 // cross a 64K boundary, which could cause DosQProcStat
106 // to fail...
107 #define BUF_SIZE 0xFFFF // raised from 0x8000
108
109 if (!(arc = DosAllocMem((VOID**)&pps,
110 BUF_SIZE,
111 PAG_READ | PAG_WRITE | PAG_COMMIT
112 | OBJ_TILE // 16-bit compatible, ignored really
113 )))
114 {
115 if (arc = DosQProcStatus(pps, BUF_SIZE))
116 {
117 // error:
118 DosFreeMem(pps); // V0.9.10 (2001-04-08) [umoeller]
119
120 // and even worse, I forgot to set the return ptr
121 // to NULL, so this was freed twice... I guess
122 // this produced the crashes in WarpIN with the
123 // KILLPROCESS attribute... V0.9.10 (2001-04-08) [umoeller]
124 pps = NULL;
125 }
126 }
127
128 *ppps = pps;
129
130 return arc;
131}
132
133/*
134 *@@ prc16FreeInfo:
135 * frees memory allocated by prc16GetInfo.
136 *
137 *@@added V0.9.3 (2000-05-05) [umoeller]
138 *@@changed V0.9.10 (2001-04-08) [umoeller]: now using DosFreeMem
139 */
140
141APIRET prc16FreeInfo(PQPROCSTAT16 pInfo)
142{
143 if (!pInfo)
144 return ERROR_INVALID_PARAMETER;
145
146 return DosFreeMem(pInfo);
147}
148
149/*
150 *@@ prc16FindProcessFromName:
151 * searches the specified buffer for a process
152 * with the specified name and returns a pointer
153 * to its data within pInfo.
154 *
155 * Returns NULL if not found.
156 *
157 *@@added V0.9.3 (2000-05-05) [umoeller]
158 */
159
160PQPROCESS16 prc16FindProcessFromName(PQPROCSTAT16 pInfo, // in: from prc16GetInfo
161 const char *pcszName) // in: e.g. "pmshell.exe"
162{
163 PQPROCESS16 pProcess,
164 pReturn = NULL;
165 if (pInfo)
166 {
167 for ( pProcess = (PQPROCESS16)PTR(pInfo->ulProcesses, 0);
168 pProcess->ulType != 3;
169 pProcess = (PQPROCESS16)PTR(pProcess->ulThreadList,
170 pProcess->usThreads * sizeof(QTHREAD16))
171 )
172 {
173 CHAR szModuleName[CCHMAXPATH];
174 if (DosQueryModuleName(pProcess->usHModule,
175 sizeof(szModuleName),
176 szModuleName)
177 == NO_ERROR)
178 {
179 // the module name is fully qualified, so find the
180 // file name (after the last backslash)
181 PSZ pLastBackslash = strrchr(szModuleName, '\\');
182 if (pLastBackslash)
183 // found:
184 if (stricmp(pLastBackslash + 1, pcszName) == 0)
185 {
186 // matches:
187 pReturn = pProcess;
188 break;
189 }
190 }
191 }
192 }
193
194 return (pReturn);
195}
196
197/*
198 *@@ prc16FindProcessFromPID:
199 * searches the specified buffer for a process
200 * with the specified PID and returns a pointer
201 * to its data within pInfo.
202 *
203 * Returns NULL if not found.
204 *
205 *V0.9.5 (2000-09-29) [umoeller]
206 */
207
208PQPROCESS16 prc16FindProcessFromPID(PQPROCSTAT16 pInfo, // in: from prc16GetInfo
209 ULONG ulPID) // in: PID
210{
211 PQPROCESS16 pProcess,
212 pReturn = NULL;
213 if (pInfo)
214 {
215 for ( pProcess = (PQPROCESS16)PTR(pInfo->ulProcesses, 0);
216 pProcess->ulType != 3;
217 pProcess = (PQPROCESS16)PTR(pProcess->ulThreadList,
218 pProcess->usThreads * sizeof(QTHREAD16))
219 )
220 {
221 if (pProcess->usPID == ulPID)
222 {
223 pReturn = pProcess;
224 break;
225 }
226 }
227 }
228
229 return (pReturn);
230}
231
232/********************************************************************
233 *
234 * DosQProcStat (16-bit) helpers
235 *
236 ********************************************************************/
237
238/*
239 * prcReport16:
240 * fill PRCPROCESS structure
241 */
242
243VOID prcReport16(PQPROCESS16 pProcess, PPRCPROCESS pprcp)
244{
245 if (pProcess)
246 {
247 PQTHREAD16 pThread;
248 int i;
249
250 DosQueryModuleName(pProcess->usHModule,
251 sizeof(pprcp->szModuleName),
252 pprcp->szModuleName);
253 // DosGetPrty(PRTYS_PROCESS, &(pprcp->usPriority), pProcess->usPID);
254
255 // sum up CPU time for process
256 for (pprcp->ulCPU = 0,
257 i = 0,
258 pThread = (PQTHREAD16)PTR(pProcess->ulThreadList, 0);
259 i < pProcess->usThreads;
260 i++, pThread++ )
261 {
262 pprcp->ulCPU += (pThread->ulSysTime + pThread->ulUserTime);
263 }
264
265 pprcp->usPID = pProcess->usPID;
266 pprcp->usParentPID = pProcess->usParentPID;
267 pprcp->usThreads = pProcess->usThreads;
268 pprcp->ulSID = pProcess->ulSID;
269 pprcp->ulSessionType = pProcess->ulSessionType;
270 pprcp->ulStatus = pProcess->ulStatus;
271 }
272}
273
274/*
275 *@@ prc16QueryProcessInfo:
276 * this searches for a given process ID (usPID) and
277 * fills a given PRCPROCESS structure with lots of
278 * information about this process.
279 * Returns FALSE upon errors, e.g. if no process
280 * of that ID is found.
281 */
282
283BOOL prc16QueryProcessInfo(PQPROCSTAT16 pps, // in: from prc16GetInfo
284 USHORT usPID, // in: PID to query
285 PPRCPROCESS pprcp) // out: process info
286{
287 BOOL rc = FALSE;
288 if (pps)
289 {
290 PQPROCESS16 pProcess;
291
292 for ( pProcess = (PQPROCESS16)PTR(pps->ulProcesses, 0);
293 pProcess->ulType != 3;
294 pProcess = (PQPROCESS16)PTR(pProcess->ulThreadList,
295 pProcess->usThreads * sizeof(QTHREAD16))
296 )
297 {
298 if (pProcess->usPID == usPID)
299 {
300 prcReport16(pProcess, pprcp);
301 rc = TRUE;
302 break;
303 }
304 }
305 }
306
307 return (rc);
308}
309
310/*
311 *@@ prc16ForEachProcess:
312 * this calls a given callback func for each running
313 * process. The callback must be a FNWP, which will be
314 * passed the following parameters for each call:
315 * -- HWND hwnd: like hwnd passed to this func
316 * -- ULONG msg: like msg passed to this func
317 * -- MPARAM mp1: like mp1 passed to this func
318 * -- PPRCPROCESS: mp2 pointer to a PRCPROCESS struct for each process
319 *
320 * This function returns the number of running processes on the
321 * system. If pfnwpCallback is NULL, only this number will be
322 * returned, so you can use this as a process counter too.
323 *
324 *@@changed V0.9.10 (2001-04-16) [pr]: now using DosAllocMem
325 */
326
327ULONG prc16ForEachProcess(PFNWP pfnwpCallback, HWND hwnd, ULONG ulMsg, MPARAM mp1)
328{
329 ULONG ulrc = 0;
330 PQPROCSTAT16 pps;
331 PQPROCESS16 pProcess;
332 PRCPROCESS prcp;
333
334 if (!DosAllocMem((PVOID*)&pps,
335 BUF_SIZE,
336 PAG_READ | PAG_WRITE | PAG_COMMIT | OBJ_TILE))
337 {
338 if (!DosQProcStatus(pps, BUF_SIZE))
339 for ( pProcess = (PQPROCESS16)PTR(pps->ulProcesses, 0);
340 pProcess->ulType != 3;
341 pProcess = (PQPROCESS16)PTR(pProcess->ulThreadList,
342 pProcess->usThreads * sizeof(QTHREAD16))
343 )
344 {
345 if (pfnwpCallback)
346 {
347 prcReport16(pProcess, &prcp);
348 (*pfnwpCallback)(hwnd, ulMsg, mp1, &prcp);
349 }
350 ulrc++;
351 }
352
353 DosFreeMem(pps);
354 }
355
356 return (ulrc);
357}
358
359/*
360 *@@ prc16QueryThreadCount:
361 * returns the total number of running threads
362 * in the given process. If pid == 0, the
363 * total thread count for the system is returned.
364 *
365 *@@changed V0.9.9 (2001-03-07) [umoeller]: added pps param
366 */
367
368ULONG prc16QueryThreadCount(PQPROCSTAT16 pps, // in: from prc16GetInfo
369 USHORT usPID)
370{
371 ULONG ulrc = 0;
372
373 if (pps)
374 {
375 if (usPID)
376 {
377 // process query:
378 PQPROCESS16 pProcess;
379 for ( pProcess = (PQPROCESS16)PTR(pps->ulProcesses, 0);
380 pProcess->ulType != 3;
381 pProcess = (PQPROCESS16)PTR(pProcess->ulThreadList,
382 pProcess->usThreads * sizeof(QTHREAD16))
383 )
384 {
385 if (pProcess->usPID == usPID)
386 {
387 ulrc = pProcess->usThreads;
388 break;
389 }
390 }
391 }
392 else
393 {
394 // global query:
395 PQGLOBAL16 pg;
396 pg = (PQGLOBAL16)PTR(pps->ulGlobal, 0);
397 ulrc = pg->ulThreads;
398 }
399 }
400
401 return (ulrc);
402}
403
404/*
405 *@@ prc16QueryThreadInfo:
406 * this searches for a given thread in a given process
407 * and fills a given PRCTHREAD structure with lots of
408 * information about that thread.
409 *
410 * Returns FALSE upon errors.
411 *
412 * Note: This function loops thru all processes which
413 * are currently running and is therefore not terribly
414 * fast. Use economically.
415 *
416 *@@changed V0.9.9 (2001-03-07) [umoeller]: added pps param
417 */
418
419BOOL prc16QueryThreadInfo(PQPROCSTAT16 pps, // in: from prc16GetInfo
420 USHORT usPID,
421 USHORT usTID,
422 PPRCTHREAD pprct)
423{
424 BOOL brc = FALSE;
425 if (pps)
426 {
427 PQPROCESS16 pProcess;
428
429 // find process:
430 for ( pProcess = (PQPROCESS16)PTR(pps->ulProcesses, 0);
431 pProcess->ulType != 3;
432 pProcess = (PQPROCESS16)PTR(pProcess->ulThreadList,
433 pProcess->usThreads * sizeof(QTHREAD16))
434 )
435 {
436 if (pProcess->usPID == usPID)
437 {
438 PQTHREAD16 pThread;
439 int i;
440 // process found: find thread
441 for ( i = 0, pThread = (PQTHREAD16)PTR(pProcess->ulThreadList, 0);
442 i < pProcess->usThreads;
443 i++, pThread++ )
444 {
445 if (pThread->usTID == usTID)
446 {
447 // thread found:
448 pprct->usTID = pThread->usTID;
449 pprct->usThreadSlotID = pThread->usThreadSlotID;
450 pprct->ulBlockID = pThread->ulBlockID;
451 pprct->ulPriority = pThread->ulPriority;
452 pprct->ulSysTime = pThread->ulSysTime;
453 pprct->ulUserTime = pThread->ulUserTime;
454 pprct->ucStatus = pThread->ucStatus;
455
456 brc = TRUE;
457
458 break; // thread-for loop
459 }
460 } // end for thread
461 break; // process-for loop
462 }
463 } // end for process
464 }
465
466 return brc;
467}
468
469/*
470 *@@ prcQueryPriority:
471 * shortcut to prc16QueryThreadInfo if you want the priority only.
472 *
473 * Returns -1 upon errors.
474 *
475 * Note: This function loops thru all processes which
476 * are currently running and is therefore not terribly
477 * fast. Use economically.
478 *
479 *@@changed V0.9.9 (2001-03-07) [umoeller]: added pps param
480 */
481
482ULONG prc16QueryThreadPriority(PQPROCSTAT16 pps, // in: from prc16GetInfo
483 USHORT usPID,
484 USHORT usTID)
485{
486 PRCTHREAD prct;
487 ULONG ulrc = -1;
488 if (prc16QueryThreadInfo(pps, usPID, usTID, &prct))
489 ulrc = prct.ulPriority;
490 return (ulrc);
491}
492
493/*
494 *@@category: Helpers\Control program helpers\Process status\32-bit DosQuerySysState
495 */
496
497/********************************************************************
498 *
499 * DosQuerySysState (32-bit) interface
500 *
501 ********************************************************************/
502
503/*
504 *@@ prc32GetInfo:
505 * nifty interface to DosQuerySysState,
506 * the 32-bit version of DosQProcStat.
507 * This returns the head of a newly
508 * allocated buffer which has plenty
509 * of pointers for subsequent browing.
510 *
511 * Use prc32FreeInfo to free the buffer.
512 *
513 *@@added V0.9.1 (2000-02-12) [umoeller]
514 *@@changed V0.9.3 (2000-05-01) [umoeller]: now using DosAllocMem
515 *@@changed V0.9.10 (2001-04-08) [umoeller]: fixed second QuerySysState param
516 */
517
518PQTOPLEVEL32 prc32GetInfo(APIRET *parc) // out: error, ptr can be NULL
519{
520 #define BUFSIZE (1024 * 1024) // 1 meg
521
522 PCHAR pBuf = NULL; // (PCHAR)malloc(BUFSIZE);
523
524 if (DosAllocMem((PVOID*)&pBuf,
525 BUFSIZE,
526 PAG_READ | PAG_WRITE | PAG_COMMIT | OBJ_TILE)
527 == NO_ERROR)
528 if (pBuf)
529 {
530 APIRET arc = DosQuerySysState(QS32_SUPPORTED,
531 QS32_SUPPORTED, // this was missing
532 // V0.9.10 (2001-04-08) [umoeller]
533 0, 0,
534 (PCHAR)pBuf,
535 BUFSIZE);
536 if (parc)
537 *parc = arc;
538
539 if (arc == NO_ERROR)
540 return ((PQTOPLEVEL32)pBuf);
541 else
542 DosFreeMem(pBuf);
543 }
544
545 return NULL;
546}
547
548/*
549 *@@ prc32FreeInfo:
550 * frees the memory allocated by prc32GetInfo.
551 *
552 *@@added V0.9.1 (2000-02-12) [umoeller]
553 *@@changed V0.9.3 (2000-05-01) [umoeller]: now using DosFreeMem
554 */
555
556VOID prc32FreeInfo(PQTOPLEVEL32 pInfo)
557{
558 DosFreeMem(pInfo);
559}
560
561/*
562 *@@ prc32FindProcessFromName:
563 *
564 *@@added V0.9.2 (2000-03-05) [umoeller]
565 */
566
567PQPROCESS32 prc32FindProcessFromName(PQTOPLEVEL32 pInfo,
568 const char *pcszName) // in: e.g. "pmshell.exe"
569{
570 PQPROCESS32 pProcThis = pInfo->pProcessData;
571 while (pProcThis && pProcThis->ulRecType == 1)
572 {
573 int i;
574 PQTHREAD32 t = pProcThis->pThreads;
575 PQMODULE32 pModule;
576
577 if (pModule = prc32FindModule(pInfo,
578 pProcThis->usHModule))
579 {
580 // the module name is fully qualified, so find the
581 // file name (after the last backslash)
582 if (pModule->pcName)
583 {
584 PSZ pLastBackslash;
585 if (pLastBackslash = strrchr(pModule->pcName, '\\'))
586 // found:
587 if (stricmp(pLastBackslash + 1, pcszName) == 0)
588 // matches:
589 break;
590 }
591 }
592
593 // for next process, skip the threads info;
594 // the next process block comes after the
595 // threads
596 for (i=0;
597 i < pProcThis->usThreadCount;
598 i++,t++)
599 ;
600
601 pProcThis = (PQPROCESS32)t;
602 }
603
604 if (pProcThis->ulRecType == 1)
605 return (pProcThis);
606 else
607 return NULL;
608}
609
610/*
611 *@@ prc32FindProcessFromPID:
612 *
613 *@@added V0.9.21 (2002-08-12) [umoeller]
614 */
615
616PQPROCESS32 prc32FindProcessFromPID(PQTOPLEVEL32 pInfo,
617 ULONG pid)
618{
619 PQPROCESS32 pProcThis = pInfo->pProcessData;
620 while (pProcThis && pProcThis->ulRecType == 1)
621 {
622 int i;
623 PQTHREAD32 t = pProcThis->pThreads;
624
625 if (pProcThis->usPID == pid)
626 return pProcThis;
627
628 // for next process, skip the threads info;
629 // the next process block comes after the
630 // threads
631 for (i=0;
632 i < pProcThis->usThreadCount;
633 i++, t++)
634 ;
635
636 pProcThis = (PQPROCESS32)t;
637 }
638
639 return NULL;
640}
641
642/*
643 *@@ prc32FindSem16:
644 * attempts to find the specified 16-bit semaphore
645 * in the specified info buffer.
646 *
647 * The return value points into the pInfo buffer.
648 * Returns NULL if not found.
649 *
650 *@@added V0.9.1 (2000-02-12) [umoeller]
651 */
652
653PQS32SEM16 prc32FindSem16(PQTOPLEVEL32 pInfo, // in: as returned by prc32GetInfo
654 USHORT usSemID) // in: as in QPROCESS32.pausSem16
655{
656 PQS32SEM16HEAD pSemHead = pInfo->pSem16Data;
657 PQS32SEM16 // pSemThis = &pSemData->sema;
658 pSemThis = &pSemHead->Sem16Rec;
659 ULONG i = 0;
660
661 while (pSemThis)
662 {
663 if (i == usSemID)
664 return (pSemThis);
665
666 i++;
667 pSemThis = pSemThis->pNext;
668 }
669
670 return NULL;
671}
672
673/*
674 *@@ prc32FindSem32:
675 * attempts to find the specified 32-bit semaphore
676 * in the specified info buffer. This might fail
677 * because the data isn't always complete.
678 *
679 * The return value points into the pInfo buffer.
680 * Returns NULL if not found.
681 *
682 *@@added V0.9.1 (2000-02-12) [umoeller]
683 */
684
685PQS32SEM32 prc32FindSem32(PQTOPLEVEL32 pInfo, // in: as returned by prc32GetInfo
686 USHORT usSemID) // in: as in QPROCESS32.pausSem16
687{
688 // PQSEM32STRUC32 pSemThis = pInfo->pSem32Data;
689
690 /* while (pSemThis)
691 {
692 if (pSemThis->usIndex == usSemID)
693 return (pSemThis);
694
695 pSemThis = pSemThis->pNext;
696 } */
697
698 return NULL;
699}
700
701/*
702 *@@ prc32FindShrMem:
703 * attempts to find the specified shared memory
704 * block description.
705 *
706 * The return value points into the pInfo buffer.
707 * Returns NULL if not found.
708 *
709 *@@added V0.9.1 (2000-02-12) [umoeller]
710 */
711
712PQSHRMEM32 prc32FindShrMem(PQTOPLEVEL32 pInfo, // in: as returned by prc32GetInfo
713 USHORT usShrMemID) // in: as in QPROCESS32.pausShrMems
714{
715 PQSHRMEM32 pShrMem = pInfo->pShrMemData;
716 while (pShrMem)
717 {
718 if (pShrMem->usHandle == usShrMemID)
719 return (pShrMem);
720 pShrMem = pShrMem->pNext;
721 }
722
723 return NULL;
724}
725
726/*
727 *@@ prc32FindModule:
728 * attempts to find the specified module description.
729 *
730 * The return value points into the pInfo buffer.
731 * Returns NULL if not found.
732 *
733 *@@added V0.9.1 (2000-02-12) [umoeller]
734 */
735
736PQMODULE32 prc32FindModule(PQTOPLEVEL32 pInfo, // in: as returned by prc32GetInfo
737 USHORT usHModule)
738{
739 PQMODULE32 pModule = pInfo->pModuleData;
740 while (pModule)
741 {
742 if (pModule->usHModule == usHModule)
743 return pModule;
744
745 pModule = pModule->pNext;
746 }
747
748 return NULL;
749}
750
751/*
752 *@@ prc32FindFileData:
753 *
754 *
755 *@@added V0.9.1 (2000-02-12) [umoeller]
756 */
757
758PQFILEDATA32 prc32FindFileData(PQTOPLEVEL32 pInfo, // in: as returned by prc32GetInfo
759 USHORT usFileID) // in: as in QPROCESS32.pausFds
760{
761 PQFILEDATA32 pFile = pInfo->pFileData;
762 while ( (pFile)
763 && (pFile->ulRecType == 8) // this is necessary, we'll crash otherwise!!
764 )
765 {
766 ULONG ul;
767 // for some reason, there is an array in the file struct,
768 // so search the array for the SFN
769 for (ul = 0;
770 ul < pFile->ulCFiles;
771 ul++)
772 {
773 if (pFile->paFiles[ul].usSFN == usFileID)
774 return (pFile);
775 }
776
777 pFile = pFile->pNext;
778 }
779
780 return NULL;
781}
782
783
Note: See TracBrowser for help on using the repository browser.