#include "services.h"
#include <winnls.h>
+#include <strsafe.h>
#define NDEBUG
#include <debug.h>
SERVICE_EXECUTE,
SERVICE_ALL_ACCESS};
+DWORD g_dwServiceBits = 0;
/* FUNCTIONS ***************************************************************/
/* Function 0 */
-DWORD RCloseServiceHandle(
+DWORD
+WINAPI
+RCloseServiceHandle(
LPSC_RPC_HANDLE hSCObject)
{
PMANAGER_HANDLE hManager;
if (lpService->dwRefCount == 0)
{
/* If this service has been marked for deletion */
- if (lpService->bDeleted)
+ if (lpService->bDeleted &&
+ lpService->Status.dwCurrentState == SERVICE_STOPPED)
{
/* Open the Services Reg key */
dwError = RegOpenKeyExW(HKEY_LOCAL_MACHINE,
/* Function 1 */
-DWORD RControlService(
+DWORD
+WINAPI
+RControlService(
SC_RPC_HANDLE hService,
DWORD dwControl,
LPSERVICE_STATUS lpServiceStatus)
case SERVICE_CONTROL_PAUSE:
case SERVICE_CONTROL_CONTINUE:
+ case SERVICE_CONTROL_PARAMCHANGE:
+ case SERVICE_CONTROL_NETBINDADD:
+ case SERVICE_CONTROL_NETBINDREMOVE:
+ case SERVICE_CONTROL_NETBINDENABLE:
+ case SERVICE_CONTROL_NETBINDDISABLE:
DesiredAccess = SERVICE_PAUSE_CONTINUE;
break;
if ((dwControlsAccepted & SERVICE_ACCEPT_PAUSE_CONTINUE) == 0)
return ERROR_INVALID_SERVICE_CONTROL;
break;
+
+ case SERVICE_CONTROL_PARAMCHANGE:
+ if ((dwControlsAccepted & SERVICE_ACCEPT_PARAMCHANGE) == 0)
+ return ERROR_INVALID_SERVICE_CONTROL;
+ break;
+
+ case SERVICE_CONTROL_NETBINDADD:
+ case SERVICE_CONTROL_NETBINDREMOVE:
+ case SERVICE_CONTROL_NETBINDENABLE:
+ case SERVICE_CONTROL_NETBINDDISABLE:
+ if ((dwControlsAccepted & SERVICE_ACCEPT_NETBINDCHANGE) == 0)
+ return ERROR_INVALID_SERVICE_CONTROL;
+ break;
}
/* Send control code to the service */
- dwError = ScmControlService(lpService,
+ dwError = ScmControlService(lpService->lpImage->hControlPipe,
+ lpService->lpServiceName,
+ (SERVICE_STATUS_HANDLE)lpService,
dwControl);
/* Return service status information */
if (dwError == ERROR_SUCCESS)
{
- if (dwControl == SERVICE_CONTROL_STOP ||
- dwControl == SERVICE_CONTROL_PAUSE ||
- dwControl == SERVICE_CONTROL_CONTINUE)
- {
- /* Log a successful send control */
+ if (dwControl == SERVICE_CONTROL_STOP ||
+ dwControl == SERVICE_CONTROL_PAUSE ||
+ dwControl == SERVICE_CONTROL_CONTINUE)
+ {
+ /* Log a successful send control */
- switch (dwControl)
- {
- case SERVICE_CONTROL_STOP:
- uID = IDS_SERVICE_STOP;
- break;
+ switch (dwControl)
+ {
+ case SERVICE_CONTROL_STOP:
+ uID = IDS_SERVICE_STOP;
+ break;
- case SERVICE_CONTROL_PAUSE:
- uID = IDS_SERVICE_PAUSE;
- break;
+ case SERVICE_CONTROL_PAUSE:
+ uID = IDS_SERVICE_PAUSE;
+ break;
- case SERVICE_CONTROL_CONTINUE:
- uID = IDS_SERVICE_RESUME;
- break;
- }
- LoadStringW(GetModuleHandle(NULL), uID, szLogBuffer, 80);
+ case SERVICE_CONTROL_CONTINUE:
+ uID = IDS_SERVICE_RESUME;
+ break;
+ }
+ LoadStringW(GetModuleHandle(NULL), uID, szLogBuffer, ARRAYSIZE(szLogBuffer));
- lpLogStrings[0] = lpService->lpDisplayName;
- lpLogStrings[1] = szLogBuffer;
+ lpLogStrings[0] = lpService->lpDisplayName;
+ lpLogStrings[1] = szLogBuffer;
- ScmLogEvent(EVENT_SERVICE_CONTROL_SUCCESS,
- EVENTLOG_INFORMATION_TYPE,
- 2,
- lpLogStrings);
- }
+ ScmLogEvent(EVENT_SERVICE_CONTROL_SUCCESS,
+ EVENTLOG_INFORMATION_TYPE,
+ 2,
+ lpLogStrings);
+ }
}
return dwError;
/* Function 2 */
-DWORD RDeleteService(
+DWORD
+WINAPI
+RDeleteService(
SC_RPC_HANDLE hService)
{
PSERVICE_HANDLE hSvc;
/* Function 3 */
-DWORD RLockServiceDatabase(
+DWORD
+WINAPI
+RLockServiceDatabase(
SC_RPC_HANDLE hSCManager,
LPSC_RPC_LOCK lpLock)
{
/* Function 4 */
-DWORD RQueryServiceObjectSecurity(
+DWORD
+WINAPI
+RQueryServiceObjectSecurity(
SC_RPC_HANDLE hService,
SECURITY_INFORMATION dwSecurityInformation,
LPBYTE lpSecurityDescriptor,
/* Function 5 */
-DWORD RSetServiceObjectSecurity(
+DWORD
+WINAPI
+RSetServiceObjectSecurity(
SC_RPC_HANDLE hService,
DWORD dwSecurityInformation,
LPBYTE lpSecurityDescriptor,
/* Function 6 */
-DWORD RQueryServiceStatus(
+DWORD
+WINAPI
+RQueryServiceStatus(
SC_RPC_HANDLE hService,
LPSERVICE_STATUS lpServiceStatus)
{
/* Function 7 */
-DWORD RSetServiceStatus(
+DWORD
+WINAPI
+RSetServiceStatus(
RPC_SERVICE_STATUS_HANDLE hServiceStatus,
LPSERVICE_STATUS lpServiceStatus)
{
/* Restore the previous service type */
lpService->Status.dwServiceType = dwPreviousType;
+ /* Dereference a stopped service */
+ if ((lpServiceStatus->dwServiceType & SERVICE_WIN32) &&
+ (lpServiceStatus->dwCurrentState == SERVICE_STOPPED))
+ {
+ /* Decrement the image run counter */
+ lpService->lpImage->dwImageRunCount--;
+
+ /* If we just stopped the last running service... */
+ if (lpService->lpImage->dwImageRunCount == 0)
+ {
+ /* Stop the dispatcher thread */
+ ScmControlService(lpService->lpImage->hControlPipe,
+ L"",
+ (SERVICE_STATUS_HANDLE)lpService,
+ SERVICE_CONTROL_STOP);
+
+ /* Remove the service image */
+ ScmRemoveServiceImage(lpService->lpImage);
+ lpService->lpImage = NULL;
+ }
+ }
+
/* Unlock the service database */
ScmUnlockDatabase();
(lpServiceStatus->dwWin32ExitCode != ERROR_SUCCESS))
{
/* Log a failed service stop */
- swprintf(szLogBuffer, L"%lu", lpServiceStatus->dwWin32ExitCode);
+ StringCchPrintfW(szLogBuffer, ARRAYSIZE(szLogBuffer),
+ L"%lu", lpServiceStatus->dwWin32ExitCode);
lpLogStrings[0] = lpService->lpDisplayName;
lpLogStrings[1] = szLogBuffer;
break;
}
- LoadStringW(GetModuleHandle(NULL), uID, szLogBuffer, 80);
+ LoadStringW(GetModuleHandle(NULL), uID, szLogBuffer, ARRAYSIZE(szLogBuffer));
lpLogStrings[0] = lpService->lpDisplayName;
lpLogStrings[1] = szLogBuffer;
/* Function 8 */
-DWORD RUnlockServiceDatabase(
+DWORD
+WINAPI
+RUnlockServiceDatabase(
LPSC_RPC_LOCK Lock)
{
DPRINT("RUnlockServiceDatabase(%p)\n", Lock);
/* Function 9 */
-DWORD RNotifyBootConfigStatus(
+DWORD
+WINAPI
+RNotifyBootConfigStatus(
SVCCTL_HANDLEW lpMachineName,
DWORD BootAcceptable)
{
/* Function 10 */
-DWORD RI_ScSetServiceBitsW(
+DWORD
+WINAPI
+RI_ScSetServiceBitsW(
RPC_SERVICE_STATUS_HANDLE hServiceStatus,
DWORD dwServiceBits,
int bSetBitsOn,
int bUpdateImmediately,
wchar_t *lpString)
{
- UNIMPLEMENTED;
- return ERROR_CALL_NOT_IMPLEMENTED;
+ PSERVICE pService;
+
+ DPRINT("RI_ScSetServiceBitsW(%p %lx %d %d %S)\n",
+ hServiceStatus, dwServiceBits, bSetBitsOn,
+ bUpdateImmediately, lpString);
+
+ if (ScmShutdown)
+ return ERROR_SHUTDOWN_IN_PROGRESS;
+
+ if (lpString != NULL)
+ return ERROR_INVALID_PARAMETER;
+
+ if (hServiceStatus == 0)
+ {
+ DPRINT("hServiceStatus == NULL!\n");
+ return ERROR_INVALID_HANDLE;
+ }
+
+ // FIXME: Validate the status handle
+ pService = (PSERVICE)hServiceStatus;
+
+ if (bSetBitsOn)
+ {
+ DPRINT("Old service bits: %08lx\n", pService->dwServiceBits);
+ DPRINT("Old global service bits: %08lx\n", g_dwServiceBits);
+ pService->dwServiceBits |= dwServiceBits;
+ g_dwServiceBits |= dwServiceBits;
+ DPRINT("New service bits: %08lx\n", pService->dwServiceBits);
+ DPRINT("New global service bits: %08lx\n", g_dwServiceBits);
+ }
+ else
+ {
+ DPRINT("Old service bits: %08lx\n", pService->dwServiceBits);
+ DPRINT("Old global service bits: %08lx\n", g_dwServiceBits);
+ pService->dwServiceBits &= ~dwServiceBits;
+ g_dwServiceBits &= ~dwServiceBits;
+ DPRINT("New service bits: %08lx\n", pService->dwServiceBits);
+ DPRINT("New global service bits: %08lx\n", g_dwServiceBits);
+ }
+
+ return ERROR_SUCCESS;
}
/* Function 11 */
-DWORD RChangeServiceConfigW(
+DWORD
+WINAPI
+RChangeServiceConfigW(
SC_RPC_HANDLE hService,
DWORD dwServiceType,
DWORD dwStartType,
(dwErrorControl != SERVICE_ERROR_CRITICAL))
return ERROR_INVALID_PARAMETER;
+ if (lpdwTagId && (!lpLoadOrderGroup || !*lpLoadOrderGroup))
+ {
+ return ERROR_INVALID_PARAMETER;
+ }
+
lpService = hSvc->ServiceEntry;
if (lpService == NULL)
{
/* Function 12 */
-DWORD RCreateServiceW(
+DWORD
+WINAPI
+RCreateServiceW(
SC_RPC_HANDLE hSCManager,
LPCWSTR lpServiceName,
LPCWSTR lpDisplayName,
/* Allocate a new service entry */
dwError = ScmCreateNewServiceRecord(lpServiceName,
- &lpService);
+ &lpService,
+ dwServiceType,
+ dwStartType);
if (dwError != ERROR_SUCCESS)
goto done;
/* Fill the new service entry */
- lpService->Status.dwServiceType = dwServiceType;
- lpService->dwStartType = dwStartType;
lpService->dwErrorControl = dwErrorControl;
/* Fill the display name */
goto done;
}
-DPRINT1("\n");
/* Write the security descriptor */
dwError = ScmWriteSecurityDescriptor(hServiceKey,
lpService->pSecurityDescriptor);
/* Function 13 */
-DWORD REnumDependentServicesW(
+DWORD
+WINAPI
+REnumDependentServicesW(
SC_RPC_HANDLE hService,
DWORD dwServiceState,
LPBYTE lpServices,
/* Function 14 */
-DWORD REnumServicesStatusW(
+DWORD
+WINAPI
+REnumServicesStatusW(
SC_RPC_HANDLE hSCManager,
DWORD dwServiceType,
DWORD dwServiceState,
/* Function 15 */
-DWORD ROpenSCManagerW(
+DWORD
+WINAPI
+ROpenSCManagerW(
LPWSTR lpMachineName,
LPWSTR lpDatabaseName,
DWORD dwDesiredAccess,
/* Function 16 */
-DWORD ROpenServiceW(
+DWORD
+WINAPI
+ROpenServiceW(
SC_RPC_HANDLE hSCManager,
LPWSTR lpServiceName,
DWORD dwDesiredAccess,
/* Function 17 */
-DWORD RQueryServiceConfigW(
+DWORD
+WINAPI
+RQueryServiceConfigW(
SC_RPC_HANDLE hService,
LPBYTE lpBuf, //LPQUERY_SERVICE_CONFIGW lpServiceConfig,
DWORD cbBufSize,
/* Function 18 */
-DWORD RQueryServiceLockStatusW(
+DWORD
+WINAPI
+RQueryServiceLockStatusW(
SC_RPC_HANDLE hSCManager,
LPBYTE lpBuf, // LPQUERY_SERVICE_LOCK_STATUSW lpLockStatus,
DWORD cbBufSize,
/* Function 19 */
-DWORD RStartServiceW(
+DWORD
+WINAPI
+RStartServiceW(
SC_RPC_HANDLE hService,
DWORD argc,
LPSTRING_PTRSW argv)
/* Function 20 */
-DWORD RGetServiceDisplayNameW(
+DWORD
+WINAPI
+RGetServiceDisplayNameW(
SC_RPC_HANDLE hSCManager,
LPCWSTR lpServiceName,
LPWSTR lpDisplayName,
/* Function 21 */
-DWORD RGetServiceKeyNameW(
+DWORD
+WINAPI
+RGetServiceKeyNameW(
SC_RPC_HANDLE hSCManager,
LPCWSTR lpDisplayName,
LPWSTR lpServiceName,
/* Function 22 */
-DWORD RI_ScSetServiceBitsA(
+DWORD
+WINAPI
+RI_ScSetServiceBitsA(
RPC_SERVICE_STATUS_HANDLE hServiceStatus,
DWORD dwServiceBits,
int bSetBitsOn,
int bUpdateImmediately,
char *lpString)
{
- UNIMPLEMENTED;
- return ERROR_CALL_NOT_IMPLEMENTED;
+ if (ScmShutdown)
+ return ERROR_SHUTDOWN_IN_PROGRESS;
+
+ if (lpString != NULL)
+ return ERROR_INVALID_PARAMETER;
+
+ return RI_ScSetServiceBitsW(hServiceStatus,
+ dwServiceBits,
+ bSetBitsOn,
+ bUpdateImmediately,
+ NULL);
}
/* Function 23 */
-DWORD RChangeServiceConfigA(
+DWORD
+WINAPI
+RChangeServiceConfigA(
SC_RPC_HANDLE hService,
DWORD dwServiceType,
DWORD dwStartType,
/* Function 24 */
-DWORD RCreateServiceA(
+DWORD
+WINAPI
+RCreateServiceA(
SC_RPC_HANDLE hSCManager,
LPSTR lpServiceName,
LPSTR lpDisplayName,
/* Function 25 */
-DWORD REnumDependentServicesA(
+DWORD
+WINAPI
+REnumDependentServicesA(
SC_RPC_HANDLE hService,
DWORD dwServiceState,
LPBYTE lpServices,
/* Function 26 */
-DWORD REnumServicesStatusA(
+DWORD
+WINAPI
+REnumServicesStatusA(
SC_RPC_HANDLE hSCManager,
DWORD dwServiceType,
DWORD dwServiceState,
/* Function 27 */
-DWORD ROpenSCManagerA(
+DWORD
+WINAPI
+ROpenSCManagerA(
LPSTR lpMachineName,
LPSTR lpDatabaseName,
DWORD dwDesiredAccess,
/* Function 28 */
-DWORD ROpenServiceA(
+DWORD
+WINAPI
+ROpenServiceA(
SC_RPC_HANDLE hSCManager,
LPSTR lpServiceName,
DWORD dwDesiredAccess,
/* Function 29 */
-DWORD RQueryServiceConfigA(
+DWORD
+WINAPI
+RQueryServiceConfigA(
SC_RPC_HANDLE hService,
LPBYTE lpBuf, //LPQUERY_SERVICE_CONFIGA lpServiceConfig,
DWORD cbBufSize,
/* Function 30 */
-DWORD RQueryServiceLockStatusA(
+DWORD
+WINAPI
+RQueryServiceLockStatusA(
SC_RPC_HANDLE hSCManager,
LPBYTE lpBuf, // LPQUERY_SERVICE_LOCK_STATUSA lpLockStatus,
DWORD cbBufSize,
/* Function 31 */
-DWORD RStartServiceA(
+DWORD
+WINAPI
+RStartServiceA(
SC_RPC_HANDLE hService,
DWORD argc,
LPSTRING_PTRSA argv)
/* Function 32 */
-DWORD RGetServiceDisplayNameA(
+DWORD
+WINAPI
+RGetServiceDisplayNameA(
SC_RPC_HANDLE hSCManager,
LPCSTR lpServiceName,
LPSTR lpDisplayName,
/* Function 33 */
-DWORD RGetServiceKeyNameA(
+DWORD
+WINAPI
+RGetServiceKeyNameA(
SC_RPC_HANDLE hSCManager,
LPCSTR lpDisplayName,
LPSTR lpServiceName,
/* Function 34 */
-DWORD RI_ScGetCurrentGroupStateW(
+DWORD
+WINAPI
+RI_ScGetCurrentGroupStateW(
SC_RPC_HANDLE hSCManager,
LPWSTR lpLoadOrderGroup,
LPDWORD lpState)
/* Function 35 */
-DWORD REnumServiceGroupW(
+DWORD
+WINAPI
+REnumServiceGroupW(
SC_RPC_HANDLE hSCManager,
DWORD dwServiceType,
DWORD dwServiceState,
/* Function 36 */
-DWORD RChangeServiceConfig2A(
+DWORD
+WINAPI
+RChangeServiceConfig2A(
SC_RPC_HANDLE hService,
SC_RPC_CONFIG_INFOA Info)
{
- SC_RPC_CONFIG_INFOW InfoW;
+ SC_RPC_CONFIG_INFOW InfoW = { 0 };
DWORD dwRet, dwLength;
PVOID ptr = NULL;
DPRINT("RChangeServiceConfig2A() called\n");
DPRINT("dwInfoLevel = %lu\n", Info.dwInfoLevel);
+ if ((Info.dwInfoLevel < SERVICE_CONFIG_DESCRIPTION) ||
+ (Info.dwInfoLevel > SERVICE_CONFIG_FAILURE_ACTIONS))
+ return ERROR_INVALID_LEVEL;
+
InfoW.dwInfoLevel = Info.dwInfoLevel;
if (InfoW.dwInfoLevel == SERVICE_CONFIG_DESCRIPTION)
/* Function 37 */
-DWORD RChangeServiceConfig2W(
+DWORD
+WINAPI
+RChangeServiceConfig2W(
SC_RPC_HANDLE hService,
SC_RPC_CONFIG_INFOW Info)
{
if (ScmShutdown)
return ERROR_SHUTDOWN_IN_PROGRESS;
+ if ((Info.dwInfoLevel < SERVICE_CONFIG_DESCRIPTION) ||
+ (Info.dwInfoLevel > SERVICE_CONFIG_FAILURE_ACTIONS))
+ return ERROR_INVALID_LEVEL;
+
hSvc = ScmGetServiceFromHandle(hService);
if (hSvc == NULL)
{
/* Function 38 */
-DWORD RQueryServiceConfig2A(
+DWORD
+WINAPI
+RQueryServiceConfig2A(
SC_RPC_HANDLE hService,
DWORD dwInfoLevel,
LPBYTE lpBuffer,
if (ScmShutdown)
return ERROR_SHUTDOWN_IN_PROGRESS;
+ if ((dwInfoLevel < SERVICE_CONFIG_DESCRIPTION) ||
+ (dwInfoLevel > SERVICE_CONFIG_FAILURE_ACTIONS))
+ return ERROR_INVALID_LEVEL;
+
hSvc = ScmGetServiceFromHandle(hService);
if (hSvc == NULL)
{
/* Function 39 */
-DWORD RQueryServiceConfig2W(
+DWORD
+WINAPI
+RQueryServiceConfig2W(
SC_RPC_HANDLE hService,
DWORD dwInfoLevel,
LPBYTE lpBuffer,
if (ScmShutdown)
return ERROR_SHUTDOWN_IN_PROGRESS;
+ if ((dwInfoLevel < SERVICE_CONFIG_DESCRIPTION) ||
+ (dwInfoLevel > SERVICE_CONFIG_FAILURE_ACTIONS))
+ return ERROR_INVALID_LEVEL;
+
hSvc = ScmGetServiceFromHandle(hService);
if (hSvc == NULL)
{
/* Function 40 */
-DWORD RQueryServiceStatusEx(
+DWORD
+WINAPI
+RQueryServiceStatusEx(
SC_RPC_HANDLE hService,
SC_STATUS_TYPE InfoLevel,
LPBYTE lpBuffer,
/* Function 41 */
-DWORD REnumServicesStatusExA(
+DWORD
+WINAPI
+REnumServicesStatusExA(
SC_RPC_HANDLE hSCManager,
SC_ENUM_TYPE InfoLevel,
DWORD dwServiceType,
/* Function 42 */
-DWORD REnumServicesStatusExW(
+DWORD
+WINAPI
+REnumServicesStatusExW(
SC_RPC_HANDLE hSCManager,
SC_ENUM_TYPE InfoLevel,
DWORD dwServiceType,
/* Function 43 */
-DWORD RSendTSMessage(
+DWORD
+WINAPI
+RSendTSMessage(
handle_t BindingHandle) /* FIXME */
{
UNIMPLEMENTED;
/* Function 44 */
-DWORD RCreateServiceWOW64A(
+DWORD
+WINAPI
+RCreateServiceWOW64A(
handle_t BindingHandle,
LPSTR lpServiceName,
LPSTR lpDisplayName,
/* Function 45 */
-DWORD RCreateServiceWOW64W(
+DWORD
+WINAPI
+RCreateServiceWOW64W(
handle_t BindingHandle,
LPWSTR lpServiceName,
LPWSTR lpDisplayName,
/* Function 46 */
-DWORD RQueryServiceTagInfo(
+DWORD
+WINAPI
+RQueryServiceTagInfo(
handle_t BindingHandle) /* FIXME */
{
UNIMPLEMENTED;
/* Function 47 */
-DWORD RNotifyServiceStatusChange(
+DWORD
+WINAPI
+RNotifyServiceStatusChange(
SC_RPC_HANDLE hService,
SC_RPC_NOTIFY_PARAMS NotifyParams,
GUID *pClientProcessGuid,
/* Function 48 */
-DWORD RGetNotifyResults(
+DWORD
+WINAPI
+RGetNotifyResults(
SC_NOTIFY_RPC_HANDLE hNotify,
PSC_RPC_NOTIFY_PARAMS_LIST *ppNotifyParams)
{
/* Function 49 */
-DWORD RCloseNotifyHandle(
+DWORD
+WINAPI
+RCloseNotifyHandle(
LPSC_NOTIFY_RPC_HANDLE phNotify,
PBOOL pfApcFired)
{
/* Function 50 */
-DWORD RControlServiceExA(
+DWORD
+WINAPI
+RControlServiceExA(
SC_RPC_HANDLE hService,
DWORD dwControl,
DWORD dwInfoLevel)
/* Function 51 */
-DWORD RControlServiceExW(
+DWORD
+WINAPI
+RControlServiceExW(
SC_RPC_HANDLE hService,
DWORD dwControl,
DWORD dwInfoLevel)
/* Function 52 */
-DWORD RSendPnPMessage(
+DWORD
+WINAPI
+RSendPnPMessage(
handle_t BindingHandle) /* FIXME */
{
UNIMPLEMENTED;
/* Function 53 */
-DWORD RValidatePnPService(
+DWORD
+WINAPI
+RValidatePnPService(
handle_t BindingHandle) /* FIXME */
{
UNIMPLEMENTED;
/* Function 54 */
-DWORD ROpenServiceStatusHandle(
+DWORD
+WINAPI
+ROpenServiceStatusHandle(
handle_t BindingHandle) /* FIXME */
{
UNIMPLEMENTED;
/* Function 55 */
-DWORD RFunction55(
+DWORD
+WINAPI
+RFunction55(
handle_t BindingHandle) /* FIXME */
{
UNIMPLEMENTED;