Modified Kernel APIs (Windows Embedded CE 6.0)

1/6/2010

The following table shows the kernel APIs that have been modified for Windows Embedded CE 6.0, and compares the modification with the functionality from Windows CE 5.0.

Function Windows CE 5.0 CE 6.0

ActivateDevice

ActivateDeviceEx

Driver that is loading flags did not account for kernel-mode or user-mode drivers.

Driver-loaded flags account for kernel-mode and user-mode drivers.

CeGetCallerTrust

CeGetCurrentTrust

These functions check the trust level of the process.

The trusted-level mechanism is obsolete. Applications are always trusted in kernel mode and untrusted in user mode. In CE 6.0, all applications that are allowed to run are considered trusted.

CreateFiber

A thread could not be converted to a fiber if the stack size of the thread was different from the process default stack size set by the /STACK linker setting.

A thread can be converted to a fiber, even if the stack size of the thread is different from the process default stack size set by the /STACK linker setting.

File Mapping Functions:

CreateFileForMapping

CreateFileMapping

FlushViewOfFile

MapViewOfFile

UnmapViewOfFile

Memory-mapped files are mapped in a shared address space.

For example, in Windows CE 5.0, a memory-mapped file object, that was opened both by the kernel and by applications was accessed at the same address by all processes.

Memory-mapped files are mapped in the address space of the process, so it is not possible to pass memory-mapped file pointers between processes. Each process must open the memory-mapped file.

A RAM-backed memory-mapped file is not associated with a real file. If two user-mode processes open the same RAM-backed memory-mapped file, they get the same address because applications can use self-referential pointers in the buffer. If the mapping is shared between kernel mode and user mode, the kernel-mode view is at a different address than the user-mode view. If the mapping is file-backed, the mapping can be located at a different address in one process than in another process, or even between two user-mode processes. Therefore, instead of storing pointers in the mapping, you must use buffer offsets to refer to locations inside the mapping.

In Windows Embedded CE 6.0, buffer offset values, rather than pointers, are used to access the active data.

CreateMsgQueue

The message queue managed the creation of named message queues, and the message queue keeps track of the number of readers and writers in the MSGQUEUEINFO structure. Handles were reference counted.

Flags sent to CreateMsgQueue were not validated.

The handle infrastructure manages message queues. For named message queues, two separate events are required, so the read and write ends of the named message queue are prefixed with "R:" and "W:". To account for the "R:" or "W:" in the message queue length, the lpszName parameter cannot be set to a length larger than (MAX_PATH - 2).

The parameters for this function are validated so that if CreateMsgQueue is called with flags other than MSGQUEUE_NOPRECOMMIT or MSGQUEUE_ALLOW_BROKEN, the call fails, and the last error is set to ERROR_INVALID_PARAMETER.

CreateProcess

An application that called the CreateProcess function had full access to the process handle that was created.

Default functionality allowed the application that called CreateProcess to have full access to the process handle that was created.

Because API privileges are not implemented, process and thread handles returned from CreateProcess calls are real handles that you can use in other process-related calls, such as TerminateProcess, ReadProcessMemory, and WriteProcessMemory. The period following process keeps the code working, even in releases in which API privileges might be enabled:

  • After a successful call to CreateProcess, close the process and thread handle.
  • Make a call to OpenProcess and OpenThread by using the process and thread identifier that is returned in the PROCESS_INFORMATION structure.
  • Use the handle that is returned by OpenProcess and OpenThread to call into other process-related and thread-related APIs.

The process and thread handles that are returned by CreateProcess can be used only for signaling purposes, such as waiting with WaitForSingleObject, WaitForMultipleObjects, and ResumeThread. This process or thread wait-only handle can also be used for querying the exit code of the process or thread with the GetExitCodeProcess and the GetExitCodeThread functions. To get a handle with full access to the process object, you must call OpenProcess with the process identifier. However, OpenProcess requires the caller to have API privileges to access the process that is being opened, so it might not be possible for all callers to open the process.

The process and thread handles are returned in the PROCESS_INFORMATION structure. Functions such as ReadProcessMemory, WriteProcessMemory, and TerminateProcess must use the handle that is returned from OpenProcess.

This prevents an untrusted application from having full access to the process handle of the trusted application that it started. To obtain access to the space of the created process, the application must call the OpenProcess function to obtain a full handle to the process. OpenProcess checks the trust level of the caller before returning a handle to the process.

This change allows an untrusted application to create a trusted application without compromising the security of the trusted application. For example, a shell can start an administrative or a digital rights management (DRM) application without automatically giving it control over that application.

CreateWatchDogTimer

If a watchdog timer existed, the handle to the existing watchdog timer was returned, and GetLastError returned ERROR_ALREADY_EXISTS.

If a watchdog timer exists, a new handle is returned to the same object, and GetLastError returns ERROR_ALREADY_EXISTS.

DuplicateHandle

This function could duplicate handles to events, mutexes, and semaphores.

This function can duplicate all real handles, not just handles to events, mutexes, and semaphores. All real handles include: event handles, mutex handles, API-set handles, file handles, database-file handles, semaphore handles, memory-map handles, watchdog handles, process handles, thread handles, token handles, and any handles that are generated by a handle server.

GetProcAddress

LoadLibraryEx

If a DLL was loaded by using LOAD_LIBRARY_AS_DATAFILE, you could not obtain function pointers within that module. As a result, if the DLL was loaded as a data file, and you called GetProcAddress and passed in a handle that was returned by LoadLibraryEx, the function pointer returned was NULL. In previous releases, this scenario returned a non-NULL pointer, but using that pointer results in undefined behavior and could potentially cause a failure in the calling thread.

LoadLibraryEx and GetProcAddress have been changed to bring them into conformance with expected behavior and to prevent undefined behavior.

If a DLL is loaded by using LOAD_LIBRARY_AS_DATAFILE, you cannot obtain function pointers within that module. As a result, if the DLL is loaded as a data file and you call GetProcAddress and pass in a handle that is returned by LoadLibraryEx, the function pointer that is returned is NULL.

If you were relying on GetProcAddress to return a non-NULL pointer for a module that is loaded with LOAD_LIBRARY_AS_DATAFILE flag, you can modify the call as follows. Change:

HMODULE hmod = LoadLibraryEx(<dllname>, 0, LOAD_LIBRARY_AS_DATAFILE);

To:

HMODULE hmod = LoadLibraryEx(<dllname>, 0, DONT_RESOLVE_DLL_REFERENCES);

HeapCreate

Only applications running in kernel mode could create a shared heap.

Only kernel-mode code can call HeapCreate with HEAP_SHARED_READONLY.

OpenMsgQueue

If a message queue existed, the handle to the existing message queue was returned, and GetLastError returned ERROR_ALREADY_EXISTS.

If a message queue exists, a new handle is returned to the same object, and GetLastError returns ERROR_ALREADY_EXISTS.

OpenProcess

This function did not support fdwAccess or fInherit.

This function supports fdwAccess and fInherit.

TerminateThread

Permitted calling TerminateThread on kernel thread. This had the following disadvantages:

  • Possible kernel heap corruption if the thread is in the middle of a heap allocation.
  • Possible resource leak: the thread incremented the reference count of an object and was terminated.
  • Possible corrupted DLL if the thread is in the middle of LoadLibrary, doing import, and so on.
  • Possible deadlock: holding a lock while being terminated and need to acquire loader lock on its way to exit.

Calling TerminateThread on the kernel always fails.

VirtualAlloc

User application could call VirtualAlloc function with a size more than 2 MB, in which case kernel would reserve the virtual memory in the shared heap region.

User applications cannot call VirtualAlloc with shared heap address range (0x70000000 to 0x7fffffff) because this is read-only for user applications and read/write for kernel mode.

Remarks

To share memory between user applications, possible solutions in CE 6.0 are the following:

  • Message queues.
  • Memory-mapped files, with or without file backing.
  • Remote heap.

See Also

Concepts

Obsolete Kernel APIs
New Kernel APIs
Kernel Mode APIs

Other Resources

Kernel API Modifications: Windows CE 5.0 vs. Windows Embedded CE 6.0