ReactOS  0.4.13-dev-544-gede3fdd
base_x.h
Go to the documentation of this file.
1 /*
2  * COPYRIGHT: See COPYING in the top level directory
3  * PROJECT: ReactOS System Libraries
4  * FILE: dll/win32/kernel32/include/base_x.h
5  * PURPOSE: Base API Client Macros
6  * PROGRAMMER: Alex Ionescu (alex@relsoft.net)
7  */
8 
9 #pragma once
10 
11 /* INCLUDES *******************************************************************/
12 
13 //
14 // This macro (split it up in 3 pieces to allow for intermediary code in between)
15 // converts a NULL-terminated ASCII string, usually associated with an object
16 // name, into its NT-native UNICODE_STRING structure, by using the TEB's Static
17 // Unicode String.
18 //
19 // It should only be used when the name is supposed to be less than MAX_PATH
20 // (260 characters).
21 //
22 // It returns the correct ERROR_FILENAME_EXCED_RANGE Win32 error when the path
23 // is too long.
24 //
25 // Note that Basep8BitStringToStaticUnicodeString looks deceptively similar.
26 // However, that function was designed for File APIs, which can be switched into
27 // a special "OEM" mode, that uses different NLS files/encoding, and thus calls
28 // RtlOemStringToAnsiString (see SetFileApisToOEM). Therefore, this macro and
29 // that function are not interchangeable. As a separate note, that function uses
30 // the *Ex version of the Rtl conversion APIs, which does stricter checking that
31 // is not done when this macro is used.
32 //
33 #define ConvertAnsiToUnicodePrologue \
34 { \
35  NTSTATUS Status; \
36  PUNICODE_STRING UnicodeCache; \
37  ANSI_STRING AnsiName;
38 #define ConvertAnsiToUnicodeBody(name) \
39  UnicodeCache = &NtCurrentTeb()->StaticUnicodeString; \
40  RtlInitAnsiString(&AnsiName, name); \
41  Status = RtlAnsiStringToUnicodeString(UnicodeCache, &AnsiName, FALSE);
42 #define ConvertAnsiToUnicodeEpilogue \
43  if (Status == STATUS_BUFFER_OVERFLOW) \
44  SetLastError(ERROR_FILENAME_EXCED_RANGE); \
45  else \
46  BaseSetLastNTError(Status); \
47  return FALSE; \
48 }
49 
50 //
51 // This macro uses the ConvertAnsiToUnicode macros above to convert a CreateXxxA
52 // Win32 API into its equivalent CreateXxxW API.
53 //
54 #define ConvertWin32AnsiObjectApiToUnicodeApi(obj, name, ...) \
55  ConvertAnsiToUnicodePrologue \
56  if (!name) return Create##obj##W(__VA_ARGS__, NULL); \
57  ConvertAnsiToUnicodeBody(name) \
58  if (NT_SUCCESS(Status)) return Create##obj##W(__VA_ARGS__, UnicodeCache->Buffer); \
59  ConvertAnsiToUnicodeEpilogue
60 
61 //
62 // This macro uses the ConvertAnsiToUnicode macros above to convert a CreateXxxA
63 // Win32 API into its equivalent CreateXxxW API.
64 //
65 #define ConvertWin32AnsiObjectApiToUnicodeApi2(obj, name, ...) \
66  ConvertAnsiToUnicodePrologue \
67  if (!name) return Create##obj##W(NULL, __VA_ARGS__); \
68  ConvertAnsiToUnicodeBody(name) \
69  if (NT_SUCCESS(Status)) return Create##obj##W(UnicodeCache->Buffer, __VA_ARGS__); \
70  ConvertAnsiToUnicodeEpilogue
71 
72 //
73 // This macro uses the ConvertAnsiToUnicode macros above to convert a FindFirst*A
74 // Win32 API into its equivalent FindFirst*W API.
75 //
76 #define ConvertWin32AnsiChangeApiToUnicodeApi(obj, name, ...) \
77  ConvertAnsiToUnicodePrologue \
78  ConvertAnsiToUnicodeBody(name) \
79  if (NT_SUCCESS(Status)) return obj##W(UnicodeCache->Buffer, ##__VA_ARGS__); \
80  ConvertAnsiToUnicodeEpilogue
81 
82 //
83 // This macro uses the ConvertAnsiToUnicode macros above to convert a OpenXxxA
84 // Win32 API into its equivalent OpenXxxW API.
85 //
86 #define ConvertOpenWin32AnsiObjectApiToUnicodeApi(obj, acc, inh, name) \
87  ConvertAnsiToUnicodePrologue \
88  if (!name) \
89  { \
90  SetLastError(ERROR_INVALID_PARAMETER); \
91  return NULL; \
92  } \
93  ConvertAnsiToUnicodeBody(name) \
94  if (NT_SUCCESS(Status)) return Open##obj##W(acc, inh, UnicodeCache->Buffer);\
95  ConvertAnsiToUnicodeEpilogue
96 
97 //
98 // This macro (split it up in 3 pieces to allow for intermediary code in between)
99 // wraps the usual code path required to create an NT object based on a Unicode
100 // (Wide) Win32 object creation API.
101 //
102 // It makes use of BaseFormatObjectAttributes and allows for a custom access
103 // mode to be used, and also sets the correct error codes in case of a collision
104 //
105 #define CreateNtObjectFromWin32ApiPrologue \
106 { \
107  NTSTATUS Status; \
108  HANDLE Handle; \
109  UNICODE_STRING ObjectName; \
110  OBJECT_ATTRIBUTES LocalAttributes; \
111  POBJECT_ATTRIBUTES ObjectAttributes = &LocalAttributes;
112 #define CreateNtObjectFromWin32ApiBody(ntobj, sec, name, access, ...) \
113  if (name) RtlInitUnicodeString(&ObjectName, name); \
114  ObjectAttributes = BaseFormatObjectAttributes(&LocalAttributes, \
115  sec, \
116  name ? &ObjectName : NULL); \
117  Status = NtCreate##ntobj(&Handle, access, ObjectAttributes, ##__VA_ARGS__);
118 #define CreateNtObjectFromWin32ApiEpilogue \
119  if (NT_SUCCESS(Status)) \
120  { \
121  if (Status == STATUS_OBJECT_NAME_EXISTS) \
122  SetLastError(ERROR_ALREADY_EXISTS); \
123  else \
124  SetLastError(ERROR_SUCCESS); \
125  return Handle; \
126  } \
127  BaseSetLastNTError(Status); \
128  return NULL; \
129 }
130 
131 //
132 // This macro uses the CreateNtObjectFromWin32Api macros from above to create an
133 // NT object based on the Win32 API settings.
134 //
135 // Note that it is hardcoded to always use XXX_ALL_ACCESS permissions, which is
136 // the behavior up until Vista. When/if the target moves to Vista, the macro can
137 // be improved to support caller-specified access masks, as the underlying macro
138 // above does support this.
139 //
140 #define CreateNtObjectFromWin32Api(obj, ntobj, capsobj, sec, name, ...) \
141  CreateNtObjectFromWin32ApiPrologue \
142  CreateNtObjectFromWin32ApiBody(ntobj, sec, name, capsobj##_ALL_ACCESS, ##__VA_ARGS__); \
143  CreateNtObjectFromWin32ApiEpilogue
144 
145 //
146 // This macro opens an NT object based on the Win32 API settings.
147 //
148 #define OpenNtObjectFromWin32Api(ntobj, acc, inh, name) \
149  CreateNtObjectFromWin32ApiPrologue \
150  if (!name) \
151  { \
152  BaseSetLastNTError(STATUS_INVALID_PARAMETER); \
153  return NULL; \
154  } \
155  RtlInitUnicodeString(&ObjectName, name); \
156  InitializeObjectAttributes(ObjectAttributes, \
157  &ObjectName, \
158  inh ? OBJ_INHERIT : 0, \
159  BaseGetNamedObjectDirectory(), \
160  NULL); \
161  Status = NtOpen##ntobj(&Handle, acc, ObjectAttributes); \
162  if (!NT_SUCCESS(Status)) \
163  { \
164  BaseSetLastNTError(Status); \
165  return NULL; \
166  } \
167  return Handle; \
168 }
169