+static DWORD
+ScmCreateNewControlPipe(PSERVICE_IMAGE pServiceImage)
+{
+ WCHAR szControlPipeName[MAX_PATH + 1];
+ HKEY hServiceCurrentKey = INVALID_HANDLE_VALUE;
+ DWORD ServiceCurrent = 0;
+ DWORD KeyDisposition;
+ DWORD dwKeySize;
+ DWORD dwError;
+
+ /* Get the service number */
+ /* TODO: Create registry entry with correct write access */
+ dwError = RegCreateKeyExW(HKEY_LOCAL_MACHINE,
+ L"SYSTEM\\CurrentControlSet\\Control\\ServiceCurrent", 0, NULL,
+ REG_OPTION_VOLATILE,
+ KEY_WRITE | KEY_READ,
+ NULL,
+ &hServiceCurrentKey,
+ &KeyDisposition);
+ if (dwError != ERROR_SUCCESS)
+ {
+ DPRINT1("RegCreateKeyEx() failed with error %lu\n", dwError);
+ return dwError;
+ }
+
+ if (KeyDisposition == REG_OPENED_EXISTING_KEY)
+ {
+ dwKeySize = sizeof(DWORD);
+ dwError = RegQueryValueExW(hServiceCurrentKey,
+ L"", 0, NULL, (BYTE*)&ServiceCurrent, &dwKeySize);
+
+ if (dwError != ERROR_SUCCESS)
+ {
+ RegCloseKey(hServiceCurrentKey);
+ DPRINT1("RegQueryValueEx() failed with error %lu\n", dwError);
+ return dwError;
+ }
+
+ ServiceCurrent++;
+ }
+
+ dwError = RegSetValueExW(hServiceCurrentKey, L"", 0, REG_DWORD, (BYTE*)&ServiceCurrent, sizeof(ServiceCurrent));
+
+ RegCloseKey(hServiceCurrentKey);
+
+ if (dwError != ERROR_SUCCESS)
+ {
+ DPRINT1("RegSetValueExW() failed (Error %lu)\n", dwError);
+ return dwError;
+ }
+
+ /* Create '\\.\pipe\net\NtControlPipeXXX' instance */
+ swprintf(szControlPipeName, L"\\\\.\\pipe\\net\\NtControlPipe%u", ServiceCurrent);
+
+ DPRINT("PipeName: %S\n", szControlPipeName);
+
+ pServiceImage->hControlPipe = CreateNamedPipeW(szControlPipeName,
+ PIPE_ACCESS_DUPLEX,
+ PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE | PIPE_WAIT,
+ 100,
+ 8000,
+ 4,
+ 30000,
+ NULL);
+ DPRINT("CreateNamedPipeW(%S) done\n", szControlPipeName);
+ if (pServiceImage->hControlPipe == INVALID_HANDLE_VALUE)
+ {
+ DPRINT1("Failed to create control pipe!\n");
+ return GetLastError();
+ }
+
+ return ERROR_SUCCESS;
+}
+
+
+static PSERVICE_IMAGE
+ScmGetServiceImageByImagePath(LPWSTR lpImagePath)
+{
+ PLIST_ENTRY ImageEntry;
+ PSERVICE_IMAGE CurrentImage;
+
+ DPRINT("ScmGetServiceImageByImagePath() called\n");
+
+ ImageEntry = ImageListHead.Flink;
+ while (ImageEntry != &ImageListHead)
+ {
+ CurrentImage = CONTAINING_RECORD(ImageEntry,
+ SERVICE_IMAGE,
+ ImageListEntry);
+ if (_wcsicmp(CurrentImage->szImagePath, lpImagePath) == 0)
+ {
+ DPRINT("Found image: '%S'\n", CurrentImage->szImagePath);
+ return CurrentImage;
+ }
+
+ ImageEntry = ImageEntry->Flink;
+ }
+
+ DPRINT1("Couldn't find a matching image\n");
+
+ return NULL;
+
+}
+
+
+static DWORD
+ScmCreateOrReferenceServiceImage(PSERVICE pService)
+{
+ RTL_QUERY_REGISTRY_TABLE QueryTable[2];
+ UNICODE_STRING ImagePath;
+ PSERVICE_IMAGE pServiceImage = NULL;
+ NTSTATUS Status;
+ DWORD dwError = ERROR_SUCCESS;
+
+ DPRINT("ScmCreateOrReferenceServiceImage()");
+
+ RtlInitUnicodeString(&ImagePath, NULL);
+
+ /* Get service data */
+ RtlZeroMemory(&QueryTable,
+ sizeof(QueryTable));
+
+ QueryTable[0].Name = L"ImagePath";
+ QueryTable[0].Flags = RTL_QUERY_REGISTRY_DIRECT | RTL_QUERY_REGISTRY_REQUIRED;
+ QueryTable[0].EntryContext = &ImagePath;
+
+ Status = RtlQueryRegistryValues(RTL_REGISTRY_SERVICES,
+ pService->lpServiceName,
+ QueryTable,
+ NULL,
+ NULL);
+ if (!NT_SUCCESS(Status))
+ {
+ DPRINT1("RtlQueryRegistryValues() failed (Status %lx)\n", Status);
+ return RtlNtStatusToDosError(Status);
+ }
+
+ DPRINT("ImagePath: '%wZ'\n", &ImagePath);
+
+ pServiceImage = ScmGetServiceImageByImagePath(ImagePath.Buffer);
+ if (pServiceImage == NULL)
+ {
+ /* Create a new service image */
+ pServiceImage = (PSERVICE_IMAGE)HeapAlloc(GetProcessHeap(),
+ HEAP_ZERO_MEMORY,
+ sizeof(SERVICE_IMAGE) + ((wcslen(ImagePath.Buffer) + 1) * sizeof(WCHAR)));
+ if (pServiceImage == NULL)
+ {
+ dwError = ERROR_NOT_ENOUGH_MEMORY;
+ goto done;
+ }
+
+ pServiceImage->dwImageRunCount = 1;
+ pServiceImage->hControlPipe = INVALID_HANDLE_VALUE;
+ pServiceImage->hProcess = INVALID_HANDLE_VALUE;
+
+ /* Set the image path */
+ wcscpy(pServiceImage->szImagePath,
+ ImagePath.Buffer);
+
+ RtlFreeUnicodeString(&ImagePath);
+
+ /* Create the control pipe */
+ dwError = ScmCreateNewControlPipe(pServiceImage);
+ if (dwError != ERROR_SUCCESS)
+ {
+ HeapFree(GetProcessHeap(), 0, pServiceImage);
+ goto done;
+ }
+
+ /* FIXME: Add more initialization code here */
+
+
+ /* Append service record */
+ InsertTailList(&ImageListHead,
+ &pServiceImage->ImageListEntry);
+
+ pService->lpImage = pServiceImage;
+ }
+ else
+ {
+ /* Create a new service image */
+ pService->lpImage->dwImageRunCount++;
+ }
+
+done:;
+ RtlFreeUnicodeString(&ImagePath);
+
+ return dwError;
+}
+
+
+static VOID
+ScmDereferenceServiceImage(PSERVICE_IMAGE pServiceImage)
+{
+ DPRINT1("ScmDereferenceServiceImage() called\n");
+
+ pServiceImage->dwImageRunCount--;
+
+ if (pServiceImage->dwImageRunCount == 0)
+ {
+ DPRINT1("dwImageRunCount == 0\n");
+
+ /* FIXME: Terminate the process */
+
+ /* Remove the service image from the list */
+ RemoveEntryList(&pServiceImage->ImageListEntry);
+
+ /* Close the control pipe */
+ if (pServiceImage->hControlPipe != INVALID_HANDLE_VALUE)
+ CloseHandle(pServiceImage->hControlPipe);
+
+ /* Close the process handle */
+ if (pServiceImage->hProcess != INVALID_HANDLE_VALUE)
+ CloseHandle(pServiceImage->hProcess);
+
+ /* Release the service image */
+ HeapFree(GetProcessHeap(), 0, pServiceImage);
+ }
+}
+