pfnCallBack | The flat address of the callback function you want the Shell VxD to call when an appy time event occurs. The function will receive two parameters, dwRefData and dwFlags which are exactly identical to the two parameters you passed to _SHELL_CallAtAppyTime. Note that Shell VxD will call your callback function with C Calling sequence. In short, you have to define your callback function like this: BeginProc OnAppyTime, CCALL, PUBLIC ArgVar dwRefData,DWORD ; declare argument name and type ArgVar dwFlags, DWORD EnterProc <Your code here> LeaveProc Return EndProc OnAppyTime |
dwRefData | Reference data you want Shell VxD to pass to your callback function. It can be anything you want. |
dwFlags | Event flags. Can be one of the following values: CAAFL_RING0 Ring zero event. CAAFL_TIMEOUT Time out the event after the duration specified by dwTimeout. Simply put, if you want to wait for the appy time event for some period only, use CAAFL_TIMEOUT flag. If you want to wait indefinitely for the appy time event, use NULL. I don't know what CAAFL_RING0 actually does. |
dwTimeout | The period of time the VxD wants to wait for the appy time event to occur. I can't find any info about the time unit used with this argument. |
This service is asynchronous, meaning that it returns immediately after registering your callback function for the appy time event. If this service call is successful, it returns the application time event handle in eax. If it fails, eax contains 0. You can cancel the appy time registration by calling on _SHELL_CancelAppyTimeEvent which takes only one parameter, the appy time event handle returned by _SHELL_CallAtAppyTime. To be on the safe side, prior to calling _SHELL_CallAtAppyTime, you should check the system if appy time event will be available. For example, what if you register for appy time event while the system is shutting down? Your VxD's callback will never be called! You can query the system wheter appy time event will be available by calling _SHELL_QueryAppyTimeAvailable. This service takes no parameter. It returns 0 in eax if appy time will not be available, i.e. the system is closing down or the message server got GP faults. This service doesn't tell you that now is the appy time: it only tells you that there may be appy time events. In short, if you want to play safe, call _SHELL_QueryAppyTimeAvailable first and if it returns a nonzero value in eax, you can proceed to call _SHELL_CallAtAppyTime.
shex_dwTotalSize | The size in bytes of SHEXPACKET structure plus the optional parameter, rgchBaggage, which immediately follows this structure. I'll describe what rgchBaggage shortly. |
shex_dwSize | The size in bytes of SHEXPACKET structure, not counting rgchBaggage. Combined with shex_dwTotalSize above, the SHELL VxD can calculate the size of rgchBaggage which is of arbitrary length. |
shex_ibOp | The operation you want to perform. If you specify 0, it means you want to open the file. If the file is an executable one, it executes it. If you want to perform other operation, you must specify the name of the operation somewhere in rgchBaggage and this field must contain the distance in bytes from the start of this SHEXPACKET structure to the first character of the ASCIIZ string that specifies the name of the operation you want to perform. The size of SHEXPACKET is 32 bytes. If the operation string immediately follows the SHEXPACKET structure, the value in shex_ibOp MUST be 32. As to the list of the operations you can perform, check ShellExecute. There are three operations defined, "open", "print" and "explore". |
shex_ibFile | The relative distance from the start of this structure to the ASCIIZ string that is the name of the file you want to send to ShellExecute, just like shex_ibOp. |
shex_ibParams | The optional parameters you want to pass to the file specified in shex_ibFile. If the file is a document or you don't want to pass any parameter to it, use 0. If you want to pass some parameters to the file, put the parameter string somewhere after this structure and put the relative distance from the start of this structure to the string in this field. In short, just like shex_ibOp and shex_ibFile. |
shex_ibDir | The working directory. Specify 0 if you want to use the Windows directory else you can specify your preferred directory string somewhere after this structure and put the relative distance between the start of this structure and the directory string in this field. |
shex_dwReserved | As the name implied, it's reserved. Don't mess with it. |
shex_nCmdShow | How the application window should be shown. It's one of the value you normally pass to ShowWindow, ie. the SW_XXXX value. Look up those values in windows.inc. |
All members are DWORDs in size. Now where is that rgchBaggage member I promised I would describe? It's a little difficult to explain. rgchBaggage is a member of SHEXPACKET structure but it cannot be included into the structure definition because its size is arbitrary. Check shell.inc, you'd see that rgchBaggage is not defined in SHEXPACKET yet the Windows 9x DDK documentation asserts that it's a member of SHEXPACKET. What's rgchBaggage? It's simply an array of ASCIIZ strings that follows SHEXPACKET structure. Within this array, you can put the name of the operation you want to perform on the file, the name of the file, the parameters you want to pass to the file and the working directory. SHELL VxD obtains the offset of the string in rgchBaggage by adding the relative distance between the SHEXPACKET structure to the first byte of the string to the flat offset of the SHEXPACKET. For example, if the SHEXPACKET structure begins at 60000h, and the string immediately follows the structure, the distance between the structure and the string is the size of the structure itself, 32 bytes (20h). So Shell VxD knows that the string is located at address 60020h.
VxDName TEXTEQU <VXDEXEC> ControlName TEXTEQU <VXDEXEC_Control> VxDMajorVersion TEXTEQU <1> VxDMinorVersion TEXTEQU <0>
VxD_STATIC_DATA_SEG VxD_STATIC_DATA_ENDS
VXD_LOCKED_CODE_SEG ;---------------------------------------------------------------------------- ; Remember: The name of the vxd MUST be uppercase else it won't work/unload ;---------------------------------------------------------------------------- DECLARE_VIRTUAL_DEVICE %VxDName,%VxDMajorVersion,%VxDMinorVersion, %ControlName,UNDEFINED_DEVICE_ID,UNDEFINED_INIT_ORDER
Begin_control_dispatch %VxDName Control_Dispatch W32_DEVICEIOCONTROL, OnDeviceIoControl End_control_dispatch %VxDName
BeginProc OnDeviceIoControl assume esi:ptr DIOCParams .if [esi].dwIoControlCode==1 VxDCall _SHELL_CallAtAppyTime,<<OFFSET32 OnAppyTime>,0,0,0> .endif xor eax,eax ret EndProc OnDeviceIoControl VXD_LOCKED_CODE_ENDS
VXD_PAGEABLE_CODE_SEG BeginProc OnAppyTime, CCALL ArgVar RefData,DWORD ArgVar TheFlag,DWORD EnterProc mov File.shex_dwTotalSize,sizeof SHEXPACKET add File.shex_dwTotalSize,sizeof EXEName mov File.shex_dwSize,sizeof SHEXPACKET mov File.shex_ibOp,0 mov File.shex_ibFile,sizeof SHEXPACKET mov File.shex_ibParams,0 mov File.shex_ibDir,0 mov File.shex_dwReserved,0 mov File.shex_nCmdShow,1 VxDCall _SHELL_ShellExecute, <OFFSET32 File> LeaveProc Return EndProc OnAppyTime VXD_PAGEABLE_CODE_ENDS
VXD_PAGEABLE_DATA_SEG File SHEXPACKET <> EXEName db "calc.exe",0 VXD_PAGEABLE_DATA_ENDS
end