{
if (strncmp(client->settings->ChannelDefArray[i].Name, "rdpdbg", 6) == 0)
{
- context->debug_channel = WTSVirtualChannelOpenEx(context->vcm, "rdpdbg", 0);
+ context->debug_channel = WTSVirtualChannelManagerOpenEx(context->vcm, "rdpdbg", 0);
if (context->debug_channel != NULL)
{
{
if (context->debug_channel)
{
- WTSVirtualChannelWrite(context->debug_channel, (BYTE*) "test2", 5, NULL);
+ WTSVirtualChannelWrite(context->debug_channel, (PCHAR) "test2", 5, NULL);
}
}
else if ((flags & 0x4000) && code == 0x2D) /* 'x' key */
--- /dev/null
+/**
+ * WinPR: Windows Portable Runtime
+ * Windows Native System Services
+ *
+ * Copyright 2013 Marc-Andre Moreau <marcandre.moreau@gmail.com>
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef WINPR_NT_H
+#define WINPR_NT_H
+
+#include <winpr/winpr.h>
+#include <winpr/wtypes.h>
+
+#ifndef _WIN32
+
+typedef struct _PEB PEB;
+typedef struct _PEB* PPEB;
+
+typedef struct _TEB TEB;
+typedef struct _TEB* PTEB;
+
+/**
+ * Process Environment Block
+ */
+
+struct _THREAD_BLOCK_ID
+{
+ DWORD ThreadId;
+ TEB* ThreadEnvironmentBlock;
+};
+typedef struct _THREAD_BLOCK_ID THREAD_BLOCK_ID;
+
+struct _PEB
+{
+ DWORD ThreadCount;
+ DWORD ThreadArraySize;
+ THREAD_BLOCK_ID* Threads;
+};
+
+/*
+ * Thread Environment Block
+ */
+
+struct _TEB
+{
+ PEB* ProcessEnvironmentBlock;
+
+ DWORD LastErrorValue;
+ PVOID TlsSlots[64];
+};
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+WINPR_API PTEB NtCurrentTeb(void);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+
+#endif /* WINPR_NT_H */
+
set_target_properties(${MODULE_NAME} PROPERTIES VERSION ${WINPR_VERSION_FULL} SOVERSION ${WINPR_VERSION} PREFIX "lib")
+set_complex_link_libraries(VARIABLE ${MODULE_PREFIX}_LIBS
+ MONOLITHIC ${MONOLITHIC_BUILD} INTERNAL
+ MODULE winpr
+ MODULES winpr-nt)
+
if(MONOLITHIC_BUILD)
else()
+ target_link_libraries(${MODULE_NAME} ${${MODULE_PREFIX}_LIBS})
install(TARGETS ${MODULE_NAME} DESTINATION ${CMAKE_INSTALL_LIBDIR})
endif()
set_property(TARGET ${MODULE_NAME} PROPERTY FOLDER "WinPR")
+
+if(BUILD_TESTING)
+ add_subdirectory(test)
+endif()
#include <winpr/error.h>
-/**
- * api-ms-win-core-errorhandling-l1-1-1.dll:
- *
- * GetErrorMode
- * SetErrorMode
- * GetLastError
- * SetLastError
- * RestoreLastError
- * RaiseException
- * UnhandledExceptionFilter
- * SetUnhandledExceptionFilter
- * AddVectoredExceptionHandler
- * RemoveVectoredExceptionHandler
- * AddVectoredContinueHandler
- * RemoveVectoredContinueHandler
- */
-
#ifndef _WIN32
+#include <stdio.h>
+
+#include <winpr/nt.h>
+
UINT GetErrorMode(void)
{
return 0;
DWORD GetLastError(VOID)
{
- return 0;
+ return NtCurrentTeb()->LastErrorValue;
}
VOID SetLastError(DWORD dwErrCode)
{
-
+ NtCurrentTeb()->LastErrorValue = dwErrCode;
}
VOID RestoreLastError(DWORD dwErrCode)
--- /dev/null
+TestError
+TestError.c
+
--- /dev/null
+
+set(MODULE_NAME "TestError")
+set(MODULE_PREFIX "TEST_ERROR")
+
+set(${MODULE_PREFIX}_DRIVER ${MODULE_NAME}.c)
+
+set(${MODULE_PREFIX}_TESTS
+ TestErrorSetLastError.c)
+
+create_test_sourcelist(${MODULE_PREFIX}_SRCS
+ ${${MODULE_PREFIX}_DRIVER}
+ ${${MODULE_PREFIX}_TESTS})
+
+add_executable(${MODULE_NAME} ${${MODULE_PREFIX}_SRCS})
+
+set_complex_link_libraries(VARIABLE ${MODULE_PREFIX}_LIBS
+ MONOLITHIC ${MONOLITHIC_BUILD}
+ MODULE winpr
+ MODULES winpr-crt winpr-synch winpr-thread winpr-error)
+
+target_link_libraries(${MODULE_NAME} ${${MODULE_PREFIX}_LIBS})
+
+set_target_properties(${MODULE_NAME} PROPERTIES RUNTIME_OUTPUT_DIRECTORY "${TESTING_OUTPUT_DIRECTORY}")
+
+foreach(test ${${MODULE_PREFIX}_TESTS})
+ get_filename_component(TestName ${test} NAME_WE)
+ add_test(${TestName} ${TESTING_OUTPUT_DIRECTORY}/${MODULE_NAME} ${TestName})
+endforeach()
+
+set_property(TARGET ${MODULE_NAME} PROPERTY FOLDER "WinPR/Test")
+
--- /dev/null
+
+#include <winpr/crt.h>
+#include <winpr/synch.h>
+#include <winpr/thread.h>
+
+#include <winpr/error.h>
+
+static int status = 0;
+
+static DWORD errors[4] =
+{
+ ERROR_INVALID_DATA,
+ ERROR_BROKEN_PIPE,
+ ERROR_INVALID_NAME,
+ ERROR_BAD_ARGUMENTS
+};
+
+static void* test_error_thread(void* arg)
+{
+ int id;
+ DWORD error;
+
+ id = (int) (size_t) arg;
+
+ error = errors[id];
+
+ SetLastError(error);
+
+ Sleep(10);
+
+ error = GetLastError();
+
+ if (error != errors[id])
+ {
+ printf("GetLastError() failure (thread %d): Expected: 0x%04X, Actual: 0x%04X\n",
+ id, errors[id], error);
+
+ if (!status)
+ status = -1;
+
+ return NULL;
+ }
+
+ return NULL;
+}
+
+int TestErrorSetLastError(int argc, char* argv[])
+{
+ DWORD error;
+ HANDLE threads[4];
+
+ SetLastError(ERROR_ACCESS_DENIED);
+
+ error = GetLastError();
+
+ if (error != ERROR_ACCESS_DENIED)
+ {
+ printf("GetLastError() failure: Expected: 0x%04X, Actual: 0x%04X\n",
+ ERROR_ACCESS_DENIED, error);
+ return -1;
+ }
+
+ threads[0] = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) test_error_thread, (void*) (size_t) 0, 0, NULL);
+ threads[1] = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) test_error_thread, (void*) (size_t) 1, 0, NULL);
+ threads[2] = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) test_error_thread, (void*) (size_t) 2, 0, NULL);
+ threads[3] = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) test_error_thread, (void*) (size_t) 3, 0, NULL);
+
+ WaitForSingleObject(threads[0], INFINITE);
+ WaitForSingleObject(threads[1], INFINITE);
+ WaitForSingleObject(threads[2], INFINITE);
+ WaitForSingleObject(threads[3], INFINITE);
+
+ CloseHandle(threads[0]);
+ CloseHandle(threads[1]);
+ CloseHandle(threads[2]);
+ CloseHandle(threads[3]);
+
+ error = GetLastError();
+
+ if (error != ERROR_ACCESS_DENIED)
+ {
+ printf("GetLastError() failure: Expected: 0x%04X, Actual: 0x%04X\n",
+ ERROR_ACCESS_DENIED, error);
+ return -1;
+ }
+
+ return status;
+}
+
--- /dev/null
+# WinPR: Windows Portable Runtime
+# libwinpr-nt cmake build script
+#
+# Copyright 2012 Marc-Andre Moreau <marcandre.moreau@gmail.com>
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+set(MODULE_NAME "winpr-nt")
+set(MODULE_PREFIX "WINPR_NT")
+
+set(${MODULE_PREFIX}_SRCS
+ nt.c)
+
+if(MSVC AND (NOT MONOLITHIC_BUILD))
+ set(${MODULE_PREFIX}_SRCS ${${MODULE_PREFIX}_SRCS} module.def)
+endif()
+
+add_complex_library(MODULE ${MODULE_NAME} TYPE "OBJECT"
+ MONOLITHIC ${MONOLITHIC_BUILD}
+ SOURCES ${${MODULE_PREFIX}_SRCS})
+
+set_target_properties(${MODULE_NAME} PROPERTIES VERSION ${WINPR_VERSION_FULL} SOVERSION ${WINPR_VERSION} PREFIX "lib")
+
+set(${MODULE_PREFIX}_LIBS
+ ${CMAKE_THREAD_LIBS_INIT}
+ ${CMAKE_DL_LIBS})
+
+if(${CMAKE_SYSTEM_NAME} MATCHES SunOS)
+ set(${MODULE_PREFIX}_LIBS ${${MODULE_PREFIX}_LIBS} rt)
+endif()
+
+if(MONOLITHIC_BUILD)
+ set(WINPR_LIBS ${WINPR_LIBS} ${${MODULE_PREFIX}_LIBS} PARENT_SCOPE)
+else()
+ target_link_libraries(${MODULE_NAME} ${${MODULE_PREFIX}_LIBS})
+ install(TARGETS ${MODULE_NAME} DESTINATION ${CMAKE_INSTALL_LIBDIR})
+endif()
+
+set_property(TARGET ${MODULE_NAME} PROPERTY FOLDER "WinPR")
+
+if(BUILD_TESTING)
+ add_subdirectory(test)
+endif()
--- /dev/null
+
+set(MINWIN_LAYER "0")
+set(MINWIN_GROUP "none")
+set(MINWIN_MAJOR_VERSION "0")
+set(MINWIN_MINOR_VERSION "0")
+set(MINWIN_SHORT_NAME "nt")
+set(MINWIN_LONG_NAME "Windows Native System Services")
+set(MODULE_LIBRARY_NAME "${MINWIN_SHORT_NAME}")
--- /dev/null
+LIBRARY "libwinpr-nt"
+EXPORTS
+
--- /dev/null
+/**
+ * WinPR: Windows Portable Runtime
+ * Windows Native System Services
+ *
+ * Copyright 2013 Marc-Andre Moreau <marcandre.moreau@gmail.com>
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <winpr/nt.h>
+
+/**
+ * NtXxx Routines:
+ * http://msdn.microsoft.com/en-us/library/windows/hardware/ff557720/
+ */
+
+#ifndef _WIN32
+
+#include <pthread.h>
+
+#include <winpr/crt.h>
+
+/**
+ * The current implementation of NtCurrentTeb() is not the most efficient
+ * but it's a starting point. Beware of potential performance bottlenecks
+ * caused by multithreaded usage of SetLastError/GetLastError.
+ */
+
+static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
+
+static PPEB g_ProcessEnvironmentBlock = NULL;
+
+static void NtThreadEnvironmentBlockFree(PTEB teb);
+static void NtProcessEnvironmentBlockFree(PPEB peb);
+
+static PTEB NtThreadEnvironmentBlockNew()
+{
+ PTEB teb = NULL;
+ pthread_key_t key;
+
+ teb = (PTEB) malloc(sizeof(TEB));
+
+ if (teb)
+ {
+ ZeroMemory(teb, sizeof(TEB));
+
+ /**
+ * We are not really using the key, but it provides an automatic way
+ * of calling NtThreadEnvironmentBlockFree on thread termination for
+ * the current Thread Environment Block.
+ */
+
+ pthread_key_create(&key, (void (*)(void*)) NtThreadEnvironmentBlockFree);
+ pthread_setspecific(key, (void*) teb);
+ }
+
+ return teb;
+}
+
+static void NtThreadEnvironmentBlockFree(PTEB teb)
+{
+ DWORD index;
+ PPEB peb = NULL;
+
+ peb = teb->ProcessEnvironmentBlock;
+
+ pthread_mutex_lock(&mutex);
+
+ for (index = 0; index < peb->ThreadArraySize; index++)
+ {
+ if (peb->Threads[index].ThreadEnvironmentBlock == teb)
+ {
+ peb->Threads[index].ThreadId = 0;
+ peb->Threads[index].ThreadEnvironmentBlock = NULL;
+ peb->ThreadCount--;
+ break;
+ }
+ }
+
+ if (!peb->ThreadCount)
+ {
+ NtProcessEnvironmentBlockFree(peb);
+ }
+
+ pthread_mutex_unlock(&mutex);
+
+ free(teb);
+}
+
+static PPEB NtProcessEnvironmentBlockNew()
+{
+ PPEB peb = NULL;
+
+ peb = (PPEB) malloc(sizeof(PEB));
+
+ if (peb)
+ {
+ ZeroMemory(peb, sizeof(PEB));
+
+ peb->ThreadCount = 0;
+ peb->ThreadArraySize = 64;
+ peb->Threads = (THREAD_BLOCK_ID*) malloc(sizeof(THREAD_BLOCK_ID) * peb->ThreadArraySize);
+
+ if (peb->Threads)
+ {
+ ZeroMemory(peb->Threads, sizeof(THREAD_BLOCK_ID) * peb->ThreadArraySize);
+ }
+ }
+
+ return peb;
+}
+
+static void NtProcessEnvironmentBlockFree(PPEB peb)
+{
+ if (peb)
+ {
+ free(peb->Threads);
+ free(peb);
+ }
+
+ g_ProcessEnvironmentBlock = NULL;
+}
+
+PPEB NtCurrentPeb(void)
+{
+ PPEB peb = NULL;
+
+ pthread_mutex_lock(&mutex);
+
+ if (!g_ProcessEnvironmentBlock)
+ g_ProcessEnvironmentBlock = NtProcessEnvironmentBlockNew();
+
+ peb = g_ProcessEnvironmentBlock;
+
+ pthread_mutex_unlock(&mutex);
+
+ return peb;
+}
+
+PTEB NtCurrentTeb(void)
+{
+ DWORD index;
+ int freeIndex;
+ DWORD ThreadId;
+ PPEB peb = NULL;
+ PTEB teb = NULL;
+
+ peb = NtCurrentPeb();
+
+ ThreadId = (DWORD) pthread_self();
+
+ freeIndex = -1;
+
+ pthread_mutex_lock(&mutex);
+
+ for (index = 0; index < peb->ThreadArraySize; index++)
+ {
+ if (!peb->Threads[index].ThreadId)
+ {
+ if (freeIndex < 0)
+ freeIndex = (int) index;
+ }
+
+ if (peb->Threads[index].ThreadId == ThreadId)
+ {
+ teb = peb->Threads[index].ThreadEnvironmentBlock;
+ break;
+ }
+ }
+
+ if (!teb)
+ {
+ if (freeIndex >= 0)
+ {
+ teb = NtThreadEnvironmentBlockNew();
+ peb->Threads[freeIndex].ThreadEnvironmentBlock = teb;
+ peb->Threads[freeIndex].ThreadId = ThreadId;
+ peb->ThreadCount++;
+
+ teb->ProcessEnvironmentBlock = peb;
+ teb->LastErrorValue = 0;
+ }
+ }
+
+ pthread_mutex_unlock(&mutex);
+
+ return teb;
+}
+
+#endif
+
--- /dev/null
+TestNt
+TestNt.c
+
--- /dev/null
+
+set(MODULE_NAME "TestNt")
+set(MODULE_PREFIX "TEST_NT")
+
+set(${MODULE_PREFIX}_DRIVER ${MODULE_NAME}.c)
+
+set(${MODULE_PREFIX}_TESTS
+ TestNtCreateFile.c
+ TestNtCurrentTeb.c)
+
+create_test_sourcelist(${MODULE_PREFIX}_SRCS
+ ${${MODULE_PREFIX}_DRIVER}
+ ${${MODULE_PREFIX}_TESTS})
+
+add_executable(${MODULE_NAME} ${${MODULE_PREFIX}_SRCS})
+
+set_complex_link_libraries(VARIABLE ${MODULE_PREFIX}_LIBS
+ MONOLITHIC ${MONOLITHIC_BUILD}
+ MODULE winpr
+ MODULES winpr-crt winpr-nt)
+
+target_link_libraries(${MODULE_NAME} ${${MODULE_PREFIX}_LIBS})
+
+set_target_properties(${MODULE_NAME} PROPERTIES RUNTIME_OUTPUT_DIRECTORY "${TESTING_OUTPUT_DIRECTORY}")
+
+foreach(test ${${MODULE_PREFIX}_TESTS})
+ get_filename_component(TestName ${test} NAME_WE)
+ add_test(${TestName} ${TESTING_OUTPUT_DIRECTORY}/${MODULE_NAME} ${TestName})
+endforeach()
+
+set_property(TARGET ${MODULE_NAME} PROPERTY FOLDER "WinPR/Test")
+
--- /dev/null
+
+#include <winpr/nt.h>
+
+int TestNtCreateFile(int argc, char* argv[])
+{
+ return 0;
+}
+
--- /dev/null
+
+#include <stdio.h>
+
+#include <winpr/nt.h>
+
+int TestNtCurrentTeb(int argc, char* argv[])
+{
+ PTEB teb;
+
+ teb = NtCurrentTeb();
+
+ if (!teb)
+ {
+ printf("NtCurrentTeb() returned NULL\n");
+ return -1;
+ }
+
+ return 0;
+}
+