#include <iostream>
#include <Windows.h>
#include <ShellAPI.h>
#include <io.h>
#include <stdlib.h>
#include <sstream>
#include <vector>
#include <string>
#pragma comment(lib, "shell32.lib")
void system_error(wchar_t *name) {
// Retrieve, format, and print out a message from the last error.
// The `name' that's passed should be in the form of a present tense
// noun (phrase) such as "opening file".
//
wchar_t *ptr = NULL;
FormatMessageW( FORMAT_MESSAGE_ALLOCATE_BUFFER |
FORMAT_MESSAGE_FROM_SYSTEM,
0, GetLastError(), 0, (wchar_t *)&ptr, 1024, NULL);
LocalFree(ptr);
}
std::wstring find_image(std::wstring const &name) {
// Try to find an image file named by the user.
// First search for the exact file name in the current
// directory. If that's not found, look for same base name
// with ".com", ".exe" and ".bat" appended, in that order.
// If we can't find it in the current directory, repeat
// the entire process on directories specified in the
// PATH environment variable.
//
#define elements(array) (sizeof(array)/sizeof(array[0]))
static wchar_t *extensions[] = {L".com", L".exe", L".bat", L".cmd"};
if (-1 != _waccess(name.c_str(), 0))
return name;
for (int i=0; i<elements(extensions); i++)
if (-1 != _waccess((name+extensions[i]).c_str(), 0))
return name+extensions[i];
wchar_t buffer[FILENAME_MAX];
_wsearchenv(name.c_str(), L"PATH", buffer);
if ( buffer[0] != L'\0')
return std::wstring(buffer);
for (int i=0; i<elements(extensions); i++) {
_wsearchenv((name+extensions[i]).c_str(), L"PATH", buffer);
if ( buffer[0] != L'\0')
return std::wstring(buffer);
}
return std::wstring(L"");
}
class args {
std::vector<std::wstring> arguments;
public:
args() {
wchar_t *cmd_line = GetCommandLineW();
int argc;
wchar_t **args = CommandLineToArgvW(cmd_line, &argc);
for (int i=0; i<argc; i++)
arguments.push_back(args[i]);
LocalFree(args);
}
// args[0] = timer
// args[1] = command to execute
// remaining args = args to command to execute
std::wstring command() const {
std::wstring image = find_image(arguments[1]);
return image;
}
std::wstring arg_list() const {
if (arguments.size() < 3)
return std::wstring(L"");
std::wostringstream buffer;
for (int i=1; i<arguments.size(); i++)
buffer << L"\"" << arguments[i] << L"\" ";
return buffer.str();
}
};
HANDLE spawn(args const &a) {
PROCESS_INFORMATION p = {0};
STARTUPINFOW s = {0};
if (a.command().empty())
return INVALID_HANDLE_VALUE;
wchar_t buffer[FILENAME_MAX] = {0};
std::wstring arg_list = a.arg_list();
if (!arg_list.empty())
std::copy(arg_list.begin(), arg_list.end(), buffer);
if (!CreateProcessW(a.command().c_str(), buffer, NULL, NULL, TRUE,
NORMAL_PRIORITY_CLASS, NULL, NULL, &s, &p))
{
system_error(L"Spawning program");
return INVALID_HANDLE_VALUE;
}
WaitForSingleObject(p.hProcess, INFINITE);
return p.hProcess;
}
FILETIME operator-(FILETIME const &a, FILETIME const &b) {
FILETIME ret;
ret.dwHighDateTime = a.dwHighDateTime - b.dwHighDateTime;
ret.dwLowDateTime = a.dwLowDateTime - b.dwLowDateTime;
return ret;
}
std::wostream &operator<<(std::wostream &os, FILETIME const &a) {
long long interval = a.dwLowDateTime | ((long long)a.dwHighDateTime << 32);
return os << (double)interval / 10000000.0;
}
int main(void) {
HANDLE child = spawn(args());
if (child == INVALID_HANDLE_VALUE) {
std::wcerr << L"Unable to spawn: " << args().command() << L"\n";
return EXIT_FAILURE;
}
FILETIME creation_time, exit_time, kernel_time, user_time;
GetProcessTimes(child, &creation_time, &exit_time, &kernel_time, &user_time);
std::wcout << L"\n\nReal\t" << exit_time - creation_time << L"\n";
std::wcout << L"User\t" << user_time << L"\n";
std::wcout << L"Sys\t" << kernel_time << L"\n";
return 0;
}