https://git.reactos.org/?p=reactos.git;a=commitdiff;h=1d59cf43af3ad38ea853b…
commit 1d59cf43af3ad38ea853b883468358f648d6da97
Author: Timo Kreuzer <timo.kreuzer(a)reactos.org>
AuthorDate: Mon Aug 14 22:07:15 2023 +0300
Commit: Timo Kreuzer <timo.kreuzer(a)reactos.org>
CommitDate: Thu Sep 7 08:36:48 2023 +0300
[NTDLL_APITEST] Add tests for critical sections
---
modules/rostests/apitests/ntdll/CMakeLists.txt | 1 +
.../rostests/apitests/ntdll/RtlCriticalSection.c | 411 +++++++++++++++++++++
modules/rostests/apitests/ntdll/testlist.c | 2 +
sdk/include/xdk/winnt_old.h | 14 +-
4 files changed, 427 insertions(+), 1 deletion(-)
diff --git a/modules/rostests/apitests/ntdll/CMakeLists.txt
b/modules/rostests/apitests/ntdll/CMakeLists.txt
index 14c12de120e..85515a2efaf 100644
--- a/modules/rostests/apitests/ntdll/CMakeLists.txt
+++ b/modules/rostests/apitests/ntdll/CMakeLists.txt
@@ -59,6 +59,7 @@ list(APPEND SOURCE
RtlBitmap.c
RtlComputePrivatizedDllName_U.c
RtlCopyMappedMemory.c
+ RtlCriticalSection.c
RtlDebugInformation.c
RtlDeleteAce.c
RtlDetermineDosPathNameType.c
diff --git a/modules/rostests/apitests/ntdll/RtlCriticalSection.c
b/modules/rostests/apitests/ntdll/RtlCriticalSection.c
new file mode 100644
index 00000000000..920cc3a97a3
--- /dev/null
+++ b/modules/rostests/apitests/ntdll/RtlCriticalSection.c
@@ -0,0 +1,411 @@
+/*
+ * PROJECT: ReactOS api tests
+ * LICENSE: LGPL-2.0-or-later (
https://spdx.org/licenses/LGPL-2.0-or-later)
+ * PURPOSE: Test for Rtl Critical Section API
+ * COPYRIGHT: Copyright 2023 Timo Kreuzer <timo.kreuzer(a)reactos.org>
+ */
+
+#include "precomp.h"
+#include <pseh/pseh2.h>
+
+SYSTEM_INFO g_SysInfo;
+OSVERSIONINFOEXA g_VerInfo;
+ULONG g_Version;
+ULONG g_DefaultSpinCount;
+
+typedef
+NTSTATUS
+NTAPI
+FN_RtlInitializeCriticalSectionEx(
+ _Out_ PRTL_CRITICAL_SECTION CriticalSection,
+ _In_ ULONG SpinCount,
+ _In_ ULONG Flags);
+
+FN_RtlInitializeCriticalSectionEx* pfnRtlInitializeCriticalSectionEx;
+RTL_CRITICAL_SECTION CritSect;
+HANDLE hEventThread1Ready, hEventThread1Cont;
+HANDLE hEventThread2Ready, hEventThread2Cont;
+
+static
+void
+Test_Init(void)
+{
+ NTSTATUS Status;
+ BOOL HasDebugInfo = (g_Version <= _WIN32_WINNT_VISTA);
+
+ _SEH2_TRY
+ {
+ RtlInitializeCriticalSection(NULL);
+ Status = STATUS_SUCCESS;
+ }
+ _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+ {
+ Status = _SEH2_GetExceptionCode();
+ }
+ _SEH2_END;
+ ok_ntstatus(Status, STATUS_ACCESS_VIOLATION);
+
+ Status = RtlInitializeCriticalSection(&CritSect);
+ ok_ntstatus(Status, STATUS_SUCCESS);
+ ok_long(CritSect.LockCount, -1);
+ ok_long(CritSect.RecursionCount, 0);
+ ok_ptr(CritSect.OwningThread, NULL);
+ ok_ptr(CritSect.LockSemaphore, NULL);
+ ok_size_t(CritSect.SpinCount, g_DefaultSpinCount);
+ if (HasDebugInfo)
+ {
+ ok(CritSect.DebugInfo != NULL, "DebugInfo is %p\n",
CritSect.DebugInfo);
+ ok(CritSect.DebugInfo != LongToPtr(-1), "DebugInfo is %p\n",
CritSect.DebugInfo);
+ }
+ else
+ {
+ ok(CritSect.DebugInfo == LongToPtr(-1), "DebugInfo is %p\n",
CritSect.DebugInfo);
+ }
+
+ Status = RtlInitializeCriticalSectionAndSpinCount(&CritSect, 0);
+ ok_ntstatus(Status, STATUS_SUCCESS);
+ ok_long(CritSect.LockCount, -1);
+ ok_long(CritSect.RecursionCount, 0);
+ ok_ptr(CritSect.OwningThread, NULL);
+ ok_ptr(CritSect.LockSemaphore, NULL);
+ ok_size_t(CritSect.SpinCount, g_DefaultSpinCount);
+ if (HasDebugInfo)
+ {
+ ok(CritSect.DebugInfo != NULL, "DebugInfo is %p\n",
CritSect.DebugInfo);
+ ok(CritSect.DebugInfo != LongToPtr(-1), "DebugInfo is %p\n",
CritSect.DebugInfo);
+ }
+ else
+ {
+ ok(CritSect.DebugInfo == LongToPtr(-1), "DebugInfo is %p\n",
CritSect.DebugInfo);
+ }
+
+ Status = RtlInitializeCriticalSectionAndSpinCount(&CritSect, 0xFF000000);
+ ok_ntstatus(Status, STATUS_SUCCESS);
+ ok_size_t(CritSect.SpinCount, g_DefaultSpinCount);
+
+ Status = RtlInitializeCriticalSectionAndSpinCount(&CritSect, 0x1234);
+ ok_ntstatus(Status, STATUS_SUCCESS);
+ ok_size_t(CritSect.SpinCount, (g_SysInfo.dwNumberOfProcessors > 1) ? 0x1234 : 0);
+
+ if (pfnRtlInitializeCriticalSectionEx != NULL)
+ {
+ _SEH2_TRY
+ {
+ pfnRtlInitializeCriticalSectionEx(NULL, 0, 0);
+ Status = STATUS_SUCCESS;
+ }
+ _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+ {
+ Status = _SEH2_GetExceptionCode();
+ }
+ _SEH2_END;
+ ok_ntstatus(Status, STATUS_ACCESS_VIOLATION);
+
+ Status = pfnRtlInitializeCriticalSectionEx(&CritSect, 0, 0);
+ ok_ntstatus(Status, STATUS_SUCCESS);
+ ok_long(CritSect.LockCount, -1);
+ ok_long(CritSect.RecursionCount, 0);
+ ok_ptr(CritSect.OwningThread, NULL);
+ ok_ptr(CritSect.LockSemaphore, NULL);
+ ok_size_t(CritSect.SpinCount, g_DefaultSpinCount);
+ if (HasDebugInfo)
+ {
+ ok(CritSect.DebugInfo != NULL, "DebugInfo is %p\n",
CritSect.DebugInfo);
+ ok(CritSect.DebugInfo != LongToPtr(-1), "DebugInfo is %p\n",
CritSect.DebugInfo);
+ if ((CritSect.DebugInfo != NULL) && (CritSect.DebugInfo !=
LongToPtr(-1)))
+ {
+ ok_int(CritSect.DebugInfo->Type, 0);
+ ok_int(CritSect.DebugInfo->CreatorBackTraceIndex, 0);
+ ok_int(CritSect.DebugInfo->CreatorBackTraceIndexHigh, 0);
+ ok_ptr(CritSect.DebugInfo->CriticalSection, &CritSect);
+ ok(CritSect.DebugInfo->ProcessLocksList.Flink != NULL, "Flink is
NULL\n");
+ ok(CritSect.DebugInfo->ProcessLocksList.Blink != NULL, "Blink is
NULL\n");
+ if ((CritSect.DebugInfo->ProcessLocksList.Flink != NULL) &&
+ (CritSect.DebugInfo->ProcessLocksList.Blink != NULL))
+ {
+ ok_ptr(CritSect.DebugInfo->ProcessLocksList.Flink->Blink,
+ &CritSect.DebugInfo->ProcessLocksList);
+ ok_ptr(CritSect.DebugInfo->ProcessLocksList.Blink->Flink,
+ &CritSect.DebugInfo->ProcessLocksList);
+ }
+ ok_long(CritSect.DebugInfo->EntryCount, 0);
+ ok_long(CritSect.DebugInfo->ContentionCount, 0);
+ ok_long(CritSect.DebugInfo->Flags, 0);
+ ok_int(CritSect.DebugInfo->SpareWORD, 0);
+ }
+ }
+ else
+ {
+ ok(CritSect.DebugInfo == LongToPtr(-1), "DebugInfo is %p\n",
CritSect.DebugInfo);
+ }
+
+ Status = pfnRtlInitializeCriticalSectionEx(&CritSect, 0x00FFFFFF, 0);
+ ok_size_t(CritSect.SpinCount, (g_SysInfo.dwNumberOfProcessors > 1) ?
0x00FFFFFF : 0);
+
+ Status = pfnRtlInitializeCriticalSectionEx(&CritSect, 0x01000000, 0);
+ ok_ntstatus(Status, STATUS_INVALID_PARAMETER_2);
+
+ Status = pfnRtlInitializeCriticalSectionEx(&CritSect, 0x80000000, 0);
+ ok_ntstatus(Status, STATUS_INVALID_PARAMETER_2);
+
+ _SEH2_TRY
+ {
+ Status = pfnRtlInitializeCriticalSectionEx(NULL, 0x12345678, 0);
+ }
+ _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+ {
+ Status = _SEH2_GetExceptionCode();
+ }
+ _SEH2_END;
+ ok_ntstatus(Status, STATUS_INVALID_PARAMETER_2);
+
+ for (ULONG i = 0; i < 32; i++)
+ {
+ ULONG Flags = 1UL << i;
+ ULONG AllowedFlags = 0x07FFFFFF;
+ if (g_Version >= _WIN32_WINNT_WIN7) AllowedFlags |= 0x18000000;
+ NTSTATUS ExpectedStatus = (Flags & ~AllowedFlags) ?
+ STATUS_INVALID_PARAMETER_3 : STATUS_SUCCESS;
+ Status = pfnRtlInitializeCriticalSectionEx(&CritSect, 0, Flags);
+ ok(Status == ExpectedStatus, "Wrong Status (0x%lx) for Flags
0x%lx\n",
+ Status, Flags);
+ if (NT_SUCCESS(Status))
+ {
+ ULONG SetFlags = Flags & 0x08000000;
+ if (g_Version >= _WIN32_WINNT_WIN7) SetFlags |= (Flags &
0x03000000);
+ ok_size_t(CritSect.SpinCount, (g_SysInfo.dwNumberOfProcessors > 1) ?
g_DefaultSpinCount | SetFlags : SetFlags);
+ }
+ }
+
+ Status = pfnRtlInitializeCriticalSectionEx(&CritSect, 0, 0xFFFFFFFF);
+ ok_ntstatus(Status, STATUS_INVALID_PARAMETER_3);
+ _SEH2_TRY
+ {
+ Status = pfnRtlInitializeCriticalSectionEx(NULL, 0, 0xFFFFFFFF);
+ }
+ _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+ {
+ Status = _SEH2_GetExceptionCode();
+ }
+ _SEH2_END;
+ ok_ntstatus(Status, STATUS_INVALID_PARAMETER_3);
+
+ Status = pfnRtlInitializeCriticalSectionEx(&CritSect, 0x12345678,
0xFFFFFFFF);
+ ok_ntstatus(Status, STATUS_INVALID_PARAMETER_3);
+
+ Status = pfnRtlInitializeCriticalSectionEx(&CritSect, 0,
RTL_CRITICAL_SECTION_FLAG_FORCE_DEBUG_INFO);
+ if (g_Version >= _WIN32_WINNT_WIN7)
+ {
+ ok_ntstatus(Status, STATUS_SUCCESS);
+ ok(CritSect.DebugInfo != NULL, "DebugInfo is %p\n",
CritSect.DebugInfo);
+ ok(CritSect.DebugInfo != LongToPtr(-1), "DebugInfo is %p\n",
CritSect.DebugInfo);
+ if ((CritSect.DebugInfo != NULL) && (CritSect.DebugInfo !=
LongToPtr(-1)))
+ {
+ ok_int(CritSect.DebugInfo->Type, 0);
+ ok_int(CritSect.DebugInfo->CreatorBackTraceIndex, 0);
+ ok_int(CritSect.DebugInfo->CreatorBackTraceIndexHigh, 0);
+ ok_ptr(CritSect.DebugInfo->CriticalSection, &CritSect);
+ ok(CritSect.DebugInfo->ProcessLocksList.Flink != NULL, "Flink is
NULL\n");
+ ok(CritSect.DebugInfo->ProcessLocksList.Blink != NULL, "Blink is
NULL\n");
+ if ((CritSect.DebugInfo->ProcessLocksList.Flink != NULL) &&
+ (CritSect.DebugInfo->ProcessLocksList.Blink != NULL))
+ {
+ ok_ptr(CritSect.DebugInfo->ProcessLocksList.Flink->Blink,
+ &CritSect.DebugInfo->ProcessLocksList);
+ ok_ptr(CritSect.DebugInfo->ProcessLocksList.Blink->Flink,
+ &CritSect.DebugInfo->ProcessLocksList);
+ }
+ ok_long(CritSect.DebugInfo->EntryCount, 0);
+ ok_long(CritSect.DebugInfo->ContentionCount, 0);
+ ok_long(CritSect.DebugInfo->Flags, 0);
+ ok_int(CritSect.DebugInfo->SpareWORD, 0);
+ }
+ }
+ else
+ {
+ ok_ntstatus(Status, STATUS_INVALID_PARAMETER_3);
+ }
+ }
+ else
+ {
+ skip("RtlInitializeCriticalSectionEx not available.\n");
+ }
+}
+
+static
+DWORD
+WINAPI
+ThreadProc1(
+ _In_ LPVOID lpParameter)
+{
+ printf("ThreadProc1 starting\n");
+ RtlEnterCriticalSection(&CritSect);
+
+ SetEvent(hEventThread1Ready);
+
+ printf("ThreadProc1 waiting\n");
+ WaitForSingleObject(hEventThread1Cont, INFINITE);
+ printf("ThreadProc1 returned from wait\n");
+
+ RtlLeaveCriticalSection(&CritSect);
+
+ return 0;
+}
+
+static
+DWORD
+WINAPI
+ThreadProc2(
+ _In_ LPVOID lpParameter)
+{
+ printf("ThreadProc2 starting\n");
+ RtlEnterCriticalSection(&CritSect);
+
+ SetEvent(hEventThread2Ready);
+
+ printf("ThreadProc2 waiting\n");
+ WaitForSingleObject(hEventThread2Cont, INFINITE);
+ printf("ThreadProc2 returned from wait\n");
+
+ RtlLeaveCriticalSection(&CritSect);
+
+ return 0;
+}
+
+static
+void
+Test_Acquire(void)
+{
+ DWORD dwThreadId1, dwThreadId2;
+ HANDLE hThread1, hThread2;
+
+ RtlInitializeCriticalSection(&CritSect);
+
+ // Acquire once
+ RtlEnterCriticalSection(&CritSect);
+ ok_long(CritSect.LockCount, -2);
+ ok_long(CritSect.RecursionCount, 1);
+ ok_ptr(CritSect.OwningThread, UlongToHandle(GetCurrentThreadId()));
+ ok_ptr(CritSect.LockSemaphore, NULL);
+ ok_size_t(CritSect.SpinCount, g_DefaultSpinCount);
+
+ // Acquire recursively
+ RtlEnterCriticalSection(&CritSect);
+ ok_long(CritSect.LockCount, -2);
+ ok_long(CritSect.RecursionCount, 2);
+ ok_ptr(CritSect.OwningThread, UlongToHandle(GetCurrentThreadId()));
+ ok_ptr(CritSect.LockSemaphore, NULL);
+ ok_size_t(CritSect.SpinCount, g_DefaultSpinCount);
+
+ hEventThread1Ready = CreateEvent(NULL, TRUE, FALSE, NULL);
+ hEventThread1Cont = CreateEvent(NULL, TRUE, FALSE, NULL);
+ hEventThread2Ready = CreateEvent(NULL, TRUE, FALSE, NULL);
+ hEventThread2Cont = CreateEvent(NULL, TRUE, FALSE, NULL);
+
+ // Create thread 1 and wait to it time to try to acquire the critical section
+ hThread1 = CreateThread(NULL, 0, ThreadProc1, NULL, 0, &dwThreadId1);
+
+ // Wait up to 10 s
+ for (ULONG i = 0; (CritSect.LockCount == -2) && (i < 1000); i++)
+ {
+ Sleep(10);
+ }
+
+ ok_long(CritSect.LockCount, -6);
+ ok_long(CritSect.RecursionCount, 2);
+ ok_ptr(CritSect.OwningThread, UlongToHandle(GetCurrentThreadId()));
+ //ok_ptr(CritSect.LockSemaphore, LongToPtr(-1)); // TODO: this behaves differently on
different OS versions
+ ok_size_t(CritSect.SpinCount, g_DefaultSpinCount);
+
+ // Create thread 2 and wait to it time to try to acquire the critical section
+ hThread2 = CreateThread(NULL, 0, ThreadProc2, NULL, 0, &dwThreadId2);
+
+ // Wait up to 10 s
+ for (ULONG i = 0; (CritSect.LockCount == -6) && (i < 1000); i++)
+ {
+ Sleep(10);
+ }
+
+ ok_long(CritSect.LockCount, -10);
+ ok_long(CritSect.RecursionCount, 2);
+ ok_ptr(CritSect.OwningThread, UlongToHandle(GetCurrentThreadId()));
+ //ok_ptr(CritSect.LockSemaphore, LongToPtr(-1));
+ ok_size_t(CritSect.SpinCount, g_DefaultSpinCount);
+
+ RtlLeaveCriticalSection(&CritSect);
+ ok_long(CritSect.LockCount, -10);
+ ok_long(CritSect.RecursionCount, 1);
+ RtlLeaveCriticalSection(&CritSect);
+
+ // Wait until thread 1 has acquired the critical section
+ WaitForSingleObject(hEventThread1Ready, INFINITE);
+
+ ok_long(CritSect.LockCount, -6);
+ ok_long(CritSect.RecursionCount, 1);
+ ok_ptr(CritSect.OwningThread, UlongToHandle(dwThreadId1));
+ //ok_ptr(CritSect.LockSemaphore, LongToPtr(-1));
+ if (g_DefaultSpinCount != 0)
+ {
+ ok(CritSect.SpinCount <= g_DefaultSpinCount, "SpinCount
increased\n");
+ }
+ else
+ {
+ ok_size_t(CritSect.SpinCount, g_DefaultSpinCount);
+ }
+
+ ok_size_t(CritSect.SpinCount, g_DefaultSpinCount ? g_DefaultSpinCount - 1 : 0);
+
+ // Release thread 1, wait for thread 2 to acquire the critical section
+ SetEvent(hEventThread1Cont);
+ WaitForSingleObject(hEventThread2Ready, INFINITE);
+
+ ok_long(CritSect.LockCount, -2);
+ ok_long(CritSect.RecursionCount, 1);
+ ok_ptr(CritSect.OwningThread, UlongToHandle(dwThreadId2));
+ //ok_ptr(CritSect.LockSemaphore, LongToPtr(-1));
+ if (g_DefaultSpinCount != 0)
+ {
+ ok(CritSect.SpinCount <= g_DefaultSpinCount, "SpinCount
increased\n");
+ }
+ else
+ {
+ ok_size_t(CritSect.SpinCount, g_DefaultSpinCount);
+ }
+
+ // Release thread 2
+ SetEvent(hEventThread2Cont);
+
+ // To make Thomas happy :)
+ WaitForSingleObject(hThread1, INFINITE);
+ WaitForSingleObject(hThread2, INFINITE);
+}
+
+START_TEST(RtlCriticalSection)
+{
+ HMODULE hmodNtDll = GetModuleHandleA("ntdll.dll");
+ pfnRtlInitializeCriticalSectionEx = (FN_RtlInitializeCriticalSectionEx*)
+ GetProcAddress(hmodNtDll, "RtlInitializeCriticalSectionEx");
+
+ g_VerInfo.dwOSVersionInfoSize = sizeof(g_VerInfo);
+ GetVersionExA((LPOSVERSIONINFOA)&g_VerInfo);
+ g_Version = g_VerInfo.dwMajorVersion << 8 | g_VerInfo.dwMinorVersion;
+ printf("g_VerInfo: %lu.%lu.%lu ('%s')\n ",
+ g_VerInfo.dwMajorVersion,
+ g_VerInfo.dwMinorVersion,
+ g_VerInfo.dwBuildNumber,
+ g_VerInfo.szCSDVersion);
+ GetSystemInfo(&g_SysInfo);
+ printf("g_SysInfo.dwNumberOfProcessors = %lu\n",
g_SysInfo.dwNumberOfProcessors);
+
+ if ((g_Version >= _WIN32_WINNT_VISTA) && (g_SysInfo.dwNumberOfProcessors
> 1))
+ {
+ g_DefaultSpinCount = 0x20007d0;
+ }
+ else
+ {
+ g_DefaultSpinCount = 0;
+ }
+
+ Test_Init();
+ Test_Acquire();
+}
diff --git a/modules/rostests/apitests/ntdll/testlist.c
b/modules/rostests/apitests/ntdll/testlist.c
index 7f80f42420b..2be58938238 100644
--- a/modules/rostests/apitests/ntdll/testlist.c
+++ b/modules/rostests/apitests/ntdll/testlist.c
@@ -55,6 +55,7 @@ extern void func_RtlAllocateHeap(void);
extern void func_RtlBitmap(void);
extern void func_RtlComputePrivatizedDllName_U(void);
extern void func_RtlCopyMappedMemory(void);
+extern void func_RtlCriticalSection(void);
extern void func_RtlDebugInformation(void);
extern void func_RtlDeleteAce(void);
extern void func_RtlDetermineDosPathNameType(void);
@@ -150,6 +151,7 @@ const struct test winetest_testlist[] =
{ "RtlBitmapApi", func_RtlBitmap },
{ "RtlComputePrivatizedDllName_U", func_RtlComputePrivatizedDllName_U },
{ "RtlCopyMappedMemory", func_RtlCopyMappedMemory },
+ { "RtlCriticalSection", func_RtlCriticalSection },
{ "RtlDebugInformation", func_RtlDebugInformation },
{ "RtlDeleteAce", func_RtlDeleteAce },
{ "RtlDetermineDosPathNameType", func_RtlDetermineDosPathNameType },
diff --git a/sdk/include/xdk/winnt_old.h b/sdk/include/xdk/winnt_old.h
index 7e564277b9a..15d353fc9ef 100644
--- a/sdk/include/xdk/winnt_old.h
+++ b/sdk/include/xdk/winnt_old.h
@@ -1116,7 +1116,19 @@ typedef VOID (NTAPI *WORKERCALLBACKFUNC)(PVOID);
#define IO_REPARSE_TAG_MOUNT_POINT 0xA0000003
#define IO_REPARSE_TAG_SYMLINK 0xA000000CL
-#define RTL_CRITICAL_SECTION_FLAG_NO_DEBUG_INFO 0x01000000
+#define RTL_CRITICAL_SECTION_FLAG_NO_DEBUG_INFO 0x01000000
+#define RTL_CRITICAL_SECTION_FLAG_DYNAMIC_SPIN 0x02000000
+#define RTL_CRITICAL_SECTION_FLAG_STATIC_INIT 0x04000000
+#define RTL_CRITICAL_SECTION_FLAG_RESOURCE_TYPE 0x08000000
+#define RTL_CRITICAL_SECTION_FLAG_FORCE_DEBUG_INFO 0x10000000
+#define RTL_CRITICAL_SECTION_ALL_FLAG_BITS 0xFF000000
+#define RTL_CRITICAL_SECTION_FLAG_RESERVED \
+ (RTL_CRITICAL_SECTION_ALL_FLAG_BITS & \
+ (~(RTL_CRITICAL_SECTION_FLAG_NO_DEBUG_INFO | \
+ RTL_CRITICAL_SECTION_FLAG_DYNAMIC_SPIN | \
+ RTL_CRITICAL_SECTION_FLAG_STATIC_INIT | \
+ RTL_CRITICAL_SECTION_FLAG_RESOURCE_TYPE | \
+ RTL_CRITICAL_SECTION_FLAG_FORCE_DEBUG_INFO)))
#ifndef RC_INVOKED