Monitoring Files

What are monitoring files ?

Monitoring files are text files containing functions descriptions.
Each function specified in monitoring file will be monitored when you load the monitoring file with WinAPIOverride.
(see Loading Monitoring files and Overriding dll)

Use Monitoring File Builder application to generate monitoring files for an application or dll

To get an API definition best ways are to use MSDN and next microsoft visual c++ SDK headers.
Speedest way in Visual Studio is to enter the func name,do right click, and next hit "Go to Definition"

Just copy definition, you can let keywords like const, struct,... (see Auto Removed Keywords)

Examples of monitoring files can be found in the "Monitoring Files" directory

  - Monitoring Files Automatic Generation (for dll, exe, COM, ActiveX,.NET or from debug or .map files)
  - Monitor all api call done by an exe


  - Basic Syntax (dll exports, exe internal functions, dll internal functions)
  - Calling Convention
  - Monitoring Direction

  - Structure management / User Types
  - Defines management
  - Advanced Syntax

        - Parameter Options
               Parameter Size
               Parameter Size : 32 / 64 bit compatibility
               Pointers passed by reference / Pointers to array / Pointers to string
               Parameters User Define
               Parameter Conditional Logging

        - Return Options
               Return Pointer
               Large Return
               Return User Define
               Return Conditional Logging
               Call Success Conditional Logging

        - Conditional Logging
               Parameter Conditional Logging
               Return Conditional Logging
               Call Success Conditional Logging

        - Breaking Options
               Breaking Time (Before or/and After Call)
               Parameter Conditional Breaking
               Return Conditional Breaking
               Success/Failure Conditional Breaking
               Logging after breaking (logs take into account changes done on registers or parameters from the break dialog)

        - Failure Options

        - Other Options
               Install a hook on a function pointer
               Install a hook on a label or inside function body
               Bypass module filtering for a function (usefull for callbacks)
               Changing the display name of a function
               Specify if function is not using stack shadow space (x64 only for pure asm functions not respecting ABI)

  - Auto Removed keywords
  - Particular cases : function pointer and "..."
  - Fully Supported Parameters


  - COM/ActiveX Monitoring Files
  - .NET Monitoring Files



Basic Syntax

This syntax with Monitoring Direction allows you to do basic monitoring.
If you want to put filters on parameter values, break process before or after the function call, or specify failure value, refer to the advanced syntax

All in [ ] is optional

   - Commented lines : all lines begining with ";" will be considered as comments

   - API or dll function :
LibraryName| [ReturnType] FuncName( ParamType [paramName] ) [;]

Examples
KERNEL32.DLL|HMODULE LoadLibraryW(PWSTR)
KERNEL32.DLL|LoadLibraryExA(LPCSTR lpFileName,HANDLE hFile,DWORD dwFlags);


   - Monitoring ordinal only dll exported function :
DLL_ORDINAL@0xOrdinal@DllName| [ReturnType] FuncName(ParamType [paramName]) [;]
Example
DLL_ORDINAL@0x1dd@USER32.DLL|int MessageBoxA(HWND hWnd,LPCSTR lpText,LPCSTR lpCaption,UINT uType);

   - Monitoring function inside an exe :
EXE_INTERNAL@0xHexAddress| [ReturnType] FuncName(ParamType [paramName]) [;]
EXE_INTERNAL_RVA@0xHexAddress| [ReturnType] FuncName(ParamType [paramName]) [;]

Address provided to EXE_INTERNAL is the Virtual Address.
If you want to use Relative Virtual Address, use EXE_INTERNAL_RVA.
Since Windows Vista and exe base address randomization protection, you should better use the _RVA version with the relative virtual address

Example
EXE_INTERNAL@0x401000|Add(int x,int y)
EXE_INTERNAL_RVA@0x001000|Add(int x,int y)

Notice : to find the address of a function inside an exe refer too Faq: How to find function address



   - Monitoring function relative from dll base address :
DLL_INTERNAL@0xHexAddress@DllName| [ReturnType] FuncName(ParamType [paramName]) [;]
HexAddress is the relative address from dll base address of process memory : you don't need to care if dll is rebased or not

Example
  On some systems MessageBoxA is at the address 0x2e824 in user32.dll so in this case
DLL_INTERNAL@0x2e824@user32.dll| int MessageBoxA(HWND,LPSTR,LPSTR,UINT)
Notice : it's a quite bad example as MessageBoxA is an exported function. Use DLL_INTERNAL@0x only for not exported functions


   - Monitoring function pointer inside an exe :
This new keyword has been introduced to securely hook function pointers.
It can be use by the way to monitor some Virtual Function Table (VTBL) items
(refer to your favorite C++ documentation for VTBL description)
EXE_INTERNAL_POINTER@0xHexAddress| [ReturnType] FuncName(ParamType [paramName]) [;]
EXE_INTERNAL_RVA_POINTER@0xRelativeHexAddress| [ReturnType] FuncName(ParamType [paramName]) [;]

Address provided to EXE_INTERNAL_POINTER is the Virtual Address.
If you want to use Relative Virtual Address, use EXE_INTERNAL_RVA_POINTER.
Since Windows Vista and exe base address randomization protection, you should better use the _RVA version with the relative virtual address

Example
EXE_INTERNAL_POINTER@0x401000|Add(int x,int y)
EXE_INTERNAL_RVA_POINTER@0x001000|Add(int x,int y)

   - Monitoring function pointer relative from dll base address :
This new keyword has been introduced to securely hook function pointers.
It can be use by the way to monitor some Virtual Function Table (VTBL) items
(refer to your favorite C++ documentation for VTBL description)
DLL_INTERNAL_POINTER@0xHexAddress@DllName| [ReturnType] FuncName(ParamType [paramName]) [;]
HexAddress is the relative address (RVA) from dll base address of process memory : you don't need to care if dll is rebased or not

Example
DLL_INTERNAL_POINTER@0x2e824@MyDll.dll| Add(int x,int y)


Calling Convention
To specify the calling convention, just let standard function definition like
int __cdecl Function(int i,unsigned int ui)
__cdecl and __stdcall can be omitted.


Supported calling convention keywords are the following :
  - __cdecl, STDMETHODVCALLTYPE, STDAPIVCALLTYPE, STDAPIV, STDMETHODIMPV
  - __stdcall, WINAPI, STDAPI, WINOLEAPI,STDMETHODCALLTYPE, STDAPICALLTYPE, STDMETHODIMP
  - __fastcall : Microsoft fastcall : Parameters passed through ECX, EDX then by stack with Right To Left (RTL) order
  - __thiscall
  - __fastcall_borland : Borland / Embarcadero fastcall : Parameters passed through EAX, EDX, ECX then by stack with Left To Right (LTR) order (Pascal). Added in version 6.0

Monitoring direction

Monitoring direction is an extra keyword to specify when parameters should be logged.

To add it, after you function description (in the same line) add |Direction where Direction is one of the following keywords :
   - In : parameters are logged before the function call
   - Out : parameters are logged after the function call
   - InNoRet : parameters are logged before the function call and the log information are sent to WinAPIOverride before the function is called. So using this you wont get returned values nor after call registers, but it's great advantage is that log is captured even if the funtion call make the process crash.
   - InOut : InNoRet+Out : two logs are sent. One with parameters before the call and another after the function call

Notice : If no direction is specified, the default direction is "In"

Examples
msvcrt.dll|char * strcat( char *strDestination, char *strSource )|In
msvcrt.dll|strcpy( char *strDestination, char *strSource )|Out

Explanation
You want to monitor the following function call:
   strcat("To ","you");
According to the direction, results will be

Direction Monitoring Result for strcat("To ","you");
In strcat("To ","you")
Out strcat("To you","you")
InNoRet strcat("To ","you") even if your first buffer is not big enough and strcat make your process crash
InOut Two logs are produced :
strcat("To ","you") : the InNoRet part even if your first buffer is not big enough and strcat make your process crash
strcat("To you","you") : the Out part



Advanced Syntax

Notice : All options are not case sensitive, so you can put ":logvalue" instead of ":LogValue" without any trouble.

Logging options
  Description
Parameters options   
  :DataSize= Allow to Specify an amount of data in byte to log for unsopported structures.
Use this keyword for structures or types that are more than 4 bytes length.

For a struct defined by
{
DWORD dw1;
DWORD dw2;
DWORD dw3;
}Foo;
and a function func(Foo foo); as the size of Foo is 12 bytes, you can log all the foo data by using the following

Lib.dll|func(Foo foo:DataSize= 12)


User structures are fully supported, and size is computed, so if your structure is defined in "UserTypes" directory,
you don't need to specify the struct size (See User Types for more information)

 
  :PointedElementsCount= This option has the same effect as the ":PointedDataSize" option multiplied by the size of the current type

PointedElementsCount = PointedDataSize*sizeof(Type), where sizeof(Type) is auto computed according to Type definition.

By the way if you are waiting for a 7 intergers array, you can write
Lib.dll|funcArray(int* Array:PointedElementsCount=7) instead of Lib.dll|funcArray(int* Array:PointedDataSize=28)

Like the ":PointedDataSize" option, This option as all the facilities of ArgX and basic operations (+-*/)
SECURITY_STATUS WINAPI NCryptEnumAlgorithms(NCRYPT_PROV_HANDLE hProvider,DWORD dwAlgOperations,DWORD *pdwAlgCount,NCryptAlgorithmName **ppAlgList:PointerReference:ProcessorDependent:PointedElementsCount=Arg3,DWORD dwFlags);|Out
  :PointedDataSize= When parameter is a pointer, allow to specify an amount of data to log (value is in byte byte count)
Use this keyword for array,buffer or pointer to unsupported types.

With the same Foo structure and a function funcRef(Foo* pfoo)
Lib.dll|func(Foo* pfoo:PointedDataSize=12)

You can use this option for array too. By the way if you are waiting for a 7 intergers array, as sizeof(int)==4, pointed data size is 7*4=28, so you can write
Lib.dll|funcArray(int* Array:PointedDataSize=28)

Basics operations (+-*/) are supported, so you can write
Lib.dll|funcArray(int* Array:PointedDataSize=7*(4+4))

You can also specify a parameter number defining the size.
It is realy useful for all function writing or reading buffer.
Syntax is :PointedDataSize=ArgU where U is one based parameter number. By the way you can write
kernel32.dll|BOOL ReadFile( HANDLE hFile, LPVOID lpBuffer:PointedDataSize=Arg4, DWORD nNumberOfBytesToRead, LPDWORD lpNumberOfBytesRead, LPOVERLAPPED lpOverlapped)|Out

kernel32.dll|BOOL WriteFile( HANDLE hFile, LPCVOID lpBuffer:PointedDataSize=Arg3, DWORD nNumberOfBytesToWrite, LPDWORD lpNumberOfBytesWritten, LPOVERLAPPED lpOverlapped)|Out

Since version 5.3, for functions having Array and ArrayItemsCount as arguments, the ArgU has been extended so you can define a factor : you can write :PointedDataSize=ArgU*ItemSize where ItemSize is the size of a single item.

For a function passing an array of dword in first parameter, and number of item in array in second parameter,
as sizeof(DWORD)=4, we can write

Mydll.dll|void MyFunction(DWORD* ArrayOfDword:PointedDataSize=Arg2*4, SIZE_T ArrayItemsCount)

User structures are fully supported, and size is computed, so if your structure is defined in "UserTypes" directory,
you don't need to specify the struct size (See User Types for more information)

Static array are supported
Mydll.dll|void MyFunction(int iArray[2][4][5],short sArray[5])

32 / 64 bit compatibility With a view to have a single monitoring file for 32 bit and 64 bit software, as type size can be processor dependent, the following keywords have been introduced :
  :ProcessorDependent For a FOO type, when this keyword is specified,
  - the FOO64 type will be search when monitoring file is loaded into a 64 bit process
  - the FOO32 and if not found the FOO type will be searched when monitoring file is loaded into a 32 bit process
Don't forget to provide the 2 structs in your User Defines directory

Lib.dll|func(FOO* pfoo:ProcessorDependent)
will act like
Lib.dll|func(FOO64* pfoo) in a 64 bit process
and
Lib.dll|func(FOO32* pfoo) or Lib.dll|func(FOO* pfoo) in a 32 bit process

  PointerSize and RegisterSize for the ":PointedDataSize" and ":DataSize" option When using the ":PointedDataSize" of ":DataSize" option, you may will face some structures defined by
{
LPVOID Pointer;
SIZE_T Data;
DWORD dw3;
}Foo;

In such case, as sizeof(DWORD)=4, you can write

Lib.dll|func(FOO* pfoo:PointedDataSize=PointerSize+RegisterSize+4)
And if you get an array
Lib.dll|func(FOO* pfoo:PointedDataSize=Arg2*(PointerSize+RegisterSize+4), DWORD NbItems)
Pointers passed by reference / Pointers to array / Pointers to string  
  :PointerReference When functions are allocating objects, arrays or strings, you have to provide a reference to a pointer as parameter like
Lib.dll|funcAllocateArray(IN DWORD NbItems,OUT DWORD** pArray)|Out

This option do a deferencing before logging, so the content of DWORD** pArray, aka DWORD* Array will be logged instead

All other options apply to the deferenced type (aka for T**, all options applies to T*)
This is interesting for ":PointedDataSize=", ":PointedElementsCount=",...

Lib.dll|funcAllocateArray(IN DWORD NbItems,OUT DWORD** pArray:PointerReference:PointedDataSize=Arg1*4)|Out
Lib.dll|funcAllocateArray(IN DWORD NbItems,OUT DWORD** pArray:PointerReference:PointedElementsCount=Arg1)|Out
kernel32.dll|DWORD GetFullPathNameW(LPCWSTR lpFileName,DWORD nBufferLength,LPWSTR lpBuffer,LPWSTR* lpFilePart:PointerReference)|Out

This option do a single dereferencing, and don't manage multiple dimensions,
so T** is logged as a T[0]* type even if there is more dimensions.

For T** = new T*[16]; array, only T[0]* will be logged
   
Parameters User Define  
  :Define= Allow to specify a file containing define values. (See User Defines for more information)
Doing this, the detailed view will display defined flags instead of raw value.
The file name is relative path from the "UserDefines" directory

Example of results
user32.dll|int MessageBoxW( HWND hWnd, LPCWSTR lpText, LPCWSTR lpCaption, UINT uType:Define=user32.dll/MessageBox_Type.txt)
kernel32.dll|HANDLE CreateFileW( LPCWSTR lpFileName, DWORD dwDesiredAccess:Define=kernel32.dll/CreateFile_DesiredAccess.txt, DWORD dwShareMode:Define=kernel32.dll/CreateFile_ShareMode.txt, LPSECURITY_ATTRIBUTES lpSecurityAttributes, DWORD dwCreationDisposition:Define=kernel32.dll/CreateFile_CreationDisposition.txt, DWORD dwFlagsAndAttributes:Define=kernel32.dll/CreateFile_FlagsAndAttributes.txt, HANDLE hTemplateFile)|FailureIfRetValue=0xFFFFFFFF

 



 
Conditional logging options can be mixed together without troubles (they can be mixed with breaking options too)
user32.dll|ChildWindowFromPoint(HWND hWndParent:LogValue=0xd, POINT Point:LogBufferValue=C8 00 00 00 2C 01 00 00)|LogIfNullRet
Parameters Conditional Logging  
  :LogValue= Log calls only when the parameter(s) match the specified value(s).
Use this keyword for types size less than register size (4 bytes lentgh in 32bit, 8 for 64bit).

Value can be in decimal or hexadecimal
To enable log for different values, just use this option with different values
 
SendMessageA monitored only with WM_GETTEXT or EM_GETSELTEXT messages
User32.dll|SendMessageA(HWND hWnd,UINT Msg:LogValue=0xd:LogValue=0x462,WPARAM wParam,LPSTR lParam)

Conditions on multiples parameters
Lib.dll|Add(int x:LogValue=0xd:LogValue=0x462, int y:LogValue=12:LogValue=48)

  :LogBufferValue= Log calls only when the parameter(s) match the specified value(s).
Use this keyword for structures or types that are more than register size (4 bytes lentgh in 32bit, 8 for 64bit).

Take care of byte ordering for struct Point {0xC8,0x12C} is in little endian C8 00 00 00 2C 01 00 00
 
To watch only cos call when value is 2.0 , as double type is 8 bytes length, for 32bit
ntdll.dll|cos(double:LogBufferValue=0000000000000040)

To catch ChildWindowFromPoint only when Point is {0xC8,0x12C}
user32.dll|ChildWindowFromPoint(HWND hWndParent, POINT Point:LogBufferValue=C8 00 00 00 2C 01 00 00)

 
  :LogPointedValue= Log calls only when the parameter(s) match the specified pointed value(s).
Use this keyword for simple pointer, pointer to structures, or buffer.
Simple pointer : if pointed value should be 0x4 or 0x6
Lib.dll|func(int *px:LogPointedValue=04 00 00 00:LogPointedValue=06 00 00 00)

Pointer to buffer : To log all message boxes having the "Error" caption in UNICODE enter the following
USER32.DLL|MessageBoxW(HWND,LPCWSTR,LPCWSTR:LogPointedValue=4500720072006F0072000000,UINT)

Use the String Hex dialog for string to bytes buffer conversion
 
  :LogValueSignedLessOrEqual= Log calls only when the signed representation of parameter is <= at the specified value.
Lib.dll|func(int i:LogValueSignedLessOrEqual=-21)
Notice: float and double are currently not supported

  :LogValueSignedGreaterOrEqual= Log calls only when the signed representation of parameter is >= at the specified value.
Lib.dll|func(int i:LogValueSignedGreaterOrEqual=-21)
Notice: float and double are currently not supported

  :LogValueUnsignedLessOrEqual= Log calls only when the unsigned representation of parameter is <= at the specified value.
Lib.dll|func(DWORD dw:LogValueUnsignedLessOrEqual=0xfffffff7)
Notice: float and double are currently not supported

  :LogValueUnsignedGreaterOrEqual= Log calls only when the unsigned representation of parameter is >= at the specified value.
Lib.dll|func(DWORD dw:LogValueUnsignedGreaterOrEqual=0xfffffff7)
Notice: float and double are currently not supported

   
Return Conditional Logging  
  |LogIfNullRet Call is logged only if the returned value is null.
Don't work for double or floating results
Incompatible with the "InNoRet" direction spying

Lib.dll|f(int a,int b) | LogIfNullRet

  |LogIfNotNullRet Call is logged only if the returned value is not null.
Don't work for double or floating results
Incompatible with the "InNoRet" direction spying
 
Lib.dll|f(int a,int b) | LogIfNotNullRet

Call Success Conditional Logging  
  |LogOnFailure Check the failure of the function defined by Failure Options, and log the call only if function fails
Incompatible with the "InNoRet" direction spying
 
Lib.dll|f(int a,int b) | LogOnFailure

  |LogOnSuccess Check the failure of the function defined by Failure Options, and log the call only if function doesn't fail
Incompatible with the "InNoRet" direction spying
 
Lib.dll|f(int a,int b) | LogOnSuccess
   
Return Pointer
supported since 6.1
When the return value points to an array or a struct
By default you don't need to do anything, pointer to struct are automatically parsed according to your UserTypes directory content,
If struct is not defined or for arrays, you can use the |ReturnPointedDataSize= option
 
  |ReturnPointedDataSize= When return is a pointer, allow to specify an amount of data to log (value is in byte count)
Use this keyword for array,buffer or pointer to unsupported types.
Same as parameter option :PointedDataSize= for return (See :PointedDataSize= parameter option syntax for more information)

Lib.dll|f(int a,int b) | ReturnPointedDataSize=32
Lib.dll|f(int a,int b) | ReturnPointedDataSize=Arg1
Lib.dll|f(int a,int b) | ReturnPointedDataSize=Arg2*4
   
Large Return
supported since 6.0
When the size of return type is larger than the size of register (struct larger than 4 bytes for 32bit, and 8 bytes for 64bit)
This flag allow to get return content and avoid bad parameter parsing
Use these options only for direct struct or type returns (like MSG MyFunction())
Do not use these options for pointers to array, pointers to struct or pointers to class (like MSG* MyFunction())
Since v6.1, pointer to struct are automatically parsed according to your UserTypes directory content,
or you can use the |ReturnPointedDataSize= option
 
  |LargeReturnType= allow to specify a type supported by WinApiOverride or define in your "UserTypes" directory
Only for static functions (use MethodLargeReturnType for methods)
Lib.dll|f(int a,int b) | LargeReturnType=MSG
  |LargeReturnSize= allow to specify directly the size of return type
Only for static functions (use MethodLargeReturnType for methods)
Lib.dll|f(int a,int b) | |LargeReturnSize=0x40
  |LargeReturn If you are not interest by the return content, but just want a good parameter parsing
Only for static functions (use MethodLargeReturnType for methods)
Lib.dll|f(int a,int b) | LargeReturn
  |MethodLargeReturnType= allow to specify a type supported by WinApiOverride or define in your "UserTypes" directory
Lib.dll|ClassName::f(int a,int b) | MethodLargeReturnType=MSG
  |MethodLargeReturnSize= allow to specify directly the size of return type
Lib.dll|ClassName::f(int a,int b) | |MethodLargeReturnSize=0x40
  |MethodLargeReturn If you are not interest by the return content, but just want a good parameter parsing
Lib.dll|ClassName::f(int a,int b) | MethodLargeReturn
   
Return User Define
 
  |ReturnDefine= Allow to specify a file containing define values. (See User Defines for more information)
Doing this, the detailed view will display defined flags instead of raw value.
The file name is relative path from the "UserDefines" directory
This option works like the parameter :Define= option
user32.dll|int MessageBoxW( HWND hWnd, LPCWSTR lpText, LPCWSTR lpCaption, UINT uType) |ReturnDefine=user32.dll/MessageBox_Return.txt

Mixing this option with the parameter :Define= option, we get for MessageBox :
user32.dll|int MessageBoxW( HWND hWnd, LPCWSTR lpText, LPCWSTR lpCaption, UINT uType:Define=user32.dll/MessageBox_Type.txt) |ReturnDefine=user32.dll/MessageBox_Return.txt



Breaking options :

Breaking options defines when the break dialog must appears.
This dialog allows you to change parameters content and returned value, show callstack and make dump.
When the breaking dialog is displayed all threads of the process are suspended

Notice: You can mix Logging options and breaking options like
lib.dll|Add(int:LogValue=4:BreakValue=8,int:BreakPointedValue=45 20)|BreakBeforeCall|LogIfNotNullRet

  Description
General  
  |BreakBeforeCall Display the break dialog before each function call (according to parameters options)
lib.dll|Add(int,int)|BreakBeforeCall

  |BreakAfterCall Display the break dialog after each function call (according to parameters options)
lib.dll|Add(int,int)|BreakAfterCall

  |BreakBeforeAndAfterCall Display the break dialog before and after each function call (according to parameters options)
lib.dll|Add(int,int)|BreakBeforeAndAfterCall

  |DontCheckModulesFilters Allow function to bypass module filtering.
Intersting if some functions needs module filtering and other not.
lib.dll|Add(int,int)|DontCheckModulesFilters
   
Return Conditional Breaking  
  |BreakAfterCallIfNullRet Display the break dialog after function call if the return value is 0 (according to parameters options)

lib.dll|Add(int,int)|BreakAfterCallIfNullRet

  |BreakAfterCallIfNotNullRet Display the break dialog after function call if the return value is !0 (according to parameters options)
lib.dll|Add(int,int)|BreakAfterCallIfNotNullRet

  |BreakOnFailure Display the break dialog after function call if the function fails (according to parameters options) See failure options
lib.dll|Add(int,int)|BreakOnFailure

  |BreakOnSuccess Display the break dialog after function call if the function succeed (according to parameters options) See failure options
lib.dll|Add(int,int)|BreakOnSuccess
   
Parameters Conditional Breaking Must be couple with General or Return Conditional Breaking options
 
  :BreakValue= break only calls when the parameter(s) match the specified value(s).
Value can be in decimal or hexadecimal
To enable break for different values, just use this option with different values
lib.dll|Add(int:BreakValue=0x78,int)|BreakBeforeCall
lib.dll|Add(int:BreakValue=0x78:BreakValue=-7,int:BreakValue=0x45)|BreakAfterCall

  :BreakBufferValue= Break only calls when the parameter(s) match the specified value(s).
Use it for structures or types that are more than 4 bytes length
Take care of byte ordering for struct Point {0xC8,0x12C} is in little endian C8 00 00 00 2C 01 00 00
 
To break only on cos call when value is 2.0 , as double type is 8 bytes length
ntdll.dll|cos(double:BreakBufferValue=0000000000000040)|BreakBeforeCall

To break ChildWindowFromPoint only when Point is {0xC8,0x12C}
user32.dll|ChildWindowFromPoint(HWND hWndParent, POINT Point:BreakBufferValue=C8 00 00 00 2C 01 00 00)|BreakAfterCall

  :BreakPointedValue= Break only calls when the parameter(s) match the specified pointed value(s).

To break only on calls where the pointed value is 0x4 or 0x6
Lib.dll|func(int *px:BreakPointedValue=04 00 00 00:BreakPointedValue=06 00 00 00)|BreakAfterCall

You can use it to break on buffer too. To break on all message boxes having the "Error" caption in UNICODE enter the following
USER32.DLL|MessageBoxW(HWND,LPCWSTR,LPCWSTR:BreakPointedValue=4500720072006F0072000000,UINT)|BreakBeforeCall
  :BreakValueSignedLessOrEqual= Break only when the signed representation of parameter is <= at the specified value.
Lib.dll|func(int i:BreakValueSignedLessOrEqual=-21)
Notice: float and double are currently not supported

  :BreakValueSignedGreaterOrEqual= Break only when the signed representation of parameter is >= at the specified value.
Lib.dll|func(int i:BreakValueSignedGreaterOrEqual=-21)
Notice: float and double are currently not supported

  :BreakValueUnsignedLessOrEqual= Break only when the unsigned representation of parameter is <= at the specified value.
Lib.dll|func(DWORD dw:BreakValueUnsignedLessOrEqual=0xfffffff7)
Notice: float and double are currently not supported

  :BreakValueUnsignedGreaterOrEqual= Break only when the unsigned representation of parameter is >= at the specified value.
Lib.dll|func(DWORD dw:BreakValueUnsignedGreaterOrEqual=0xfffffff7)
Notice: float and double are currently not supported

   
Logging options Theses options allow you to save the log entry after you've done changes on registers or parameters with the break dialog
 
By the way if the original call is Add(4,5) and with the breaking dialog you change it to Add(7,8)
  - With these options you will log Add(7,8)
  - Without these options, you will log Add(4,5)
 
  |LogInputAfterBreak Applies to |BreakBeforeCall and |BreakBeforeAndAfterCall options coupled with In, InNotRet,InOut monitoring directions
lib.dll|Add(int,int)|In|BreakBeforeCall|LogInputAfterBreak

  |LogOutputAfterBreak Applies to |BreakAfterCall, |BreakBeforeAndAfterCall, |BreakAfterCallIfNullRet,|BreakAfterCallIfNotNullRet,
|BreakOnFailure, |BreakOnSuccess
couple with Out, InOut monitoring directions
lib.dll|Add(int,int)|Out|BreakAfterCall|LogOutputAfterBreak


Failure options :

Failure options allow you to define when function fails.
It provides 2 things :
- More precise logging or breaking conditions
- A visual return : failling call are hightlighted in the log list by a red background.


  Description
Integer return  
  |FailureIfNullRet Function fails if the returned value is 0
lib.dll|func(int a)|FailureIfNullRet
  |FailureIfNotNullRet Function fails if the returned value is !0
lib.dll|func(int a)|FailureIfNotNullRet
  |FailureIfRetValue= Allow to define one failling value
lib.dll|func(int a)|FailureIfRetValue=-1
  |FailureIfRetValue!= Allow to define one success value
lib.dll|func(int a)|FailureIfRetValue!=0x243
  |FailureIfNegativeRet Function fails if the returned value is <0
lib.dll|func(int a)|FailureIfNegativeRet
  |FailureIfPositiveRet Function fails if the returned value is >0
lib.dll|func(int a)|FailureIfPositiveRet
  |FailureIfSignedRet< Function fails if the signed returned value is < specified value
lib.dll|func(int a)|FailureIfSignedRet<32
  |FailureIfSignedRet> Function fails if the signed returned value is > specified value
lib.dll|func(int a)|FailureIfSignedRet>-12
  |FailureIfUnsignedRet<
 or |FailureIfRet<
Function fails if the unsigned returned value is < specified value
lib.dll|func(int a)|FailureIfUnsignedRet<32
lib.dll|func(int a)|FailureIfRet<0x789
  |FailureIfUnsignedRet>
 or |FailureIfRet>
Function fails if the unsigned returned value is > specified value
lib.dll|func(int a)|FailureIfUnsignedRet>0x75
lib.dll|func(int a)|FailureIfRet>0x789
   
Floating return  
  |FailureIfNullFloatingRet Function fails if the floating returned value is 0
lib.dll|func(double d)|FailureIfNullFloatingRet
  |FailureIfNotNullFloatingRet Function fails if the floating returned value is !0
lib.dll|func(double d)|FailureIfNotNullFloatingRet
  |FailureIfFloatingRetValue= Allow to define one failling floating value
lib.dll|func(double d)|FailureIfFloatingRetValue=0x243
  |FailureIfFloatingRetValue!= Allow to define one success floating value
lib.dll|func(double d)|FailureIfFloatingRetValue!=0x243
  |FailureIfFloatingNegativeRet Function fails if the floating returned value is <0
lib.dll|func(double d)|FailureIfFloatingNegativeRet
  |FailureIfFloatingPositiveRet Function fails if the floating returned value is >0
lib.dll|func(double d)|FailureIfFloatingPositiveRet
  |FailureIfFloatingRet< Function fails if the floating returned value is < specified value
lib.dll|func(double d)|FailureIfFloatingRet<0.123
  |FailureIfFloatingRet> Function fails if the floating returned value is > specified value
lib.dll|func(double d)|FailureIfFloatingRet>0.456
   
GetLastError() result  
  FailureIfLastErrorValue= Function fails if value returned by GetLastError() is equal to specified value
lib.dll|func(int a)|FailureIfLastErrorValue=0x243
  FailureIfLastErrorValue!= Function fails if value returned by GetLastError() is not equal to specified value
lib.dll|func(int a)|FailureIfLastErrorValue!=24
  FailureIfLastErrorValue< Function fails if value returned by GetLastError() is < to specified value
lib.dll|func(int a)|FailureIfLastErrorValue<24
  FailureIfLastErrorValue> Function fails if value returned by GetLastError() is > to specified value
lib.dll|func(int a)|FailureIfLastErrorValue>0x24

Only one failure value is available. That means you can't do the following
lib.dll|fonc(int,int) | FailureIfRetValue=2 | FailureIfRetValue=5

But a failure value can be associated to a GetLastError failure value. By the way you can do the following
lib.dll|func(int,int) | FailureIfNullRet | FailureIfLastErrorValue!=997
In that case the function must match the 2 failure conditions to be declared as failed

By the way for ReadFile API, as we don't want ERROR_IO_PENDING (0x3e5) to be report as a failure we can write
kernel32.dll|BOOL ReadFile( HANDLE hFile, LPVOID lpBuffer:PointedDataSize=Arg4, DWORD nNumberOfBytesToRead, LPDWORD lpNumberOfBytesRead, LPOVERLAPPED lpOverlapped)|Out|FailureIfNullRet|FailureIfLastErrorValue!=0x3e5

and the output will be the following :
Only the first call having a null return and last error !=0x3e5 is report as an error


As no particular action is done for failling calls (logs are only highlighted), fill free to use failure option as an highlighting option


Other options :

   |FunctionPointer: allows to install a hook on a function pointer (since v6.4.1)
This behaviour as the same effect as EXE_INTERNAL_RVA_POINTER, EXE_INTERNAL_POINTER, DLL_INTERNAL_POINTER, but provides an easier writing way for exported functions
lib.dll|func(int a)|FunctionPointer


   |DontHookReturnAddress: allows to install a hook on a label or inside a function body (since v6.0)
Not hooking return address, means that stack is exactly the same between original call and the hooked one, even return address is let unchanged.
The callee won't see any difference by stack crawling (by the way, this option used to bypass framework .Net stack checking for the fast .Net hooking)

As stack is not affected at all, that mean you are not forced to install hook at the begining of a function. You can install this kind of hook anywhere in the code, inside the function code itself.
As return address is not hooked, InNoRet monitoring is required and "Out" monitoring and "Post" hooks are not available (See Hooking Sequence). "InNoRet" monitoring, "Pre" hooks and overrinding are still availables.

Notice:
If you need to catch the return value, you still can do it by using two hooks with |DontHookReturnAddress option : one at the begining of function and one at the end
Keep in mind that a hook needs 5 bytes, so the best is to find a 5 bytes opcode at the end of the function (Notice : Ms compiler gives you a nice gift with the __security_check_cookie call, as a call instruction is 5 bytes length)
You don't need to take care of stack alignment : the hooking algorithm can handle aligned and unaligned stack

Let see a standard function asm code

  1. // function standard begin
  2. mov dword ptr [rsp+20h],r9d // <-- first hook can be put here
  3. mov qword ptr [rsp+18h],r8
  4. mov qword ptr [rsp+10h],rdx
  5. mov qword ptr [rsp+8],rcx
  6. push rsi
  7. push rdi
  8. sub rsp,538h
  9. // function body
  10. ...
  11. ...
  12. ...
  13. // function standard end
  14. call __security_check_cookie // <-- second hook can be put here : return value is in Rax
  15. add rsp,538h
  16. pop rdi
  17. pop rsi
  18. ret
If you require "Post" hook, use the previous technic with two "Pre" hooks. The second "Pre" hook will be in fact an equivalent of "Post" hook.


   |DontCheckModulesFilters : modules filters are not taken into account and function is always logged (since v6.0)
That means all other logs respect provided filters, but those with the "|DontCheckModulesFilters" options don't.
This can be usefull in case of callback: in this case the caller could be in kernel32 or user32 which is filtered.
lib.dll|func(int a)|DontCheckModulesFilters
   |DisplayName=PrettyFuncName where PrettyFuncName is a function prefered name.

This option allows you to change the name displayed in WinAPIOverride log list.
The exported name of dll function is sometime not understandable like for C++ functions.
So it makes analysis easier. By the way using
msvcrt.dll|??2@YAPAXI@Z(unsigned int)|DisplayName=operator new
will display operator new(45) instead of ??2@YAPAXI@Z(45)

   |NoStackShadowSpace x64 only, used for function with stack parameter which don't use shadow space. Should be reserved for specific asm function for which first stack parameter is at function entry Rsp (for standard functions, first stack parameter is at function entry Rsp + 0x20)

   ! at the begin of the line : specific for monitoring library : if line begins with !, that means it's currently disable but can be enable from monitoring library interface.
Commented definitions are unvisible from library and so can't be enabled.
Use '!' for function definition that generate lot's of call and are generaly not necessary (like the GetLastError() function),
and use ';' before definition that can't be hooked. It is usefull to let them commented, because when the Monitoring File Builder application generates a monitoring file,
it will find function definition in monitoring folder and will translate it's desactivated state for the new created monitoring files.

   |FirstBytesCanExecuteAnywhere
   |FirstBytesCanExecuteAnywhere=

Change the standard hooking way to a more powerfull hooking way.

This can be done if the first asm instructions of your function can be executed at an another location
By the way this can be done if first asm instruction are like
mov edi,edi              // 8B FF
push ebp                  // 55
mov ebp,esp            // 8B EC

As you can see this portion of code can be executed anywhere in memory.

So instead of removing hook and call original function, hook is not removed, but the begin of function is executed in another location.
The great advantage of these options is that YOU CAN'T LOOSE FUNCTION CALL.

If you don't specify a value ("|FirstBytesCanExecuteAnywhere") the size of code executed at another location is 5 bytes.

The "|FirstBytesCanExecuteAnywhere=" option allows you to specify the number of byte executed at another place.
This number must be greater than an absolute jmp instruction (5 bytes in 32 bits) .
This allows you to adjust the number of movable bytes.

By the way if the movables asm code is
push ebp                  // 55
mov ebp,esp            // 8B EC
sub esp,3D4h          // 81 EC D4 03 00 00
we can't cut it at byte 5, else the "sub esp, 3D4h " instruction is cut, and a beautifull crash will append.
But as this code can be executed anywhere and is 9 bytes, put |FirstBytesCanExecuteAnywhere=9 after the monitoring definition.
Only the 9 first bytes of the function will be executed at another address.



   |FirstBytesCanExecuteAnywhereWithRelativeAddressChange
   |FirstBytesCanExecuteAnywhereWithRelativeAddressChange=

Same as |FirstBytesCanExecuteAnywhere option,but specifying that a 32 bit relative address needs to be changed.
The relative address to modify must be at the last 4 bytes.

By the way
jmp (relative) 0x3D4      // E9 4D 03 00 00
Ok, the instruction is 5 bytes length, so a hook can be installed, but if we execute this instruction at another place, the relative jump will fail.
To get a working code, WinAPIOverride has to compute the new relative address from the execution location to the original destination.
So specifying a such option tells WinAPIOverride to compute new relative address.

|FirstBytesCanExecuteAnywhereWithRelativeAddressChange moves 5 bytes, and
|FirstBytesCanExecuteAnywhereWithRelativeAddressChange= allows you to specify the number of movable bytes between 5 and 64
(warning modified address is still at the 4 last bytes)



   |FirstBytesCantExecuteAnywhere

Force first bytes to be executed at there original place.
It can be usefull if the "Do first bytes analysis (applies only on new loaded files or dll)" option is set in the options dialog.
In some case the "Insecure first bytes analysis" fails only for 1 or 2 functions for 200 or more hooked functions.
So once crashing functions analysed, put this flag on them and have powerful hooks.


Examples of use :
LIB.DLL|int Func(int a, int b);|FirstBytesCanExecuteAnywhere
LIB.DLL|int Func2(int a, int b,int c);|FirstBytesCanExecuteAnywhere=9
LIB.DLL|int Func3(int a, int b,int c);|FirstBytesCanExecuteAnywhereWithRelativeAddressChange
LIB.DLL|int Func4(int a, int b,int c);|FirstBytesCanExecuteAnywhereWithRelativeAddressChange=9
LIB.DLL|int Func5(int a, int b,int c);|FirstBytesCantExecuteAnywhere

These options are very powerfull : no loss of message and speedest algorithm; but you have to be sure you can use them .

To see how to find first functions bytes without a dissassembler refer to faq : Get first functions bytes without a dissassembler

First bytes of function may change at each software/dll version.
So using these options generally make your monitoring file not compatible with other version of the software/dll





   |BlockingCall

Allow to hook calls made by other threads even if previous calls have not ended.
Use it only for slow blocking call like MessageBox or DialogBox function.
Don't use it with high speed blocking functions like SendMessage or WaitForSingleObject, else your application may will crash and as using this option
slow down the hook algorithm, you may will loose more messages than without this option.

Notice : Use it only if you can't use the "FirstBytesCanExecuteAnywhere" options, or if Powerless hooks option is activated.
This option has no effect on PowerFull hooks
USER32.DLL|int MessageBoxA(HWND hWnd,LPCSTR lpText,LPCSTR lpCaption,UINT uType);|BlockingCall



Auto Removed Keywords

The following list of parameter keywords is automatically removed (case insensitive) :
const, struct, in, out, inout, far, class, __in, __inout, __out, __reserved, __in_opt, __in_default, __out_opt__inout_opt, _In_, _In_opt_, _Inout_, _Inout_opt_, _Out_, _Out_opt_, _In_z_, _In_opt_z_, _Inout_z_, _Inout_opt_z_, _Out_z_, _Out_opt_z_

Example
msvcrt.dll|char * strcat( char *strDestination, const char *strSource )
is the same as
msvcrt.dll|char * strcat( char *strDestination, char *strSource )

Particular cases : function pointer and "..."

Function pointer :

Since version 5.0, function parameters like lib.dll|func(int (__cdecl*)(unsigned int)) are fully supported.
On previous versions, Instead of describing the whole function description, you have to use FARPROC keyword

Example:
Instead of
lib.dll|func(int (__cdecl*)(unsigned int))
use
lib.dll|func(FARPROC pFunc)

"..." :

  1) If you want to make a generic monitoring, you have to remove them to avoid trying reading invalid memory.
By the way the printf function will by defined by :
msvcrt.dll|int printf( const char *format)

  2) If you want to make a particular monitoring on one call, adjust the amount of parameters to the specific function call you want to watch.
By the way if you want to monitor the call printf("hello my name is %s, I am %d years old", strName, nYears), just use the following monitoring description
msvcrt.dll|int printf( const char *format, char* Name, int Years)
You may will catch some other noisy printf calls, but ordering logs by caller address will allow you to find the good ones. (Click the "Caller Address" column header to order logs)


Fully Supported Parameters Types

If a type of parameter is not fully supported, it will be display like an unsigned long

To monitor not supported types or structures you can
    a) use :DataSize= and :PointedDataSize= logging options (see the above Logging options in the advanced syntax)
or
    b) define your user structs and types. In this case size is computed, so if you struct is defined in "UserTypes" directory, you don't need to specify the struct size (See User Types for more information)

All types are not case sensitive (you can use PSTR or pstr).

Static array are supported
f(int iArray[2][4][5],short sArray[5])


PSTR, PCSTR, LPSTR, LPCSTR, CHAR*, SEC_CHAR*, PCHAR, LPCHAR,
PWSTR, PCWSTR, LPWSTR, LPCWSTR, LPCWSTR, WCHAR*, PWCHAR, LPWCHAR, wchar_t*, SEC_WCHAR*, BSTR, OLECHAR, LPOLESTR
VOID*, PVOID, LPVOID, LPCVOID, VOID**, PVOID*, LPVOID*, LPCVOID*,
CHAR, SEC_CHAR, UCHAR, BOOLEAN, BYTE, BYTE*, PBYTE, LPBYTE, BOOLEAN*, PBOOLEAN, LPBOOLEAN, UCHAR*, PUCHAR, LPUCHAR,
WCHAR, SEC_WCHAR, wchar_t, wctrans_t, WORD, short, SHORT, USHORT, u_short, wint_t, wctype_t, WPARAM,
short*, SHORT*, PSHORT, LPSHORT, USHORT*, PUSHORT, LPUSHORT, WORD*, PWORD, LPWORD, u_short*,
BOOL, BOOL*, PBOOL, LPBOOL,
SIZE_T, _fsize_t, SIZE_T*, PSIZE_T, LPSIZE_T,
INT, INT*, PINT, LPINT, UINT, UINT*, PUINT, LPUINT,
LONG, NTSTATUS, LONG_PTR, LPARAM, LONG*, PLONG, LPLONG, LONG_PTR*, PLONG_PTR, LPLONG_PTR,
ULONG_PTR, UINT_PTR, SOCKET, ULONG, u_long, DWORD, ULONG*, PULONG, LPULONG, SOCKET*, u_long*,
DWORD*, PDWORD, LPDWORD, ULONG_PTR*, PULONG_PTR, LPULONG_PTR, LSA_HANDLE, LSA_HANDLE*,
PLSA_HANDLE, LPLSA_HANDLE,
HKEY, PHKEY, HKEY*, COLORREF, COLORREF*, LPCOLORREF, PFNCALLBACK, LCID,
SYSTEMTIME, SYSTEMTIME*, PSYSTEMTIME, LPSYSTEMTIME, FILETIME, FILETIME*, PFILETIME, LPFILETIME,
ACCESS_MASK, ACCESS_MASK*, PACCESS_MASK,
HANDLE, HINSTANCE, HWND, HMODULE, HMODULE*, PHMODULE, LPHMODULE, HANDLE*, PHANDLE, LPHANDLE,
HDESK, HBRUSH, HRGN, HDPA, HDSA, HDC, HICON, HICON*, WNDPROC, HMENU, HIMAGELIST,
DLGPROC, FARPROC, LPWSAOVERLAPPED_COMPLETION_ROUTINE,
HPALETTE, HFONT, HMETAFILE, HGDIOBJ, HCOLORSPACE, HBITMAP, HCONV, HSZ, HDDEDATA, SC_HANDLE,
HCERTSTORE, HGLOBAL, PSID, PSID*, PSECURITY_DESCRIPTOR, PSECURITY_DESCRIPTOR*, SECURITY_INFORMATION,
REGSAM, SECURITY_ATTRIBUTES, SECURITY_ATTRIBUTES*, PSECURITY_ATTRIBUTES, LPSECURITY_ATTRIBUTES,
ACL, ACL*, PACL, LPCDLGTEMPLATE,
WNDCLASS, WNDCLASS*, PWNDCLASS, LPWNDCLASS, WNDCLASSEX, WNDCLASSEX*, PWNDCLASSEX, LPWNDCLASSEX,
POINT, POINT*, PPOINT, LPPOINT, POINTL, POINTL*, PPOINTL,
SIZE, SIZE*, PSIZE, LPSIZE, RECT, RECT*, PRECT, LPRECT, RECTL, RECTL, PRECTL, LPRECTL,
CRITICAL_SECTION, CRITICAL_SECTION*, PCRITICAL_SECTION, LPCRITICAL_SECTION,
sockaddr, sockaddr*, PSOCKADDR, LPSOCKADDR, sockaddr_in, sockaddr_in*, hostent, hostent*,
timeval*, FILE*, LPSTARTUPINFO, LPSTARTUPINFOW, LPSHELLEXECUTEINFO, LPSHELLEXECUTEINFOW,
LARGE_INTEGER, LARGE_INTEGER*, PLARGE_INTEGER, ULARGE_INTEGER, ULARGE_INTEGER*, PULARGE_INTEGER,
GUID, GUID*, PGUID, LPGUID, REFGUID, IID, IID*, PIID, LPIID, REFIID, CLSID, CLSID*, PCLSID, LPCLSID, REFCLSID,
FMTID, FMTID*, PFMTID, LPFMTID, REFFMTID, MSG*, PMSG, LPMSG,
HCRYPTPROV, HCRYPTKEY, HCRYPTHASH,
PUNICODE_STRING, UNICODE_STRING*, PANSI_STRING, ANSI_STRING*,
PSecHandle, PCtxtHandle, PCredHandle,
MEMORY_BASIC_INFORMATION, MEMORY_BASIC_INFORMATION*, PMEMORY_BASIC_INFORMATION,
PROCESSENTRY32*, LPPROCESSENTRY32, PPROCESSENTRY32, PROCESSENTRY32W*, LPPROCESSENTRY32W, PPROCESSENTRY32W,
MODULEENTRY32*, LPMODULEENTRY32, PMODULEENTRY32, MODULEENTRY32W*, PMODULEENTRY32W, LPMODULEENTRY32W,
HEAPENTRY32*, PHEAPENTRY32, LPHEAPENTRY32, THREADENTRY32*, PTHREADENTRY32, LPTHREADENTRY32,
PROCESS_HEAP_ENTRY*, PPROCESS_HEAP_ENTRY, LPPROCESS_HEAP_ENTRY,
WIN32_FIND_DATA*, PWIN32_FIND_DATA, LPWIN32_FIND_DATA, WIN32_FIND_DATAW*, PWIN32_FIND_DATAW, LPWIN32_FIND_DATAW,
IO_STATUS_BLOCK*, PIO_STATUS_BLOCK,
PRINTDLG*, LPPRINTDLG, LPPRINTDLGA, LPPRINTDLGW, PRINTDLGEX*, LPPRINTDLGEX, LPPRINTDLGEXA, LPPRINTDLGEXW,
PAGESETUPDLG*, LPPAGESETUPDLG, LPPAGESETUPDLGA, LPPAGESETUPDLGW,
OPENFILENAME*, LPOPENFILENAME, LPOPENFILENAMEA, LPOPENFILENAMEW,
CHOOSEFONT*, LPCHOOSEFONT, LPCHOOSEFONTA, LPCHOOSEFONTW,
FINDREPLACE*, LPFINDREPLACE, LPFINDREPLACEA, LPFINDREPLACEW,
BROWSEINFO*, PBROWSEINFO, LPBROWSEINFO, LPBROWSEINFOA, LPBROWSEINFOW,
SHFILEINFOA*, PSHFILEINFOA, SHFILEINFOW*, PSHFILEINFOW,
NOTIFYICONDATA*, PNOTIFYICONDATA, NOTIFYICONDATAA*, PNOTIFYICONDATAA, NOTIFYICONDATAW*, PNOTIFYICONDATAW,
fd_set*, WSABUF*, PWSABUF, LPWSABUF,
ADDRINFO*, PADDRINFO, LPADDRINFO,
WSADATA*, PWSADATA, LPWSADATA,
LPWSAPROTOCOL_INFOA, LPWSAPROTOCOL_INFOW,
OVERLAPPED*, POVERLAPPED, LPOVERLAPPED, WSAOVERLAPPED*, PWSAOVERLAPPED, LPWSAOVERLAPPED,
float, float*, PFLOAT, LPFLOAT, double, double*, PDOUBLE, LPDOUBLE,
__int64, INT64, INT64*, PINT64, LPINT64, ULONG64, ULONG64*, PULONG64, LPULONG64,
DWORD64, DWORD64*, PDWORD64, LPDWORD64, ULONGLONG, ULONGLONG*, PULONGLONG, DWORDLONG, DWORDLONG*, PDWORDLONG,
TRACEHANDLE, TRACEHANDLE*, PTRACEHANDLE, DCB*, PDCB, LPDCB, COMMTIMEOUTS*, PCOMMTIMEOUTS, LPCOMMTIMEOUTS,
COMMCONFIG*, PCOMMCONFIG, LPCOMMCONFIG
SAFEARRAY, SAFEARRAY*, LPSAFEARRAY, SAFEARRAYBOUND, SAFEARRAYBOUND*, LPSAFEARRAYBOUND
VARIANTARG, LPVARIANT, VARIANTARG*, VARIANT*
DECIMAL, DECIMAL*, LPDECIMAL
MULTI_QI, MUTLI_QI*, LPMUTLI_QI
EXCEPINFO, EXCEPINFO*, LPEXCEPINFO
DISPPARAMS, DISPPARAMS*, PDISPPARAMS, LPDISPPARAMS
LOGFONTA, LOGFONTA*, PLOGFONTA, LPLOGFONTA, LOGFONTW, LOGFONTW*, PLOGFONTW, LPLOGFONTW