test: callback.c Source File

Main Page | Class Hierarchy | Class List | File List | Class Members | File Members

# callback.c

Go to the documentation of this file.

    00001 /*++
    00002
    00003 Copyright (c) 1994  Microsoft Corporation
    00004
    00005 Module Name:
    00006
    00007     callback.c
    00008
    00009 Abstract:
    00010
    00011     This module implements user mode call back services.
    00012
    00013 Author:
    00014
    00015     David N. Cutler (davec) 29-Oct-1994
    00016
    00017 Environment:
    00018
    00019     Kernel mode only.
    00020
    00021 Revision History:
    00022
    00023 --*/
    00024
    00025 #include "ki.h"
    00026
    00027 NTSTATUS
    00028 KeUserModeCallback (
    00029     IN ULONG ApiNumber,
    00030     IN PVOID InputBuffer,
    00031     IN ULONG InputLength,
    00032     OUT PVOID *OutputBuffer,
    00033     IN PULONG OutputLength
    00034     )
    00035
    00036 /*++
    00037
    00038 Routine Description:
    00039
    00040     This function call out from kernel mode to a user mode function.
    00041
    00042 Arguments:
    00043
    00044     ApiNumber - Supplies the API number.
    00045
    00046     InputBuffer - Supplies a pointer to a structure that is copied
    00047         to the user stack.
    00048
    00049     InputLength - Supplies the length of the input structure.
    00050
    00051     Outputbuffer - Supplies a pointer to a variable that receives
    00052         the address of the output buffer.
    00053
    00054     Outputlength - Supplies a pointer to a variable that receives
    00055         the length of the output buffer.
    00056
    00057 Return Value:
    00058
    00059     If the callout cannot be executed, then an error status is
    00060     returned. Otherwise, the status returned by the callback function
    00061     is returned.
    00062
    00063 --*/
    00064
    00065 {
    00066
    00067     ULONG Length;
    00068     ULONG NewStack;
    00069     ULONG OldStack;
    00070     NTSTATUS Status;
    00071     PULONG UserStack;
    00072     PVOID ValueBuffer;
    00073     ULONG ValueLength;
    00074     PEXCEPTION_REGISTRATION_RECORD ExceptionList;
    00075     PTEB Teb;
    00076
    00077     ASSERT(KeGetPreviousMode() == UserMode);
    00078
    00079     //
    00080     // Get the user mode stack pointer and attempt to copy input buffer
    00081     // to the user stack.
    00082     //
    00083
    00084     UserStack = KiGetUserModeStackAddress();
    00085     OldStack = *UserStack;
    00086     try {
    00087
    00088         //
    00089         // Compute new user mode stack address, probe for writability,
    00090         // and copy the input buffer to the user stack.
    00091         //
    00092
    00093         Length =  (InputLength + sizeof(CHAR) - 1) & ~(sizeof(CHAR) - 1);
    00094         NewStack = OldStack - Length;
    00095         ProbeForWrite((PCHAR)(NewStack - 16), Length + 16, sizeof(CHAR));
    00096         RtlCopyMemory((PVOID)NewStack, InputBuffer, Length);
    00097
    00098         //
    00099         // Push arguments onto user stack.
    00100         //
    00101
    00102         *(PULONG)(NewStack - 4) = (ULONG)InputLength;
    00103         *(PULONG)(NewStack - 8) = (ULONG)NewStack;
    00104         *(PULONG)(NewStack - 12) = ApiNumber;
    00105         *(PULONG)(NewStack - 16) = 0;
    00106         NewStack -= 16;
    00107
    00108         //
    00109         // Save the exception list in case another handler is defined during
    00110         // the callout.
    00111         //
    00112
    00113         Teb = (PTEB)KeGetCurrentThread()->Teb;
    00114         ExceptionList = Teb->NtTib.ExceptionList;
    00115
    00116         //
    00117         // Call user mode.
    00118         //
    00119
    00120         *UserStack = NewStack;
    00121         Status = KiCallUserMode(OutputBuffer, OutputLength);
    00122
    00123         //
    00124         // Restore exception list.
    00125         //
    00126
    00127         Teb->NtTib.ExceptionList = ExceptionList;
    00128
    00129     //
    00130     // If an exception occurs during the probe of the user stack, then
    00131     // always handle the exception and return the exception code as the
    00132     // status value.
    00133     //
    00134
    00135     } except (EXCEPTION_EXECUTE_HANDLER) {
    00136         return GetExceptionCode();
    00137     }
    00138
    00139     //
    00140     // When returning from user mode, any drawing done to the GDI TEB
    00141     // batch must be flushed.
    00142     //
    00143
    00144     if (Teb->GdiBatchCount > 0) {
    00145
    00146         //
    00147         // call GDI batch flush routine
    00148         //
    00149
    00150         *UserStack -= 256;
    00151         KeGdiFlushUserBatch();
    00152     }
    00153
    00154     *UserStack = OldStack;
    00155     return Status;
    00156 }
    00157
    00158 NTSTATUS
    00159 NtW32Call (
    00160     IN ULONG ApiNumber,
    00161     IN PVOID InputBuffer,
    00162     IN ULONG InputLength,
    00163     OUT PVOID *OutputBuffer,
    00164     OUT PULONG OutputLength
    00165     )
    00166
    00167 /*++
    00168
    00169 Routine Description:
    00170
    00171     This function calls a W32 function.
    00172
    00173 Arguments:
    00174
    00175     ApiNumber - Supplies the API number.
    00176
    00177     InputBuffer - Supplies a pointer to a structure that is copied to
    00178         the user stack.
    00179
    00180     InputLength - Supplies the length of the input structure.
    00181
    00182     Outputbuffer - Supplies a pointer to a variable that recevies the
    00183         output buffer address.
    00184
    00185     Outputlength - Supplies a pointer to a variable that recevies the
    00186         output buffer length.
    00187
    00188 Return Value:
    00189
    00190     TBS.
    00191
    00192 --*/
    00193
    00194 {
    00195
    00196     PVOID ValueBuffer;
    00197     ULONG ValueLength;
    00198     NTSTATUS Status;
    00199
    00200     ASSERT(KeGetPreviousMode() == UserMode);
    00201
    00202     //
    00203     // If the current thread is not a GUI thread, then fail the service
    00204     // since the thread does not have a large stack.
    00205     //
    00206
    00207     if (KeGetCurrentThread()->Win32Thread == (PVOID)&KeServiceDescriptorTable[0]) {
    00208         return STATUS_NOT_IMPLEMENTED;
    00209     }
    00210
    00211     //
    00212     // Probe the output buffer address and length for writeability.
    00213     //
    00214
    00215     try {
    00216         ProbeForWriteUlong((PULONG)OutputBuffer);
    00217         ProbeForWriteUlong(OutputLength);
    00218
    00219     //
    00220     // If an exception occurs during the probe of the output buffer or
    00221     // length, then always handle the exception and return the exception
    00222     // code as the status value.
    00223     //
    00224
    00225     } except(EXCEPTION_EXECUTE_HANDLER) {
    00226         return GetExceptionCode();
    00227     }
    00228
    00229     //
    00230     // Call out to user mode specifying the input buffer and API number.
    00231     //
    00232
    00233     Status = KeUserModeCallback(ApiNumber,
    00234                                 InputBuffer,
    00235                                 InputLength,
    00236                                 &ValueBuffer,
    00237                                 &ValueLength);
    00238
    00239     //
    00240     // If the callout is successful, then the output buffer address and
    00241     // length.
    00242     //
    00243
    00244     if (NT_SUCCESS(Status)) {
    00245         try {
    00246             *OutputBuffer = ValueBuffer;
    00247             *OutputLength = ValueLength;
    00248
    00249         } except(EXCEPTION_EXECUTE_HANDLER) {
    00250         }
    00251     }
    00252
    00253     return Status;
    00254 }