How to launch an Universal App as another user with WinAPI? - c

How can I launch an Universal App as another user using CreateProcessWithLogonW()? I cannot get it to launch using C:\\Windows\\System32\\cmd.exe /c start skype: even though start skype: does launch in the terminal.
#include <stdio.h>
#include <windows.h>
#include <lmcons.h>
int main(void)
{
PROCESS_INFORMATION pi = { 0 };
STARTUPINFOW si = { 0 };
si.cb = sizeof(STARTUPINFOW);
/*
not working:
L"C:\\Windows\\System32\\cmd.exe /c start skype" error: "The filename, directory name, or volume label syntax is incorrect."
L"C:\\Windows\\System32\\cmd.exe /c start skype:" no error but a pop-up with text: "You'll need a new app to open this"
*/
wchar_t lpCommandLine[] = L"C:\\Windows\\System32\\cmd.exe /c start skype:"; // lpCommandLine must be writable memory
if (!CreateProcessWithLogonW(L"username", L".", L"password", LOGON_WITH_PROFILE, NULL, lpCommandLine, 0, NULL, NULL, &si, &pi))
{
printf("GetLastError(): %i\n", GetLastError());
char buf[UNLEN + 1] = { 0 };
FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, GetLastError(), MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR)&buf, sizeof(buf), NULL);
puts(buf);
return 1;
}
else
{
// do stuff only while skype is running
puts("skype is running.");
if (WaitForSingleObject(pi.hProcess, INFINITE) == WAIT_FAILED)
puts("WaitForSingleObject() failed");
// do stuff only after skype exits
puts("skype is NOT running.");
}
return 0;
}

This is impossible. No matter what user the UWP app is run under, it will always run under a sandboxed AppContainer user that is different for every user session. You can't run a UWP app as another user using the Win32 api.

This is possible depending on what you mean by different user. For example, in our product we have a windows service which runs under 'Local System' account and from this we are able to launch a UWP app in the currently logged on user account. For this, we have used CreateProcessAsUser to launch a process in the logged on user account with command to open the protocol supported by the UWP app. Sample code :
string uwpAppLaunchCmdLine = string.Format("/c start {0}", PROTOCOL_SUPPORTED_BY_UWP_APP);
int processId;
IntPtr hErrorReadOut = IntPtr.Zero;
ProcessMetadata processMetadata;
if (!StartAsCurrentUser("cmd.exe", false, out processId,out processMetadata, coreAppLaunchCmdLine))
{
//Failed to launch
}
else
{
//success!
}

Related

Is there an option to prohibit user from accessing basic file?

I'm currently working on developing some driver. For now connection between kernel and system is done via simple text file created like this:
handle=CreateFile(TEXT("\\\\.\\" FILE_NAME),
GENERIC_READ | GENERIC_WRITE,
0,
NULL,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL,
NULL);
File is used for transfering data from kernel to system, kernel driver writes file and system app reads from it. My concern is safety of such solution, as for now anyone can simply go into this file, get all data in file, and what's even worse, modify it. Is it possible to make file not accesible for user, but still being accesible for system app?
UPDATE:
After doing some research I found a pattern how to do it for specific users:
ea[1].grfAccessPermissions = ACCESS_SYSTEM_SECURITY | READ_CONTROL | WRITE_DAC | GENERIC_ALL;
ea[1].grfAccessMode = DENY_ACCESS;
ea[1].grfInheritance = NO_INHERITANCE;
ea[1].Trustee.TrusteeForm = TRUSTEE_IS_SID;
ea[1].Trustee.ptstrName = reinterpret_cast<char*>(&everyone_sid);
dwRes = SetEntriesInAclA(2, ea, NULL, &pNewDACL);
if (ERROR_SUCCESS != dwRes) {
printf("SetEntriesInAcl Error %u\n", dwRes);
//TODO: goto Cleanup;
}
PSECURITY_DESCRIPTOR pSD = NULL;
// Initialize a security descriptor.
pSD = (PSECURITY_DESCRIPTOR)LocalAlloc(LPTR,
SECURITY_DESCRIPTOR_MIN_LENGTH);
if (NULL == pSD)
{
printf("error");
}
if (!InitializeSecurityDescriptor(pSD,
SECURITY_DESCRIPTOR_REVISION))
{
printf("error");
}
// Add the ACL to the security descriptor.
if (!SetSecurityDescriptorDacl(pSD,
TRUE, // bDaclPresent flag
pNewDACL,
FALSE)) // not a default DACL
{
printf("error");
}
SECURITY_ATTRIBUTES sa;
// Initialize a security attributes structure.
sa.nLength = sizeof(SECURITY_ATTRIBUTES);
sa.lpSecurityDescriptor = pSD;
sa.bInheritHandle = FALSE;
HANDLE hFile = CreateFileA(filename, GENERIC_ALL, 0, &sa, CREATE_NEW, FILE_ATTRIBUTE_NORMAL, NULL);
By this code I managed to make file not accesible for any user so It's great progress. However, I have no idea how to make it accesible for another project, for example:
int main()
{
std::cout << "Hello World!\n";
std::fstream testfile;
//basically in another project
testfile.open("created_file.txt", ios::out);
testfile.write("elo",3);
testfile.close();
}
I belive that maybe there is a way to get proccess SID and then give full access for it's SID, but question is how could I get process SID?

C create and run windows service

I am trying to create a service that will be run at system startup and start it immediately. Service is supposed to run my exe file.
GetLastError function return 1053 error code.
int main(void)
{
SC_HANDLE SC_manager_handle;
SC_HANDLE service_handle;
LPCTSTR binary_path = "C:\\Users\\User\\AppData\\file.exe";
LPCTSTR display_name = "ExampleService";
LPCTSTR service_name = "EXAMPLE_SERVICE";
SC_manager_handle = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);
puts("-----------------------");
if(SC_manager_handle == NULL)
puts("Open SM Manager: FAILED");
else
puts("SC Manager: SUCCESS");
service_handle = CreateService(SC_manager_handle, service_name, display_name, SERVICE_ALL_ACCESS ,SERVICE_WIN32_OWN_PROCESS, SERVICE_AUTO_START, SERVICE_ERROR_NORMAL, binary_path, NULL, NULL, NULL, NULL, NULL);
if(service_handle == NULL)
puts("Create Service: FAILED");
else
puts("Service Create: SUCCESS");
// running the exe file immediately
if(!StartService(service_handle, 0, NULL))
printf("Start Service: FAILED | ERROR: %d\n", GetLastError());
else
puts("Service Start: SUCCESS");
CloseServiceHandle(SC_manager_handle);
CloseServiceHandle(service_handle);
return 0;
}
I think you miss some important requirements for a windows service.According to the MSDN.
You need a service main function and a control handler function as you can't handle the "start" command if there's no control handler function registered.
So you can refer to the code to know how to wrote a ServiceMain Function and install it.
If you want to open the service, according to Starting a Service:
To start a service, a service control program opens a handle to an
installed database and then specifies the handle in a call to the
StartService function. After starting the service, the program uses
the members of the SERVICE_STATUS_PROCESS structure returned by the
QueryServiceStatusEx function to track the progress of the service.
I recommend you refer to the complete sample of using the service, which will greatly help you use the service.

Program escalates itself from admin to system

I wrote a program that needs to be running as SYSTEM. I add the linker option 'UAC Execution Level' to 'requireAdministrator' and it pops the UAC like it should but now I need to escalate from admin to SYSTEM how can I do that?
I thought about opening the program's token and inject it the SYSTEM token but it is not legit way. How can I do it neatly because I know once you admin you can be SYSTEM.
Write a windows service. It will run as SYSTEM user by default.
A simple tutorial is here, but remember that installing a service requires administrator privileges.
Once you're running as administrator, here are some options:
If you know you're not going to be using GUI functions, you can create a scheduled task that runs your same exe as NT AUTHORITY\SYSTEM within a few seconds, and check within your code which account the process is running as.
Copied from a project of mine and slightly modified:
#include <Windows.h>
#include <WinNls.h>
#include <shobjidl.h>
#include <objbase.h>
#include <ObjIdl.h>
#include <ShlGuid.h>
#include <taskschd.h>
#include <comdef.h>
#include <strsafe.h>
#pragma comment(lib, "taskschd.lib")
#pragma comment(lib, "comsupp.lib")
HRESULT WINAPI CreateSchedTask(WCHAR *wszExePath)
{
ITaskService *pService = NULL;
ITaskFolder *pRoot = NULL;
ITaskDefinition *pTask = NULL;
ITaskSettings *pSettings = NULL;
IRegistrationInfo *pInfo = NULL;
ITriggerCollection *pCollection = NULL;
ITrigger *pTrigger = NULL;
ITimeTrigger *pTime = NULL;
IPrincipal *pPrincipal = NULL;
IActionCollection *pActionCollection = NULL;
IAction *pAction = NULL;
IExecAction *pExecAction = NULL;
IRegisteredTask *pRegTask = NULL;
SYSTEMTIME stNow;
FILETIME ftStart, ftEnd;
ULARGE_INTEGER ulWork;
WCHAR wFmt[100];
VARIANT vBlank = _variant_t();
if (FAILED(CoInitializeEx(NULL, COINIT_APARTMENTTHREADED)))
{
return E_FAIL;
}
//CoInitializeSecurity(NULL, -1, NULL, NULL, RPC_C_AUTHN_LEVEL_PKT_PRIVACY, RPC_C_IMP_LEVEL_IMPERSONATE, NULL, 0, NULL);
if (FAILED(CoCreateInstance(CLSID_TaskScheduler, NULL, CLSCTX_INPROC_SERVER, IID_ITaskService, (LPVOID *) &pService)))
{
return E_FAIL;
}
pService->Connect(vBlank, vBlank, vBlank, vBlank);
pService->GetFolder(SysAllocString(L"\\"), &pRoot);
pService->NewTask(0, &pTask);
pService->Release();
pTask->get_RegistrationInfo(&pInfo);
pInfo->put_Author(SysAllocString(L"TASKNAMEHERE"));
pInfo->Release();
pTask->get_Settings(&pSettings);
pSettings->put_StartWhenAvailable(VARIANT_TRUE);
pSettings->put_Enabled(VARIANT_TRUE);
pSettings->Release();
pTask->get_Triggers(&pCollection);
pCollection->Create(TASK_TRIGGER_TIME, &pTrigger);
pCollection->Release();
pTrigger->QueryInterface(IID_ITimeTrigger, (LPVOID *)&pTime);
GetLocalTime(&stNow);
SystemTimeToFileTime(&stNow, &ftStart);
ulWork.HighPart = ftStart.dwHighDateTime;
ulWork.LowPart = ftStart.dwLowDateTime;
//20000000000
ulWork.QuadPart += 300000000UI64;
ftStart.dwHighDateTime = ulWork.HighPart;
ftStart.dwLowDateTime = ulWork.LowPart;
FileTimeToSystemTime(&ftStart, &stNow);
// Note: replace -07:00 with the appropriate UTC offset for your time zone
StringCchPrintfW(wFmt, 100, L"%.4hu-%.2hu-%.2huT%.2hu:%.2hu:%.2hu-07:00", stNow.wYear, stNow.wMonth, stNow.wDay, stNow.wHour, stNow.wMinute, stNow.wSecond);
pTime->put_StartBoundary(SysAllocString(wFmt));
ulWork.QuadPart += 900000000UI64;
ftEnd.dwLowDateTime = ulWork.LowPart;
ftEnd.dwHighDateTime = ulWork.HighPart;
FileTimeToSystemTime(&ftEnd, &stNow);
StringCchPrintfW(wFmt, 100, L"%.4hu-%.2hu-%.2huT%.2hu:%.2hu:%.2hu-07:00", stNow.wYear, stNow.wMonth, stNow.wDay, stNow.wHour, stNow.wMinute, stNow.wSecond);
pTime->put_EndBoundary(SysAllocString(wFmt));
pTime->put_Id(SysAllocString(L"TimeTrigger"));
pTime->Release();
pTask->get_Actions(&pActionCollection);
pActionCollection->Create(TASK_ACTION_EXEC, &pAction);
pActionCollection->Release();
pAction->QueryInterface(IID_IExecAction, (LPVOID *)&pExecAction);
pAction->Release();
pExecAction->put_Path(SysAllocString(wszExePath));
pExecAction->Release();
pTask->get_Principal(&pPrincipal);
pPrincipal->put_RunLevel(TASK_RUNLEVEL_HIGHEST);
pPrincipal->put_LogonType(TASK_LOGON_SERVICE_ACCOUNT);
pTask->put_Principal(pPrincipal);
pPrincipal->Release();
pRoot->RegisterTaskDefinition(
SysAllocString(L"System Elevation"),
pTask, TASK_CREATE_OR_UPDATE,
_variant_t(L"NT AUTHORITY\\SYSTEM"),
_variant_t(), TASK_LOGON_SERVICE_ACCOUNT,
_variant_t(L""), &pRegTask);
pRoot->Release();
pTask->Release();
pRegTask->Release();
CoUninitialize();
return S_OK;
}
INT APIENTRY wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPWSTR lpCmdLine, INT nShowCmd)
{
WCHAR wUsername[100], wExePath[MAX_PATH];
GetEnvironmentVariableW(L"USERNAME", wUsername, 100);
if (!wcschr(wUsername, L'$'))
{
GetModuleFileNameW(hInstance, wExePath, MAX_PATH);
CreateSchedTask(wExePath);
}
else
{
// NOTE: MessageBox and other GUI functions won't work since the process isn't running in winsta0\default
// File I/O instead
HANDLE hLog = CreateFileW(L"C:\\Temp\\Log.txt", GENERIC_WRITE | GENERIC_READ, 0, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
DWORD dwWritten;
UINT uLen;
CHAR szBuf[100];
SetFilePointer(hLog, 0, NULL, FILE_END);
StringCchPrintfA(szBuf, 100, "Hello from %S\r\n", wUsername);
StringCbLengthA(szBuf, 100, &uLen);
WriteFile(hLog, szBuf, uLen, &dwWritten, NULL);
CloseHandle(hLog);
}
return 0;
}
Use the Windows Process API to elevate to System. I don't have much in the way of example code for this, but you can look at PAExec, an open source alternative to SysInternals PSExec tool, that allows creating new interactive processes as System.
The idiomatic way of doing this on Windows, which is create a Windows service.

How to retrieve system proxy settings in Win 7 for windows service in C

I am writing an application that will run as a service and will pick system proxy settings for communication with the outside world .I tried WinHttpGetIEProxyConfigForCurrentUser but it fails to retrieve proxy settings for current user which is obvious since service is running under the domain of Local System. To realize the same I have to made the user to logon to the service which I don't want application user to do. I read about SERVICE_USER_OWN_PROCESS parameter which can be passed to CreateService() but neither I found its declaration in WinNT.h nor I am sure if it will work. Development of application is stuck because of this issue. Can anybody please help.
I had similar situation with running a program in the context of the current user.
First of all - somewhere in a global scope - define following variables:
HANDLE hUsrToken;
HANDLE hDupToken;
int sessionId;
You need to get the session Id of the current user:
int getInteractiveSessinoId()
{
PWTS_SESSION_INFO pSessInfo;
ulong count; // Number of current user sessions
int result = -1;
if (!WTSEnumerateSessions(WTS_CURRENT_SERVER, 0, 1, &pSessInfo, &count))
{
printf("Getting session information failed with error %d\n", << GetLastError());
WTSFreeMemory(pSessInfo);
return -2;
}
for (ulong loop = 0; loop < count; loop++)
{
if (pSessInfo[loop].State == WTSActive)
{
printf("Session %d is currently active\n", pSessInfo[loop].SessionId);
result = pSessInfo[loop].SessionId;
break;
}
}
WTSFreeMemory(pSessInfo);
return result;
}
Next you need to impersonate the current user (I called it "attach to the session"):
bool attachToSession(int sessionId)
{
// We need to duplicate the token of the session's user
if (!WTSQueryUserToken(sessionId, &hUsrToken))
{
pritnf("Query the user token failed with error %d\n", GetLastError());
return false;
}
if (!DuplicateTokenEx(hUsrToken, TOKEN_ALL_ACCESS, NULL, SecurityImpersonation, TokenImpersonation , &hDupToken))
{
printf("Duplicating a token failed with error %d\n", GetLastError());
return false;
}
if (!ImpersonateLoggedOnUser(hDupToken))
{
printf("Impersonating the user failed with error %d\n", GetLastError();
return false;
}
return true;
}
Now do whatever you want to do want to do within the current user's context, when done, revert (or "detach") from the user's context:
bool detachFromSession()
{
if (!RevertToSelf())
{
printf("Reverting the token failed with error %d\n", GetLastError());
return false;
}
(void)CloseHandle(hDupToken);
(void)CloseHandle(hUsrToken);
return true;
}
I'm not sure if it is good idea to apply the token to the current (service) thread. I think it is a better idea to create a new thread which executes whatever you want to do in the user's context and apply the impersonated token to it. So your code part may look like this:
HANDLE hUsrToken;
HANDLE hDupToken;
HANDLE hThread;
int sessionId;
DWORD threadId;
DWORD WINAPI MyThreadFunction(LPVOID lpParam)
{
// WinHttpGetIEProxyConfigForCurrentUser(...
}
sessionId = getInterActiveSessionId();
if (attachToSession(int sessionId) == false)
{
// Error handling
return;
}
hThread = CreateThread(NULL, // default security attributes
0, // use default stack size
MyThreadFunction, // thread function name
NULL, // argument to thread function
CREATE_SUSPENDED, // Delay execution
&threadId);
if (SetThreadToken(hThread, hDupToken) == false)
{
// Error handling
return;
}
ResumeThread(hThread);
I cannot garantee that this will resolve your problem, but I hope it does. Good luck!

CreateDesktop() with vista and UAC on (C, windows)

I asked this in CreateDesktop() with Vista UAC (C Windows)
I set a bounty but in trying to vote down the only answer the "accept" was pressed by mistake (i've been awake for more than 48 hs). so I am asking it again.
I'm using CreateDesktop() to create a temporary desktop where an application will run, perform a cleanup action (while remaining out of the way) and terminate. I'm closing that desktop once the application is gone. Everything is fine when using Windows XP and even Vista. The problem arises when you enable the (annoying) UAC.
Everything is OK when you create a desktop, but when you call CreateProcess() to open a program on that desktop it causes the opened application to crash with an exception on User32.dll.
I've been reading a lot about the different desktops and layers on Windows and the restrictions of memory. However, most of the programs I open (as test scenarios) are OK, but a few (like IE, Notepad, Calc and my own application) cause the crash.
Anyone has any idea why this happen on Vista with UAC, or more specifically for those specific programs? and how to fix this?
Anyone has a good solid example on how to create a desktop and open an application there without switching to it under Vista with UAC on?
Code is appreciated.
Thanks
The code used is
SECURITY_ATTRIBUTES sa;
HDESK dOld;
HDESK dNew;
BOOL switchdesk, switchdesk2, closedesk;
int AppPid;
sa.bInheritHandle = TRUE;
sa.lpSecurityDescriptor = NULL;
sa.nLength = sizeof(SECURITY_ATTRIBUTES);
//Get handle to current desktop
dOld = OpenDesktopA("default", 0, TRUE, DESKTOP_SWITCHDESKTOP|
DESKTOP_WRITEOBJECTS|
DESKTOP_READOBJECTS|
DESKTOP_ENUMERATE|
DESKTOP_CREATEWINDOW|
DESKTOP_CREATEMENU);
if(!dOld)
{
printf("Failed to get current desktop handle !!\n\n");
return 0;
}
//Make a new desktop
dNew = CreateDesktopA("kaka", 0, 0, 0, DESKTOP_SWITCHDESKTOP|
DESKTOP_WRITEOBJECTS|
DESKTOP_READOBJECTS|
DESKTOP_ENUMERATE|
DESKTOP_CREATEWINDOW|
DESKTOP_CREATEMENU, &sa);
if(!dNew)
{
printf("Failed to create new desktop !!\n\n");
return 0;
}
AppPid = PerformOpenApp(SomeAppPath);
if(AppPid == 0)
{
printf("failed to open app, err = %d\n", GetLastError());
}
else
{
printf("App pid = %d\n", AppPid);
}
closedesk = CloseDesktop(dNew);
if(!closedesk)
{
printf("Failed to close new desktop !!\n\n");
return 0;
}
return 0;
The correct solution is given as a short comment by ChristianWimmer above:
The desktop must have a security descriptor that allows access to lower integrity level like IE has. Otherwise the GUI cannot access the desktop. – ChristianWimmer Jul 22 '10 at 17:00
Since the answer is a little bit hidden and there's no source code example, let me state it clearly here:
If IE runs in protected mode then the browser tabs are created as low integrity processes. The low integrity tab process will fail to initialize if the desktop does not have a low integrity mandatory label.
As a consequence, the main IE process terminates, too. An interesting observation is that if you start IE providing a command line URL from the secure zone, then IE will succeed to start, because protected mode is disabled by default for the secure zone.
I checked the integrity level of the default desktop, and indeed I was able to verify that the default desktop has a low integrity level! So the easiest solution to the problem is to (1) create the new desktop, (2) get the mandatory label from the default desktop, and (3) copy it into the new desktop. For (2) and (3), you can use the following code
PACL pSacl;
PSECURITY_DESCRIPTOR pSecurityDescriptor;
DWORD dwResult;
dwResult = GetSecurityInfo(hDefaultDesktop, SE_WINDOW_OBJECT, LABEL_SECURITY_INFORMATION, NULL, NULL, NULL, &pSacl, &pSecurityDescriptor);
if (dwResult == ERROR_SUCCESS) {
if (pSacl != NULL) {
dwResult = SetSecurityInfo(hNewDesktop, SE_WINDOW_OBJECT, LABEL_SECURITY_INFORMATION, NULL, NULL, NULL, pSacl);
if (dwResult != ERROR_SUCCESS)
_tprintf(_T("SetSecurityInfo(hNewDesktop) failed, error = %d"), dwResult);
}
LocalFree(pSecurityDescriptor);
} else {
_tprintf(_T("GetSecurityInfo(hDefaultDesktop) failed, error = %d"), dwResult);
}
#CristianWimmer: Thanks for providing the hint to the correct solution. This saved my a lot of time!!
You appear to have come across a bug in IE as it interacts with UAC. If protected mode is set to on you cannot run IE as an ordinary user in any desktop except the default one. In order to run IE in an alternate desktop you must be running as administrator or have protected mode set to off. This is true for Vista, W2K8 and Win7.
As to the other programs that you cannot run, unfortunately I can't confirm anything. I tried upwards of thirty different programs including notepad, calc, all the office apps, visual studio 2005, 2008 and 2010, MSDN help and a number of others and all worked as expected with the noted exception of IE. Is there something truly unusual about your app that might make it behave in an unexpected manner?
One note - if you attempt to run an application like this that needs elevation (such as regedit, etc.) it will fail in CreateProcess with the last error set to ERROR_ELEVATION_REQUIRED.
For your reference, in case I'm doing something different from you, the code I used is:
#ifndef _WIN32_WINNT // Specifies that the minimum required platform is Windows Vista.
#define _WIN32_WINNT 0x0600 // Change this to the appropriate value to target other versions of Windows.
#endif
#include <stdio.h>
#include <tchar.h>
#include "windows.h"
HANDLE PerformOpenApp(TCHAR* appPath);
int _tmain(int argc, _TCHAR* argv[])
{
HDESK dNew;
BOOL closedesk;
HANDLE hApp;
//Make a new desktop
dNew = CreateDesktop(_T("kaka"), 0, 0, 0, DESKTOP_SWITCHDESKTOP|
DESKTOP_WRITEOBJECTS|
DESKTOP_READOBJECTS|
DESKTOP_ENUMERATE|
DESKTOP_CREATEWINDOW|
DESKTOP_CREATEMENU, NULL);
if(!dNew)
{
_tprintf(_T("Failed to create new desktop !!\n\n"));
return 0;
}
TCHAR path[MAX_PATH];
_putts(_T("Enter the path of a program to run in the new desktop:\n"));
_getts(path);
while(_tcslen(path) > 0)
{
hApp = PerformOpenApp(path);
if(hApp == 0)
{
_tprintf(_T("Failed to open app, err = %d\n"), GetLastError());
}
else
{
_tprintf(_T("App pid = %d\n"), GetProcessId(hApp));
_putts(_T("Press any key to close the app.\n"));
_gettchar();
TerminateProcess(hApp, 0);
CloseHandle(hApp);
}
_putts(_T("Enter the path of a program to run in the new desktop:\n"));
_getts(path);
}
closedesk = CloseDesktop(dNew);
if(!closedesk)
{
_tprintf(_T("Failed to close new desktop !!\n\n"));
return 0;
}
return 0;
}
HANDLE PerformOpenApp(TCHAR* appPath)
{
STARTUPINFO si = {0};
PROCESS_INFORMATION pi;
si.cb = sizeof(si);
si.lpDesktop = _T("kaka");
BOOL retVal = CreateProcess(NULL, appPath, NULL, NULL, FALSE, CREATE_NEW_CONSOLE, NULL,
NULL, &si, &pi);
if (retVal)
{
CloseHandle(pi.hThread);
}
return pi.hProcess;
}

Resources