/*++ Copyright (c) Microsoft Corporation. All rights reserved. Module Name: ntrtlstringandbuffer.h Abstract: Broken out from nturtl and rtl so I can move it between them in seperate trees without merge madness. To be integrated into ntrtl.h Author: Jay Krell (a-JayK) December 2000 Environment: Revision History: --*/ #ifndef _NTRTL_STRING_AND_BUFFER_ #define _NTRTL_STRING_AND_BUFFER_ #if _MSC_VER >= 1100 #pragma once #endif #ifdef __cplusplus extern "C" { #endif #if defined (_MSC_VER) #if ( _MSC_VER >= 800 ) #pragma warning(disable:4514) #if _MSC_VER >= 1200 #pragma warning(push) #endif #pragma warning(disable:4001) #pragma warning(disable:4201) #pragma warning(disable:4214) #endif #endif // // not NTSYSAPI so easily statically linked to // // // These work for both UNICODE_STRING and STRING. // That's why "plain" 0 and sizeof(Buffer[0]) is used. // // odd but correct use of RTL_STRING_IS_PUT_AT_SAFE instead of RTL_STRING_IS_GET_AT_SAFE, // we are reaching past the Length #define RTL_STRING_IS_NUL_TERMINATED(s) (RTL_STRING_IS_PUT_AT_SAFE(s, RTL_STRING_GET_LENGTH_CHARS(s), 0) \ && RTL_STRING_GET_AT_UNSAFE(s, RTL_STRING_GET_LENGTH_CHARS(s)) == 0) #define RTL_STRING_NUL_TERMINATE(s) ((VOID)(ASSERT(RTL_STRING_IS_PUT_AT_SAFE(s, RTL_STRING_GET_LENGTH_CHARS(s), 0)), \ ((s)->Buffer[RTL_STRING_GET_LENGTH_CHARS(s)] = 0))) #define RTL_NUL_TERMINATE_STRING(s) (RTL_STRING_NUL_TERMINATE(s)) /* compatibility */ #define RTL_STRING_MAKE_LENGTH_INCLUDE_TERMINAL_NUL(s) ((VOID)(ASSERT(RTL_STRING_IS_NUL_TERMINATED(s)), \ ((s)->Length += sizeof((s)->Buffer[0])))) #define RTL_STRING_IS_EMPTY(s) ((s)->Length == 0) #define RTL_STRING_GET_LAST_CHAR(s) (RTL_STRING_GET_AT((s), RTL_STRING_GET_LENGTH_CHARS(s) - 1)) #define RTL_STRING_GET_LENGTH_CHARS(s) ((s)->Length / sizeof((s)->Buffer[0])) #define RTL_STRING_GET_MAX_LENGTH_CHARS(s) ((s)->MaximumLength / sizeof((s)->Buffer[0])) #define RTL_STRING_GET_LENGTH_BYTES(s) ((s)->Length) #define RTL_STRING_SET_LENGTH_CHARS_UNSAFE(s,n) ((s)->Length = (RTL_STRING_LENGTH_TYPE)(((n) * sizeof(s)->Buffer[0]))) // // We don't provide an explicit/retail RTL_STRING_GET_AT_SAFE because it'd // need a return value distinct from all values of c. -1? NTSTATUS? Seems too heavy. // // For consistency then, we also don't provide RTL_STRING_PUT_AT_SAFE. // #define RTL_STRING_IS_GET_AT_SAFE(s,n) ((n) < RTL_STRING_GET_LENGTH_CHARS(s)) #define RTL_STRING_GET_AT_UNSAFE(s,n) ((s)->Buffer[n]) #define RTLP_STRING_GET_AT_SAFE(s,n) (RTL_STRING_IS_GET_AT_SAFE(s,n) ? RTL_STRING_GET_AT_UNSAFE(s,n) : 0) #define RTL_STRING_IS_PUT_AT_SAFE(s,n,c) ((n) < RTL_STRING_GET_MAX_LENGTH_CHARS(s)) #define RTL_STRING_PUT_AT_UNSAFE(s,n,c) ((s)->Buffer[n] = (c)) #define RTLP_STRING_PUT_AT_SAFE(s,n,c) ((void)(RTL_STRING_IS_PUT_AT_SAFE(s,n,c) ? RTL_STRING_PUT_AT_UNSAFE(s,n,c) : 0)) #if defined(RTL_STRING_RANGE_CHECKED) #define RTL_STRING_GET_AT(s,n) (ASSERT(RTL_STRING_IS_GET_AT_SAFE(s,n)), \ RTL_STRING_GET_AT_UNSAFE(s,n)) #else #define RTL_STRING_GET_AT(s,n) (RTL_STRING_GET_AT_UNSAFE(s,n)) #endif #if defined(RTL_STRING_RANGE_CHECKED) #define RTL_STRING_PUT_AT(s,n,c) (ASSERT(RTL_STRING_IS_PUT_AT_SAFE(s,n,c)), \ RTL_STRING_PUT_AT_UNSAFE(s,n,c)) #else #define RTL_STRING_PUT_AT(s,n,c) (RTL_STRING_PUT_AT_UNSAFE(s,n,c)) #endif // // preallocated heap-growable buffers // struct _RTL_BUFFER; #if !defined(RTL_BUFFER) // This is duplicated in ntldr.h. #define RTL_BUFFER RTL_BUFFER typedef struct _RTL_BUFFER { PUCHAR Buffer; PUCHAR StaticBuffer; SIZE_T Size; SIZE_T StaticSize; SIZE_T ReservedForAllocatedSize; // for future doubling PVOID ReservedForIMalloc; // for future pluggable growth } RTL_BUFFER, *PRTL_BUFFER; #endif #define RTLP_BUFFER_IS_HEAP_ALLOCATED(b) ((b)->Buffer != (b)->StaticBuffer) //++ // // NTSTATUS // RtlInitBuffer( // OUT PRTL_BUFFER Buffer, // IN PUCHAR StaticBuffer, // IN SIZE_T StaticSize // ); // // Routine Description: // // Initialize a preallocated heap-growable buffer. // // Arguments: // // Buffer - "this" // StaticBuffer - preallocated storage for Buffer to use until/unless more than StaticSize is needed // StaticSize - the size of StaticBuffer in bytes // // Return Value: // // STATUS_SUCCESS // //-- #define RtlInitBuffer(Buff, StatBuff, StatSize) \ do { \ (Buff)->Buffer = (StatBuff); \ (Buff)->Size = (StatSize); \ (Buff)->StaticBuffer = (StatBuff); \ (Buff)->StaticSize = (StatSize); \ } while (0) #define RTL_ENSURE_BUFFER_SIZE_NO_COPY (0x00000001) NTSTATUS NTAPI RtlpEnsureBufferSize( IN ULONG Flags, IN OUT PRTL_BUFFER Buffer, IN SIZE_T NewSizeBytes ); //++ // // NTSTATUS // RtlEnsureBufferSize( // IN OUT PRTL_BUFFER Buffer, // IN SIZE_T NewSizeBytes // ); // // Routine Description: // // If Buffer is smaller than NewSize, grow it to NewSize, using the static buffer if it // is large enough, else heap allocating // // Arguments: // // Flags - // RTL_ENSURE_BUFFER_SIZE_NO_COPY // Buffer - // NewSizeBytes - // // Return Value: // // STATUS_SUCCESS // STATUS_NO_MEMORY // //-- #define RtlEnsureBufferSize(Flags, Buff, NewSizeBytes) \ ( ((Buff) != NULL && (NewSizeBytes) <= (Buff)->Size) \ ? STATUS_SUCCESS \ : RtlpEnsureBufferSize((Flags), (Buff), (NewSizeBytes)) \ ) //++ // // VOID // RtlFreeBuffer( // IN OUT PRTL_BUFFER Buffer, // ); // // // Routine Description: // // Free any heap allocated storage associated with Buffer. // Notes: // - RtlFreeBuffer returns a buffer to the state it was in after // calling RtlInitBuffer, so you may reuse it. // - If you want to shrink the buffer without freeing it, just poke Buffer->Size down. // This is safe regardless of if the buffer has gone heap allocated or not. // - You may RtlFreeBuffer an RTL_BUFFER that is all zeros. You do not need to track if you // called RtlInitBuffer if you know you filled it with zeros. // - You may RtlFreeBuffer an RTL_BUFFER repeatedly. // // Arguments: // // Buffer - // // Return Value: // // none, unconditional success // //-- #define RtlFreeBuffer(Buff) \ do { \ if ((Buff) != NULL && (Buff)->Buffer != NULL) { \ if (RTLP_BUFFER_IS_HEAP_ALLOCATED(Buff)) { \ UNICODE_STRING UnicodeString; \ UnicodeString.Buffer = (PWSTR)(PVOID)(Buff)->Buffer; \ RtlFreeUnicodeString(&UnicodeString); \ } \ (Buff)->Buffer = (Buff)->StaticBuffer; \ (Buff)->Size = (Buff)->StaticSize; \ } \ } while (0) // // a preallocated buffer that is "tied" to a UNICODE_STRING // struct _RTL_UNICODE_STRING_BUFFER; typedef struct _RTL_UNICODE_STRING_BUFFER { UNICODE_STRING String; RTL_BUFFER ByteBuffer; UCHAR MinimumStaticBufferForTerminalNul[sizeof(WCHAR)]; } RTL_UNICODE_STRING_BUFFER, *PRTL_UNICODE_STRING_BUFFER; // // MAX_UNICODE_STRING_MAXLENGTH is the maximum allowed value for UNICODE_STRING::MaximumLength. // MAX_UNICODE_STRING_LENGTH is the maximum allowed value for UNICODE_STRING::Length, allowing // room for a terminal nul. // // Explanation of MAX_UNICODE_STRING_MAXLENGTH implementation // ~0 is all bits set, maximum value in two's complement arithmetic, which C guarantees for unsigned types // << shifts out the number of bits that fit in UNICODE_STRING::Length // ~ and now we have all bits set that fit in UNICODE_STRING::Length, // like if UNICODE_STRING::Length is 16 bits, we have 0xFFFF // then mask so it is even multiple of whatever UNICODE_STRING::Buffer points to. // If Length is changed to ULONG or SIZE_T, this macro is still correct. // If Buffer pointed to CHAR or "WIDER_CHAR" or something else, this macro is still correct. // #define MAX_UNICODE_STRING_MAXLENGTH ((~((~(SIZE_T)0) << (RTL_FIELD_SIZE(UNICODE_STRING, Length) * CHAR_BIT))) & ~(sizeof(((PCUNICODE_STRING)0)->Buffer[0]) - 1)) #define MAX_UNICODE_STRING_LENGTH (MAX_UNICODE_STRING_MAXLENGTH - sizeof(((PCUNICODE_STRING)0)->Buffer[0])) //++ // // NTSTATUS // RtlInitUnicodeStringBuffer( // OUT PRTL_UNICODE_STRING_BUFFER Buffer, // IN PUCHAR StaticBuffer, // IN SIZE_T StaticSize // ); // // Routine Description: // // // Arguments: // // Buffer - // StaticBuffer - can be NULL, but generally is not // StaticSize - should be at least sizeof(WCHAR), but can be zero // ought to be an even multiple of sizeof(WCHAR) // gets rounded to down to an even multiple of sizeof(WCHAR) // gets clamped to MAX_UNICODE_STRING_MAXLENGTH (64k - 2) // // RTL_UNICODE_STRING_BUFFER contains room for the terminal nul for the // case of StaticBuffer == NULL or StaticSize < sizeof(WCHAR), or, more likely, // for RtlTakeRemainingStaticBuffer leaving it with no static buffer. // // Return Value: // // STATUS_SUCCESS // //-- #define RtlInitUnicodeStringBuffer(Buff, StatBuff, StatSize) \ do { \ SIZE_T TempStaticSize = (StatSize); \ PUCHAR TempStaticBuff = (StatBuff); \ TempStaticSize &= ~(sizeof((Buff)->String.Buffer[0]) - 1); \ if (TempStaticSize > UNICODE_STRING_MAX_BYTES) { \ TempStaticSize = UNICODE_STRING_MAX_BYTES; \ } \ if (TempStaticSize < sizeof(WCHAR)) { \ TempStaticBuff = (Buff)->MinimumStaticBufferForTerminalNul; \ TempStaticSize = sizeof(WCHAR); \ } \ RtlInitBuffer(&(Buff)->ByteBuffer, TempStaticBuff, TempStaticSize); \ (Buff)->String.Buffer = (WCHAR*)TempStaticBuff; \ if ((Buff)->String.Buffer != NULL) \ (Buff)->String.Buffer[0] = 0; \ (Buff)->String.Length = 0; \ (Buff)->String.MaximumLength = (RTL_STRING_LENGTH_TYPE)TempStaticSize; \ } while (0) //++ // // NTSTATUS // RtlSyncStringToBuffer( // IN OUT PRTL_UNICODE_STRING_BUFFER UnicodeStringBuffer // ); // // Routine Description: // // After carefully modifying the underlying RTL_BUFFER, this updates // dependent fields in the underlying UNICODE_STRING. // // For example, use this after you grow the buffer with RtlEnsureBufferSize, // but that example you don't need, use RtlEnsureUnicodeStringBufferSizeChars // or RtlEnsureStringBufferSizeBytes. // // Arguments: // // UnicodeStringBuffer - // // Return Value: // // STATUS_SUCCESS - hooray // //-- #define RtlSyncStringToBuffer(x) \ ( \ ( ASSERT((x)->String.Length < (x)->ByteBuffer.Size) ), \ ( ASSERT((x)->String.MaximumLength >= (x)->String.Length) ), \ ( ASSERT((x)->String.MaximumLength <= (x)->ByteBuffer.Size) ), \ ( (x)->String.Buffer = (PWSTR)(x)->ByteBuffer.Buffer ), \ ( (x)->String.MaximumLength = (RTL_STRING_LENGTH_TYPE)((x)->ByteBuffer.Size) ), \ ( ASSERT(RTL_STRING_IS_NUL_TERMINATED(&(x)->String)) ), \ ( STATUS_SUCCESS ) \ ) //++ // // NTSTATUS // RtlSyncBufferToString( // IN OUT PRTL_UNICODE_STRING_BUFFER UnicodeStringBuffer // ); // // Routine Description: // // After carefully modifying the underlying UNICODE_STRING, this updates // dependent fields in the underlying RTL_BUFFER. // // For example, use this after you the alloc the buffer with RtlAnsiStringToUnicodeString. // This is possible because RTL_BUFFER deliberately uses the same memory allocator // as RtlAnsiStringToUnicodeString. // // Arguments: // // UnicodeStringBuffer - // // Return Value: // // STATUS_SUCCESS - hooray // //-- #define RtlSyncBufferToString(Buff_) \ ( \ ( (Buff_)->ByteBuffer.Buffer = (Buff_)->String.Buffer ), \ ( (Buff_)->ByteBuffer.Buffer.Size = (Buff_)->String.MaximumLength ), \ ( STATUS_SUCCESS ) \ ) //++ // // NTSTATUS // RtlEnsureUnicodeStringBufferSizeChars( // IN OUT PRTL_BUFFER Buffer, // IN USHORT NewSizeChars // ); // // NTSTATUS // RtlEnsureUnicodeStringBufferSizeBytes( // IN OUT PRTL_BUFFER Buffer, // IN USHORT NewSizeBytes // ); // // Routine Description: // // Optionally multiply cch to go from count of character to count of bytes. // +1 or +2 for you to account for the terminal nul. // Delegate to underlying RtlEnsureBufferSize. // Keep String.Buffer, .MaximumLength, and terminal nul in sync. // // Arguments: // // Buffer - // NewSizeChars - // NewSizeBytes - must be a multiple of sizeof(WCHAR), and we don't presently // verify that. // // Return Value: // // STATUS_SUCCESS - hooray // STATUS_NO_MEMORY - out of memory // STATUS_NAME_TOO_LONG - (NewSizeChars + 1) * sizeof(WCHAR) > UNICODE_STRING_MAX_BYTES (USHORT) // //-- #define RtlEnsureUnicodeStringBufferSizeBytes(Buff_, NewSizeBytes_) \ ( ( ((NewSizeBytes_) + sizeof((Buff_)->String.Buffer[0])) > UNICODE_STRING_MAX_BYTES ) \ ? STATUS_NAME_TOO_LONG \ : !NT_SUCCESS(RtlEnsureBufferSize(0, &(Buff_)->ByteBuffer, ((NewSizeBytes_) + sizeof((Buff_)->String.Buffer[0])))) \ ? STATUS_NO_MEMORY \ : (RtlSyncStringToBuffer(Buff_)) \ ) #define RtlEnsureUnicodeStringBufferSizeChars(Buff_, NewSizeChars_) \ (RtlEnsureUnicodeStringBufferSizeBytes((Buff_), (NewSizeChars_) * sizeof((Buff_)->String.Buffer[0]))) //++ // // NTSTATUS // RtlAppendUnicodeStringBuffer( // OUT PRTL_UNICODE_STRING_BUFFER Destination, // IN PCUNICODE_STRING Source // ); // // Routine Description: // // // Arguments: // // Destination - // Source - // // Return Value: // // STATUS_SUCCESS // STATUS_NO_MEMORY // STATUS_NAME_TOO_LONG (64K UNICODE_STRING length would be exceeded) // //-- #define RtlAppendUnicodeStringBuffer(Dest, Source) \ ( ( ( (Dest)->String.Length + (Source)->Length + sizeof((Dest)->String.Buffer[0]) ) > UNICODE_STRING_MAX_BYTES ) \ ? STATUS_NAME_TOO_LONG \ : (!NT_SUCCESS( \ RtlEnsureBufferSize( \ 0, \ &(Dest)->ByteBuffer, \ (Dest)->String.Length + (Source)->Length + sizeof((Dest)->String.Buffer[0]) ) ) \ ? STATUS_NO_MEMORY \ : ( ( (Dest)->String.Buffer = (PWSTR)(Dest)->ByteBuffer.Buffer ), \ ( RtlMoveMemory( \ (Dest)->String.Buffer + (Dest)->String.Length / sizeof((Dest)->String.Buffer[0]), \ (Source)->Buffer, \ (Source)->Length) ), \ ( (Dest)->String.MaximumLength = (RTL_STRING_LENGTH_TYPE)((Dest)->String.Length + (Source)->Length + sizeof((Dest)->String.Buffer[0]))), \ ( (Dest)->String.Length = (USHORT) ((Dest)->String.Length + (Source)->Length )), \ ( (Dest)->String.Buffer[(Dest)->String.Length / sizeof((Dest)->String.Buffer[0])] = 0 ), \ ( STATUS_SUCCESS ) ) ) ) NTSTATUS NTAPI RtlMultiAppendUnicodeStringBuffer( OUT PRTL_UNICODE_STRING_BUFFER Destination, IN ULONG NumberOfSources, IN const UNICODE_STRING* SourceArray ); //++ // // VOID // RtlFreeUnicodeStringBuffer( // OUT PRTL_UNICODE_STRING_BUFFER Buffer // ); // // Routine Description: // // Arguments: // // Buffer - // // Return Value: // // none, unconditional success // // If Buffer is a local, the stores are generally "dead" (their result // is never read) and the optimizer should "kill" them (not bother performing them). // // A buffer can be freed multiple times. // A buffer that has been freed is in the same state as one that just been inited. // A buffer that is all zeros (RtlZeroMemory) can be freed. You do not need to // track if you inited it. //-- #define RtlFreeUnicodeStringBuffer(Buff) \ do { \ if ((Buff) != NULL) { \ RtlFreeBuffer(&(Buff)->ByteBuffer); \ (Buff)->String.Buffer = (PWSTR)(Buff)->ByteBuffer.StaticBuffer; \ if ((Buff)->String.Buffer != NULL) \ (Buff)->String.Buffer[0] = 0; \ (Buff)->String.Length = 0; \ (Buff)->String.MaximumLength = (RTL_STRING_LENGTH_TYPE)(Buff)->ByteBuffer.StaticSize; \ } \ } while (0) //++ // // NTSTATUS // RtlAssignUnicodeStringBuffer( // IN OUT PRTL_UNICODE_STRING_BUFFER Buffer, // PCUNICODE_STRING String // ); // Routine Description: // // Arguments: // // Buffer - // String - // // Return Value: // // STATUS_SUCCESS // STATUS_NO_MEMORY //-- #define RtlAssignUnicodeStringBuffer(Buff, Str) \ (((Buff)->String.Length = 0), (RtlAppendUnicodeStringBuffer((Buff), (Str)))) //++ // // NTSTATUS // RtlTakeRemainingStaticBuffer( // IN OUT PRTL_BUFFER Buffer, // OUT PUCHAR* RemainingStaticBuffer, // OUT SIZE_T* RemainingStaticSize // ); // // Routine Description: // // This function makes it easy to share a static buffer among // multiple buffers, as long as the buffers are actually initialized // and "sealed" linearly/independently/one after another with // no "overlap" (overlap in control and dataflow, not in actual addresses). // // Note that if a buffer is using exactly all of its static buffer, you // will get back 0 and STATUS_SUCCESS. This is not an error condition. // This is why RtlInitUnicodeStringBuffer can now accept zero sized static buffers. // // Note that even if you violate the conditions that make this function most // useful, your code will still work, just less quickly. // // A pattern that should work is allocating one static buffer and moving it "through" // multiple buffers. Even if you run out of static space, it should work to // move the remaining zero size static buffer forward. Of course, you'll heap allocate. // // Arguments: // // Buffer - // RemainingStaticBuffer - // RemainingStaticSize - // // Return Value: // // STATUS_SUCCESS // //-- #define RtlTakeRemainingStaticBuffer(Buff, OutBuff, OutSize) \ (((Buff)->Buffer != (Buff)->StaticBuffer) \ ? ( /* take the whole thing */ \ ( *(OutBuff) = (Buff)->StaticBuffer ), \ ( *(OutSize) = (Buff)->StaticSize ), \ /* leave the buffer with nothing */ \ ( (Buff)->StaticBuffer = NULL ), \ ( (Buff)->StaticSize = 0 ), \ ( STATUS_SUCCESS ) \ ) \ : ( /* only take what isn't being used */ \ ( *(OutBuff) = &(Buff)->StaticBuffer[(Buff)->Size] ), \ ( *(OutSize) = ((Buff)->StaticSize - (Buff)->Size) ), \ /* leave the buffer with just what it is using */ \ ( (Buff)->StaticSize = (Buff)->Size ), \ ( STATUS_SUCCESS ) \ )) NTSTATUS NTAPI RtlPrependStringToUnicodeStringBuffer( IN ULONG Flags, IN OUT PRTL_UNICODE_STRING_BUFFER UnicodeStringBuffer, IN PCUNICODE_STRING UnicodeString ); NTSTATUS NTAPI RtlUnicodeStringBufferRight( IN ULONG Flags, IN OUT PRTL_UNICODE_STRING_BUFFER Buffer, IN ULONG Length ); NTSTATUS NTAPI RtlUnicodeStringBufferLeft( IN ULONG Flags, IN OUT PRTL_UNICODE_STRING_BUFFER Buffer, IN ULONG Length ); NTSTATUS NTAPI RtlUnicodeStringBufferMid( IN ULONG Flags, IN OUT PRTL_UNICODE_STRING_BUFFER Buffer, IN ULONG Offset, IN ULONG Length ); NTSTATUS NTAPI RtlInsertStringIntoUnicodeStringBuffer( IN ULONG Flags, IN OUT PRTL_UNICODE_STRING_BUFFER UnicodeStringBuffer, IN ULONG Offset, IN PCUNICODE_STRING InsertString ); NTSTATUS NTAPI RtlBufferTakeValue( IN ULONG Flags, IN OUT PRTL_BUFFER DestinationBuffer, IN OUT PRTL_BUFFER SourceBuffer ); //++ // // NTSTATUS // RtlUnicodeStringBufferTakeValue( // OUT NTSTATUS* Status, // IN ULONG Flags, // IN OUT RTL_UNICODE_STRING_BUFFER DestinationBuffer, // IN OUT RTL_UNICODE_STRING_BUFFER SourceBuffer // ); // //-- #define RtlUnicodeStringBufferTakeValue(Status, Flags, DestinationBuffer, SourceBuffer) \ ( \ ((Flags) != 0) \ ? (*(Status) = STATUS_INVALID_PARAMETER) \ : (!NT_SUCCESS(*(Status) = RtlBufferTakeValue(0, &(DestinationBuffer)->ByteBuffer, &(SourceBuffer)->ByteBuffer))) \ ? (*(Status)) \ : (*(Status) = RtlSyncStringToBuffer(DestinationBuffer), RtlSyncStringToBuffer(SourceBuffer)) \ ) NTSTATUS NTAPI RtlValidateBuffer( IN ULONG Flags, IN CONST RTL_BUFFER* Buffer ); NTSTATUS NTAPI RtlValidateUnicodeStringBuffer( IN ULONG Flags, IN CONST RTL_UNICODE_STRING_BUFFER* UnicodeStringBuffer ); #define RTL_FIND_AND_REPLACE_CHARACTER_IN_STRING_CASE_SENSITIVE (0x00000001) NTSTATUS NTAPI RtlFindAndReplaceCharacterInString( ULONG Flags, PVOID Reserved, PUNICODE_STRING String, WCHAR Find, WCHAR Replace ); typedef struct _RTL_ANSI_STRING_BUFFER { ANSI_STRING String; RTL_BUFFER ByteBuffer; UCHAR MinimumStaticBufferForTerminalNul[1]; } RTL_ANSI_STRING_BUFFER, *PRTL_ANSI_STRING_BUFFER; NTSTATUS NTAPI RtlInitAnsiStringBuffer( PRTL_ANSI_STRING_BUFFER StringBuffer, PUCHAR StaticBuffer, SIZE_T StaticSize ); VOID NTAPI RtlFreeAnsiStringBuffer( PRTL_ANSI_STRING_BUFFER AnsiStringBuffer ); NTSTATUS NTAPI RtlAssignAnsiStringBufferFromUnicodeString( PRTL_ANSI_STRING_BUFFER AnsiStringBuffer, PCUNICODE_STRING UnicodeString ); NTSTATUS NTAPI RtlAssignAnsiStringBufferFromUnicode( PRTL_ANSI_STRING_BUFFER AnsiStringBuffer, PCWSTR Unicode ); NTSTATUS NTAPI RtlUnicodeStringBufferEnsureTrailingNtPathSeperator( PRTL_UNICODE_STRING_BUFFER StringBuffer ); #ifdef __cplusplus } // extern "C" #endif #if defined (_MSC_VER) && ( _MSC_VER >= 800 ) #if _MSC_VER >= 1200 #pragma warning(pop) #else #pragma warning(default:4001) #pragma warning(default:4201) #pragma warning(default:4214) #endif #endif #endif