Invoking nvcc.exe using CreateProcess - winapi

We currently use a mock JIT compiler for CUDA, where nvcc.exe is invoked on some files and the resulting .ptx files are generated.
bool executeWindowsProcess(ofstream &logFF) {
STARTUPINFO si;
PROCESS_INFORMATION pi;
ZeroMemory( &si, sizeof(si) );
si.cb = sizeof(si);
ZeroMemory( &pi, sizeof(pi) );
char cmd[] = "\"C:\\Program Files\\NVIDIA GPU Computing Toolkit\\CUDA\\v5.0\\bin\\nvcc.exe\"";
char args[] = "\"C:\\Program Files\\NVIDIA GPU Computing Toolkit\\CUDA\\v5.0\\bin\\nvcc.exe\" --ptx --machine 32 -arch=sm_30 -o C:\\Users\\Yutong\\GOODKERNELCOMPILED.ptx --use_fast_math C:\\Users\\Yutong\\tempkernel.cu";
logFF << cmd << endl;
logFF << args << endl;
CreateProcess(cmd, args, NULL, NULL, false, CREATE_DEFAULT_ERROR_MODE, NULL, NULL, &si, &pi);
logFF << GetLastError() << endl;
WaitForSingleObject(pi.hProcess, INFINITE);
logFF << GetLastError() << endl;
CloseHandle( pi.hProcess );
CloseHandle( pi.hThread );
return true;
}
The first GetLastError() returns 123, which seems to indicate that nvcc.exe isn't invoked at all. Setting cmd[] to something like notepad.exe (which is in C:/Windows/System32/notepad.exe) works fine. I've asked some people, and it seems that:
My app is deployed for 32-bit Windows
nvcc.exe is located in C:/Program Files/..../ which is a 64-bit directory, and CreateProcess doesn't seem to be able to invoke executables in directories it doesn't have permission for.
PS, we used to use system() to invoke the JIT compiler, but system() launches an external terminal window (we're writing a GUI) and is generally not recommended.

GetLastError() only has meaning when an actual error occurs. You are not checking the return value of CreateProcess() to make sure an error actually occurred before then calling GetLastError() to retrieve it. You need to do so, eg:
bool executeWindowsProcess(ofstream &logFF)
{
STARTUPINFO si;
PROCESS_INFORMATION pi;
ZeroMemory( &si, sizeof(si) );
si.cb = sizeof(si);
ZeroMemory( &pi, sizeof(pi) );
char cmd[] = "\"C:\\Program Files\\NVIDIA GPU Computing Toolkit\\CUDA\\v5.0\\bin\\nvcc.exe\"";
char args[] = "\"C:\\Program Files\\NVIDIA GPU Computing Toolkit\\CUDA\\v5.0\\bin\\nvcc.exe\" --ptx --machine 32 -arch=sm_30 -o C:\\Users\\Yutong\\GOODKERNELCOMPILED.ptx --use_fast_math C:\\Users\\Yutong\\tempkernel.cu";
logFF << cmd << endl;
logFF << args << endl;
if (!CreateProcess(cmd, args, NULL, NULL, FALSE, CREATE_DEFAULT_ERROR_MODE, NULL, NULL, &si, &pi))
{
logFF << GetLastError() << endl;
return false;
}
logFF << "Running" << endl;
WaitForSingleObject(pi.hProcess, INFINITE);
logFF << "Terminated" << endl;
CloseHandle( pi.hThread );
CloseHandle( pi.hProcess );
return true;
}
With that said, error 123 is ERROR_INVALID_NAME ("The filename, directory name, or volume label syntax is incorrect."). Since you are trying to invoke a command-line, I suggest you set the lpApplicationName parameter of CreateProcess() to NULL and just use the lpCommandLine parameter by itself, eg:
bool executeWindowsProcess(ofstream &logFF)
{
STARTUPINFO si;
PROCESS_INFORMATION pi;
ZeroMemory( &si, sizeof(si) );
si.cb = sizeof(si);
ZeroMemory( &pi, sizeof(pi) );
char args[] = "\"C:\\Program Files\\NVIDIA GPU Computing Toolkit\\CUDA\\v5.0\\bin\\nvcc.exe\" --ptx --machine 32 -arch=sm_30 -o C:\\Users\\Yutong\\GOODKERNELCOMPILED.ptx --use_fast_math C:\\Users\\Yutong\\tempkernel.cu";
logFF << args << endl;
if (!CreateProcessA(NULL, args, NULL, NULL, FALSE, CREATE_DEFAULT_ERROR_MODE, NULL, NULL, &si, &pi))
{
logFF << GetLastError() << endl;
return false;
}
logFF << "Running" << endl;
WaitForSingleObject(pi.hProcess, INFINITE);
logFF << "Terminated" << endl;
CloseHandle( pi.hThread );
CloseHandle( pi.hProcess );
return true;
}

Related

Why isn't this code executing a hello world executable

Why isn't this code running my hello world c executable
#include <windows.h>
#include <string>
int main()
{
// path for hello world compiled program
std::string app_path = "C:\\Users\\test\\Desktop\\a.exe";
BOOL inherit_handles = true;
PROCESS_INFORMATION pi;
STARTUPINFO si;
CreateProcessA(app_path.c_str(),
NULL,
NULL,
NULL,
inherit_handles,
CREATE_NEW_CONSOLE|CREATE_PROTECTED_PROCESS|DETACHED_PROCESS,
0,
NULL,
&si,
&pi);
return 0;
}
I am clueless to why not output is given, even when I use > out.txt, although I do see some cpu usage spikes in process hacker
I also tried to use calc.exe instead of a.exe but this also didn't help
STARTUPINFO needs to be initialized:
STARTUPINFO si;
ZeroMemory(&si, sizeof(si));
si.cb = sizeof(si);
Don't inherit handles unless you need to.
Don't use CREATE_PROTECTED_PROCESS.
Don't use DETACHED_PROCESS unless you want to hide stdout.
Check the return value of CreateProcess!

How to list all modules of a certain process ID

I've written a little program that lists all DLLs of a given process ID:
#include <Windows.h>
#include <TlHelp32.h>
#include <iostream>
#include <memory>
#include <vector>
#include <charconv>
using namespace std;
using XHANDLE = unique_ptr<void, decltype([]( void *h ) { h && h != INVALID_HANDLE_VALUE && CloseHandle( (HANDLE)h ); })>;
vector<MODULEENTRY32W> getModules( DWORD dwProcessId );
[[noreturn]]
void throwSysErr( char const *str );
int main( int argc, char **argv )
{
try
{
if( argc < 2 )
return EXIT_FAILURE;
DWORD dwProcesId =
[&]() -> DWORD
{
DWORD dwRet = 0;
if( from_chars_result fcr = from_chars( argv[1], argv[1] + strlen( argv[1] ), dwRet ); fcr.ec != errc() || *fcr.ptr )
throw system_error( (int)fcr.ec, generic_category(), "invalid process id" );
return dwRet;
}();
for( MODULEENTRY32W const &me : getModules( dwProcesId ) )
wcout << me.szExePath << endl;
}
catch( exception const &exc )
{
cout << exc.what() << endl;
}
}
vector<MODULEENTRY32W> getModules( DWORD dwProcessId )
{
constexpr char const *ERR_STR = "can't list modules";
XHANDLE xhToolHelp( CreateToolhelp32Snapshot( TH32CS_SNAPMODULE, dwProcessId ) );
if( xhToolHelp.get() == INVALID_HANDLE_VALUE )
throwSysErr( ERR_STR );
vector<MODULEENTRY32W> ret;
MODULEENTRY32W me;
me.dwSize = sizeof me;
if( !Module32FirstW( xhToolHelp.get(), &me ) )
if( GetLastError() == ERROR_NO_MORE_FILES )
return ret;
else
throwSysErr( ERR_STR );
for( ; ; )
{
ret.emplace_back( me );
me.dwSize = sizeof me;
if( !Module32NextW( xhToolHelp.get(), &me ) )
if( GetLastError() == ERROR_NO_MORE_FILES )
return ret;
else
throwSysErr( ERR_STR );
}
}
[[noreturn]]
void throwSysErr( char const *str )
{
throw system_error( (int)GetLastError(), system_category(), str );
}
This does work correctly with most programs. I tried this with some process IDs running on my system. But for some 32 bit processes it lists only some essential DLLs. F.e. for Adobe Digital Editions (ADE) it lists:
C:\Program Files (x86)\Adobe Digital Editions\DigitalEditions.exe
C:\Windows\SYSTEM32\ntdll.dll
C:\Windows\System32\wow64.dll
C:\Windows\System32\wow64base.dll
C:\Windows\System32\wow64win.dll
C:\Windows\System32\wow64con.dll
C:\Windows\System32\wow64cpu.dll
For sure this process isn't only running on such a small number of DLLs.
What's going on with 32 bit processes processes like ADE ?
The DLLs you have shown are all 64bit DLLs that are loaded into every 32bit process to run the WOW64 emulation. Since your app is using TH32CS_SNAPMODULE and displaying 64bit DLLs, that suggests your app is running as a 64bit process. The CreateToolhelp32Snapshot() documentation says:
TH32CS_SNAPMODULE
0x00000008
Includes all modules of the process specified in th32ProcessID in the snapshot. To enumerate the modules, see Module32First. If the function fails with ERROR_BAD_LENGTH, retry the function until it succeeds.
64-bit Windows:  Using this flag in a 32-bit process includes the 32-bit modules of the process specified in th32ProcessID, while using it in a 64-bit process includes the 64-bit modules. To include the 32-bit modules of the process specified in th32ProcessID from a 64-bit process, use the TH32CS_SNAPMODULE32 flag.
TH32CS_SNAPMODULE32
0x00000010
Includes all 32-bit modules of the process specified in th32ProcessID in the snapshot when called from a 64-bit process. This flag can be combined with TH32CS_SNAPMODULE or TH32CS_SNAPALL. If the function fails with ERROR_BAD_LENGTH, retry the function until it succeeds.
You were all right. I now conditionally added TH32CS_SNAPMODULE32:
vector<MODULEENTRY32W> getModules( DWORD dwProcessId )
{
constexpr char const *ERR_STR = "can't list modules";
XHANDLE xhProcess( OpenProcess( PROCESS_QUERY_INFORMATION, FALSE, dwProcessId ) );
BOOL fWow64PRocess;
if( !xhProcess.get() || !IsWow64Process( xhProcess.get(), &fWow64PRocess ) )
throwSysErr( ERR_STR );
XHANDLE xhToolHelp( CreateToolhelp32Snapshot( TH32CS_SNAPMODULE | (fWow64PRocess ? TH32CS_SNAPMODULE32 : 0), dwProcessId ) );
if( xhToolHelp.get() == INVALID_HANDLE_VALUE )
throwSysErr( ERR_STR );
vector<MODULEENTRY32W> ret;
MODULEENTRY32W me;
me.dwSize = sizeof me;
if( !Module32FirstW( xhToolHelp.get(), &me ) )
if( GetLastError() == ERROR_NO_MORE_FILES )
return ret;
else
throwSysErr( ERR_STR );
for( ; ; )
{
ret.emplace_back( me );
me.dwSize = sizeof me;
if( !Module32NextW( xhToolHelp.get(), &me ) )
if( GetLastError() == ERROR_NO_MORE_FILES )
return ret;
else
throwSysErr( ERR_STR );
}
}

losing files when using ReadDirectoryChangesW

I'm using ReadDirectoryChangesW to monitor a directory.
Here's my simple code
#include <windows.h>
#include <stdlib.h>
#include <stdio.h>
#include <tchar.h>
#include <iostream>
#include <string>
#include <cwctype>
using namespace std;
wstring getname(FILE_NOTIFY_INFORMATION *tmp)
{
wstring s = L"";
for (int i = 0;i < tmp->FileNameLength / 2;i++)
s += tmp->FileName[i];
return s;
}
void _tmain(int argc, TCHAR *argv[])
{
HANDLE hDir;
char notify[1024];
DWORD cbBytes,i;
char AnsiChar[3];
wchar_t UnicodeChar[2];
LPTSTR path;
FILE_NOTIFY_INFORMATION *pnotify=(FILE_NOTIFY_INFORMATION *)notify;
FILE_NOTIFY_INFORMATION *tmp ;
// GetCurrentDirectory(MAX_PATH,path.GetBuffer(MAX_PATH+1));
wcout.imbue(locale("chs"));
path = argv[1];
hDir = CreateFile( path, FILE_LIST_DIRECTORY,
FILE_SHARE_READ |
FILE_SHARE_WRITE |
FILE_SHARE_DELETE, NULL,
OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS |
FILE_FLAG_OVERLAPPED, NULL);
wcout << L"===CreateFile complete===" << endl;
if (hDir == INVALID_HANDLE_VALUE)
{
wcout << L"invalid handle value" << endl;
return;
}
FILE_NOTIFY_INFORMATION buffer[1024];
FILE_NOTIFY_INFORMATION *pbuffer;
while (TRUE)
{
wcout << L"waiting..." << endl;
if(ReadDirectoryChangesW(hDir, &buffer, sizeof(buffer),
TRUE, FILE_NOTIFY_CHANGE_FILE_NAME| FILE_NOTIFY_CHANGE_LAST_WRITE,
&cbBytes, NULL, NULL))
{
pbuffer = buffer;
do{
tmp = pbuffer;
switch(tmp->Action)
{
case FILE_ACTION_ADDED:
wcout << L"Directory/File added - " << getname(tmp) << endl;
break;
case FILE_ACTION_REMOVED:
wcout << L"Directory/File removed - " << getname(tmp) << endl;
break;
case FILE_ACTION_MODIFIED:
wcout << L"Directory/File modfied - " << getname(tmp) << endl;
break;
case FILE_ACTION_RENAMED_OLD_NAME:
wcout << L"Directory/File old name - " << getname(tmp) << endl;
break;
case FILE_ACTION_RENAMED_NEW_NAME:
wcout << L"Directory/File new name - " << getname(tmp) << endl;
break;
default:
wcout << L"unknown action\n" << endl;
break;
}
pbuffer += pbuffer->NextEntryOffset;
}while(pbuffer->NextEntryOffset);
} else
{
wcout << "readChangesW failed now return" << endl;
return;
}
}
}
It looks fine, however, when I'm adding or deleting a large number of files in my directory, it will not report some of the changes, how can I fix this?
Try making your buffer bigger.
From the documentation for the ReadDirectoryChangesW function:
When you first call ReadDirectoryChangesW, the system allocates a buffer to store change information. This buffer is associated with the directory handle until it is closed and its size does not change during its lifetime. Directory changes that occur between calls to this function are added to the buffer and then returned with the next call. If the buffer overflows, the entire contents of the buffer are discarded and the lpBytesReturned parameter contains zero.
The buffer size that the system allocates is based on the size of the buffer you pass in. If you pass in a bigger size the system will allocate a bigger buffer to store changes that occur while you are processing the previous lot of changes, which means there's less chance of the buffer overflowing and those changes being lost.

Visual C - Win32 APP - how to use system call with system() without opening a command prompt window?

I am new to VC++
I build a simple Win32 Application via default templet.
when i run it it shows a normal window with a menubar.
I added a system call that does a curl operation in InitInstance function:
BOOL InitInstance(HINSTANCE hInstance, int nCmdShow)
{
HWND hWnd;
hInst = hInstance; // Store instance handle in our global variable
hWnd = CreateWindow(szWindowClass, szTitle, WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, NULL, NULL, hInstance, NULL);
if (!hWnd)
{
return FALSE;
}
ShowWindow(hWnd, nCmdShow);
UpdateWindow(hWnd);
//EDITED THIS WILL CREATE A FILE.HTML
system("curl www.google.co.in > file.html");
return TRUE;
}
all works fine.
But the problem is when ever i call system it opens in console window.
I want it to be a hidden process that does not shows that command prompt window..
help me with this.
The system function always shows a console window. If you want a hidden console window, you need to call CreateProcess directly. You can then ask for a DETACHED_PROCESS which runs without a console. Note that CreateProcess does not wait for the process to exit, so you will need to perform the wait yourself.
I put code in separate function, with url and filename as parameters.
#include <tchar.h>
#include <windows.h>
BOOL DownloadWithoutConsole(TCHAR* pszURI, TCHAR* pszFileName)
{
//here we will calculate our command line length in bytes
DWORD dwLen = (lstrlen(pszURI) + lstrlen(pszFileName) + 20)*sizeof(TCHAR);
//memory allocation for the command line
TCHAR* pszCmdLine = (TCHAR*)HeapAlloc(GetProcessHeap(), 0, dwLen);
ZeroMemory(pszCmdLine, dwLen);
//making command line
_stprintf_s(pszCmdLine,dwLen/sizeof(TCHAR), TEXT("cmd /c curl %s > %s"), pszURI, pszFileName);
//preparing arguments for CreateProcess
STARTUPINFO si;
ZeroMemory(&si, sizeof(si));
si.cb = sizeof(si);
PROCESS_INFORMATION pi;
ZeroMemory(&pi, sizeof(pi));
//creating new process
BOOL bResult = CreateProcess(NULL, pszCmdLine, NULL, NULL, FALSE, CREATE_NO_WINDOW,
NULL, NULL, &si, &pi);
if(bResult)
{
//waiting for process termination
WaitForSingleObject(pi.hProcess, INFINITE);
//cleanup
CloseHandle(pi.hProcess);
CloseHandle(pi.hThread);
}
//freeing memory
HeapFree(GetProcessHeap(), 0, pszCmdLine);
return(bResult);
}
int __cdecl _tmain(void)
{
DownloadWithoutConsole(TEXT("stackoverflow.com"), TEXT("test.txt"));
return(0);
}
Set nCmdShow to SW_HIDE(0) (ShowWindow). This way u will run it without he cmd prompt

got error 1314 when doing SetTokenInformation

#include <windows.h>
#include <stdio.h>
#include <Userenv.h>
#include <Wtsapi32.h>
int main() {
DWORD err;
err=GetLastError();
printf( "err001:%d\n",err);
HANDLE hTokenThis = NULL;
HANDLE hTokenDup = NULL;
HANDLE hThisProcess = GetCurrentProcess();
OpenProcessToken(hThisProcess, TOKEN_ALL_ACCESS, &hTokenThis);
err=GetLastError();
printf( "err002:%d\n",err);
DuplicateTokenEx(hTokenThis, MAXIMUM_ALLOWED,NULL, SecurityIdentification, TokenPrimary, &hTokenDup);
err=GetLastError();
printf( "err003:%d\n",err);
DWORD dwSessionId = WTSGetActiveConsoleSessionId();
WTSQueryUserToken(dwSessionId, hTokenDup);
//DWORD dwSessionId = 1;
SetTokenInformation(hTokenDup, TokenSessionId, &dwSessionId, sizeof(DWORD));
err=GetLastError();
printf( "err004:%d\n",err);
STARTUPINFO si;
PROCESS_INFORMATION pi;
ZeroMemory(&si, sizeof(STARTUPINFO));
ZeroMemory(&pi, sizeof(PROCESS_INFORMATION));
si.cb = sizeof(STARTUPINFO);
si.lpDesktop = "WinSta0\\Default";
LPVOID pEnv = NULL;
DWORD dwCreationFlag = NORMAL_PRIORITY_CLASS | CREATE_NEW_CONSOLE;
CreateEnvironmentBlock(&pEnv, hTokenDup, FALSE);
err=GetLastError();
printf( "err005:%d\n",err);
CreateProcessAsUser(
hTokenDup,
NULL,
(char *)"notepad",
NULL,
NULL,
FALSE,
dwCreationFlag,
pEnv,
NULL,
&si,
&pi);
printf("here we go\n");
err=GetLastError();
printf( "err006:%d\n",err);
return 0;
}
Compile:
gcc -o session.exe session.c c://Windows/System32/kernel32.dll c://Window
s/System32/wtsapi32.dll -lUserenv
Running Result:
session.exe
err001:126
err002:126
err003:126
err004:1314
err005:203
here we go
err006:87
gcc version 4.5.2 (GCC) from mingw.
btw, just ignore the error 126.
My question is :
Why got error 1314?
I want to start a program in the interactive desktop from service by using CreateProcessAsUser without knowing the logon user and password.
Error 1314 is "A required privilege is not held by the client".
From the WTSQueryUserToken() docs (http://msdn.microsoft.com/en-us/library/aa383840.aspx):
To call this function successfully, the calling application must be running within the context of the LocalSystem account and have the SE_TCB_NAME privilege
Also your call to WTSQueryUserToken() should look like:
WTSQueryUserToken(dwSessionId, &hTokenDup);
And you'll need appropriate privileges for SetTokenInformation() enabled as well.
Bottom line is that you're trying to do something that Windows reserves for highly privileged processes, so you'll need to make sure your process is configured to run appropriately (maybe as a service that talks to a regular non-privileged process for user interaction).

Resources