+BOOL WINAPI
+SetDefaultPrinterA(LPCSTR pszPrinter)
+{
+ BOOL bReturnValue = FALSE;
+ DWORD cch;
+ PWSTR pwszPrinter = NULL;
+
+ if (pszPrinter)
+ {
+ // Convert pszPrinter to a Unicode string pwszPrinter
+ cch = strlen(pszPrinter);
+
+ pwszPrinter = HeapAlloc(hProcessHeap, 0, (cch + 1) * sizeof(WCHAR));
+ if (!pwszPrinter)
+ {
+ ERR("HeapAlloc failed for pwszPrinter with last error %lu!\n", GetLastError());
+ goto Cleanup;
+ }
+
+ MultiByteToWideChar(CP_ACP, 0, pszPrinter, -1, pwszPrinter, cch + 1);
+ }
+
+ bReturnValue = SetDefaultPrinterW(pwszPrinter);
+
+Cleanup:
+ if (pwszPrinter)
+ HeapFree(hProcessHeap, 0, pwszPrinter);
+
+ return bReturnValue;
+}
+
+BOOL WINAPI
+SetDefaultPrinterW(LPCWSTR pszPrinter)
+{
+ const WCHAR wszDevicesKey[] = L"Software\\Microsoft\\Windows NT\\CurrentVersion\\Devices";
+
+ DWORD cbDeviceValueData;
+ DWORD cbPrinterValueData = 0;
+ DWORD cchPrinter;
+ DWORD dwErrorCode;
+ HKEY hDevicesKey = NULL;
+ HKEY hWindowsKey = NULL;
+ PWSTR pwszDeviceValueData = NULL;
+ WCHAR wszPrinter[MAX_PRINTER_NAME + 1];
+
+ // Open the Devices registry key.
+ dwErrorCode = (DWORD)RegOpenKeyExW(HKEY_CURRENT_USER, wszDevicesKey, 0, KEY_READ, &hDevicesKey);
+ if (dwErrorCode != ERROR_SUCCESS)
+ {
+ ERR("RegOpenKeyExW failed with status %lu!\n", dwErrorCode);
+ goto Cleanup;
+ }
+
+ // Did the caller give us a printer to set as default?
+ if (pszPrinter && *pszPrinter)
+ {
+ // Check if the given printer exists and query the value data size.
+ dwErrorCode = (DWORD)RegQueryValueExW(hDevicesKey, pszPrinter, NULL, NULL, NULL, &cbPrinterValueData);
+ if (dwErrorCode == ERROR_FILE_NOT_FOUND)
+ {
+ // The caller gave us an invalid printer name, return with ERROR_FILE_NOT_FOUND.
+ goto Cleanup;
+ }
+ else if (dwErrorCode != ERROR_SUCCESS)
+ {
+ ERR("RegQueryValueExW failed with status %lu!\n", dwErrorCode);
+ goto Cleanup;
+ }
+
+ cchPrinter = wcslen(pszPrinter);
+ }
+ else
+ {
+ // If there is already a default printer, we're done!
+ cchPrinter = _countof(wszPrinter);
+ if (GetDefaultPrinterW(wszPrinter, &cchPrinter))
+ {
+ dwErrorCode = ERROR_SUCCESS;
+ goto Cleanup;
+ }
+
+ // Otherwise, get us the first printer from the "Devices" key to later set it as default and query the value data size.
+ cchPrinter = _countof(wszPrinter);
+ dwErrorCode = (DWORD)RegEnumValueW(hDevicesKey, 0, wszPrinter, &cchPrinter, NULL, NULL, NULL, &cbPrinterValueData);
+ if (dwErrorCode != ERROR_MORE_DATA)
+ goto Cleanup;
+
+ pszPrinter = wszPrinter;
+ }
+
+ // We now need to query the value data, which has the format "winspool,<Port>:"
+ // and make "<Printer Name>,winspool,<Port>:" out of it.
+ // Allocate a buffer large enough for the final data.
+ cbDeviceValueData = (cchPrinter + 1) * sizeof(WCHAR) + cbPrinterValueData;
+ pwszDeviceValueData = HeapAlloc(hProcessHeap, 0, cbDeviceValueData);
+ if (!pwszDeviceValueData)
+ {
+ dwErrorCode = GetLastError();
+ ERR("HeapAlloc failed with error %lu\n", dwErrorCode);
+ goto Cleanup;
+ }
+
+ // Copy the Printer Name and a comma into it.
+ CopyMemory(pwszDeviceValueData, pszPrinter, cchPrinter * sizeof(WCHAR));
+ pwszDeviceValueData[cchPrinter] = L',';
+
+ // Append the value data, which has the format "winspool,<Port>:"
+ dwErrorCode = (DWORD)RegQueryValueExW(hDevicesKey, pszPrinter, NULL, NULL, (PBYTE)&pwszDeviceValueData[cchPrinter + 1], &cbPrinterValueData);
+ if (dwErrorCode != ERROR_SUCCESS)
+ goto Cleanup;
+
+ // Open the Windows registry key.
+ dwErrorCode = (DWORD)RegOpenKeyExW(HKEY_CURRENT_USER, wszWindowsKey, 0, KEY_SET_VALUE, &hWindowsKey);
+ if (dwErrorCode != ERROR_SUCCESS)
+ {
+ ERR("RegOpenKeyExW failed with status %lu!\n", dwErrorCode);
+ goto Cleanup;
+ }
+
+ // Store our new default printer.
+ dwErrorCode = (DWORD)RegSetValueExW(hWindowsKey, wszDeviceValue, 0, REG_SZ, (PBYTE)pwszDeviceValueData, cbDeviceValueData);
+ if (dwErrorCode != ERROR_SUCCESS)
+ {
+ ERR("RegSetValueExW failed with status %lu!\n", dwErrorCode);
+ goto Cleanup;
+ }
+
+Cleanup:
+ if (hDevicesKey)
+ RegCloseKey(hDevicesKey);
+
+ if (hWindowsKey)
+ RegCloseKey(hWindowsKey);
+
+ if (pwszDeviceValueData)
+ HeapFree(hProcessHeap, 0, pwszDeviceValueData);
+
+ SetLastError(dwErrorCode);
+ return (dwErrorCode == ERROR_SUCCESS);
+}
+