00042                    :
00043 
00044     This routine returns 
the address of 
the routine that called 
the routine
00045     that called 
this routine, and 
the routine that called 
the routine that
00046     called 
this routine. For example, 
if A called B called C which called
00047     
this routine, 
the return addresses in 
A and B would be returned.
00048 
00049 Arguments:
00050 
00051     CallersPc - Supplies a pointer to a variable that receives 
the address
00052         of 
the caller of 
the caller of 
this routine (B).
00053 
00054     CallersCallersPc - Supplies a pointer to a variable that receives 
the
00055         address of 
the caller of 
the caller of 
the caller of 
this routine
00056         (
A).
00057 
00058 Return Value:
00059 
00060     None.
00061 
00062 Note:
00063 
00064     If either of 
the calling stack frames exceeds 
the limits of 
the stack,
00065     they are set to 
NULL.
00066 
00067 --*/
00068 
00069 {
00070 
00071     CONTEXT ContextRecord;
00072     ULONG EstablisherFrame;
00073     PRUNTIME_FUNCTION FunctionEntry;
00074     BOOLEAN InFunction;
00075     ULONG NextPc;
00076     ULONG HighLimit, LowLimit;
00077 
00078     
00079     
00080     
00081     
00082 
00083     *CallersPc = 
NULL;
00084     *CallersCallersPc = 
NULL;
00085 
00086     
00087     
00088     
00089 
00090     RtlCaptureContext(&ContextRecord);
00091     NextPc = (ULONG)ContextRecord.XIntRa;
00092 
00093     
00094     
00095     
00096 
00097     
RtlpGetStackLimits(&LowLimit, &HighLimit);
00098 
00099     
00100     
00101     
00102 
00103     FunctionEntry = 
RtlLookupFunctionEntry(NextPc);
00104     
if (FunctionEntry != 
NULL) {
00105 
00106         
00107         
00108         
00109         
00110 
00111         NextPc = 
RtlVirtualUnwind(NextPc | 1,
00112                                   FunctionEntry,
00113                                   &ContextRecord,
00114                                   &InFunction,
00115                                   &EstablisherFrame,
00116                                   NULL);
00117 
00118         
00119         
00120         
00121 
00122         FunctionEntry = 
RtlLookupFunctionEntry(NextPc);
00123         
if ((FunctionEntry != 
NULL) && ((ULONG)ContextRecord.XIntSp < HighLimit)) {
00124 
00125             
00126             
00127             
00128             
00129             
00130 
00131             NextPc = 
RtlVirtualUnwind(NextPc | 1,
00132                                       FunctionEntry,
00133                                       &ContextRecord,
00134                                       &InFunction,
00135                                       &EstablisherFrame,
00136                                       NULL);
00137 
00138             *CallersPc = (PVOID)NextPc;
00139 
00140             
00141             
00142             
00143             
00144 
00145             FunctionEntry = 
RtlLookupFunctionEntry(NextPc);
00146             
if ((FunctionEntry != 
NULL) && ((ULONG)ContextRecord.XIntSp < HighLimit)) {
00147 
00148                 
00149                 
00150                 
00151                 
00152                 
00153                 
00154 
00155                 NextPc = 
RtlVirtualUnwind(NextPc | 1,
00156                                           FunctionEntry,
00157                                           &ContextRecord,
00158                                           &InFunction,
00159                                           &EstablisherFrame,
00160                                           NULL);
00161 
00162                 *CallersCallersPc = (PVOID)NextPc;
00163             }
00164         }
00165     }
00166 
00167     
return;
00168 }