How to run program from hidden folder WinAPI - c++

I'm try to run program with this code:
PROCESS_INFORMATION ProcInfo = { 0 };
STARTUPINFO StartInfo = { 0 };
StartInfo.cb = sizeof(StartInfo);
if (!::CreateProcessW(NULL, (LPWSTR)wszPathToFile, NULL, NULL, FALSE, DETACHED_PROCESS, NULL, NULL, &StartInfo, &ProcInfo)) {
return GetLastError();
}
But I get error message: The system cannot find the path specified.
wszPathToFile - path to file (example: "C:\test\test.exe /retest"). Folder "test" is hidden
How to fix it?

That the folder is hidden is not relevant. That has no impact here.
As discussed in the comments, the fact that you are casting the lpCommandLine argument indicates that szPathToFile is not the correct type. It must be a pointer to a modifiable array of wide characters. If it was then you could omit the cast and the compiler would accept szPathToFile directly.
Most likely szPathToFile is actually a pointer to an array of ANSI encoded 8 bit char.

Related

How to write to temporary folder

I am trying to write a file to the temporary folder, but it is not being executed properly. When I later go in the code to call this, it references the correct location, but says it does not exist. Any Ideas as to what I am doing wrong?
ofstream fout("%TEMP%\\test.bat");
fout << "cd C:\\Users\\jrowler\\Documents" << endl;
//Some more fout commands to write to bat
fout.close();
wchar_t cmdline[] = L"cmd.exe /C %TEMP%\\test.bat";
if (!CreateProcess(NULL, cmdline, NULL, NULL, false, CREATE_UNICODE_ENVIRONMENT,
(LPVOID)env.c_str(), NULL, &si, &pi))
{
std::cout << GetLastError();
abort();
}
Everything works if I am not trying to use the TEMP folder. If I wanted to put it on my desktop, it works perfectly fine. Any ideas why the environment variable does not work correctly when creating, but when trying to create the process, it give me an error that references the correct location specified by the environment variable.
As Retired Ninja points out, you may want to translate the environment variable, if you choose to use an environment variable.
In addition, there are other methods for special folders. In fact, the temp folder has a dedicated function - GetTempPath().
DWORD const bufferSize = ::GetTempPath(0u, nullptr) + 1u; // get the necessary buffer size
ASSERT(bufferSize);
wchar_t* buffer = new wchar_t[bufferSize];
std::memset(buffer, 0x00, bufferSize);
VERIFY(::GetTempPath(bufferSize, &buffer[0u]));
// [ perform various logic ]
delete[] buffer;
For other special folders, you may choose to use the Shell API.
SHGetFolderPath() and SHGetKnownFolderPath() work well across various versions of windows, wherever the target folder may be located. And there are a tremendous number of folders.
wchar_t folder[MAX_PATH+1];
int const folderId = ... // <-- defined in Shlobj.h
HRESULT const hr = ::SHGetFolderPath(nullptr, folderId, nullptr, SHGFP_TYPE_CURRENT, folder);
if (S_OK != hr)
{
TRACE("ERROR: Unable to get folder path.");
return false;
}
// [ perform various logic ]
wchar_t* folder = nullptr;
KNOWNFOLDERID const folderId = ... // <-- defined in KnownFolder.h
HRESULT const hr = ::SHGetKnownFolderPath(folderId, 0u, nullptr, &folder);
if (S_OK != hr)
{
TRACE("ERROR: Unable to get folder path.");
return false;
}
// [ perform various logic ]
::CoTaskMemFree(folder);
EDIT: There is an example specifically for creating and using a temp file.
EDIT2: Note that TEMP/TMP environment variables may be slightly different on various systems. However they should be the same value. Look at the 'remarks' section of GetTempPath() to see how the path is determined.

.c_str() doesn't behave as expected

I want to create a process to read out some serial port. However the user should be able to change the path where the program is located in the future. This is why I would like to include the variable BasePathFile, which is set to the default value durin the initialization of the class:
const std::string BP = "C:\\aerospec_developement\\";
...
BasePathFile = BP;
...
Can someone explain why //1 doesn't work, but //2 is fine
void AerospecGUI::ReadPressure()
{
//1 const char *Args = ("C:\\Windows\\System32\\cmd.exe /C powershell /C "+ BasePathFile+"sourcecode\\pressure.ps1 -comport COM4 -baud 1200 -parity None -data 8 -stopbits one").c_str();
//2 const char *Args = "C:\\Windows\\System32\\cmd.exe /C powershell /C C:\\aerospec_developement\\sourcecode\\pressure.ps1 -comport COM4 -baud 1200 -parity None -data 8 -stopbits one";
STARTUPINFO StartupInfo;
PROCESS_INFORMATION ProcessInfo;
memset(&StartupInfo, 0, sizeof(StartupInfo));
memset(&ProcessInfo, 0, sizeof(ProcessInfo));
StartupInfo.cb = sizeof(StartupInfo);
wchar_t wargs[1000];
mbstowcs(wargs, Args, strlen(Args)+1);//Plus null
LPWSTR argsptr = wargs;
bool result = CreateProcess(NULL, argsptr, NULL, NULL, FALSE, NULL, NULL, NULL,
&StartupInfo, &ProcessInfo);
...
Further, the author wrote a very similar line in another function. But this one worked.
bool AerospecGUI::FTP(std::string command, std::string file)
{
// This function executes a batch script with the given parameters. The batch script
// generates a .ftp file which contains the commands to perform the action given by "command"
// (get, put, delete).
const char *Args = ("C:\\Windows\\System32\\cmd.exe /C "+BasePathFile +"FTP\\FileTransfer.bat " + ServerURL + " root password " + command + " " + BasePathFile + "FTP\\ " + file +" " + BasePathFile + "FTP\\" + file.substr(0,file.size()-4)+".ftp").c_str();
STARTUPINFO StartupInfo;
PROCESS_INFORMATION ProcessInfo;
memset(&StartupInfo, 0, sizeof(StartupInfo));
memset(&ProcessInfo, 0, sizeof(ProcessInfo));
StartupInfo.cb = sizeof(StartupInfo);
wchar_t wargs[1000];
mbstowcs(wargs, Args, strlen(Args)+1);//Plus null
LPWSTR argsptr = wargs;
...
1 and the original author code are wrong: c_str() returns a pointer to a C-like string, but it's a member function of the std::string class (see docs). Dereferencing its pointer after the std::string object has expired is undefined behavior (may or may not work).
2 works fine instead
const char *Args = "C:\\... one";
since it's a string literal and its lifetime spans for the entire program execution.
For 1 you create a temporary std::string object, and gets a pointer to its internal string. Once the temporary object is destructed the string ceases to exist and the pointer will not be pointing anywhere valid.
For 2 you have an actual constant string literal, who has a lifetime of the program and will never cease to exist.
That is seems to be working for your second example is just a fluke. What you have with the stray invalid pointer is undefined behavior and sometimes those might seem to work just fine.

Error "<url> is not recognized as an internal or external command, operable program or batch file."

My code should take arguments, put "+" inbetween them, and search google chrome with this, however I get the error (Command line Argument= "Stack Overflow Site"):
http://www.google.com/search?q=Stack+Overflow+Site'C:\Program' is not
recognized as an internal or external command, operable program or
batch file.
Also in my program I get this error:
error C4996: 'strcpy': This function or variable may be unsafe.
Consider using strcpy_s instead. To disable deprecation, use
_CRT_SECURE_NO_WARNINGS. See online help for details. c:\users\user\documents\visual studio
2013\projects\project1\project1\main.cpp
I have been ignoring this, because I thought it was just a warning, but I'm not sure if it is relevant.
My code:
#include <Windows.h>
#include <string>
#include <iostream>
using namespace std;
int main(int argc, char** argv){
//Loop through arguments and put a "+" between them.
string out = "";
for (int i = 1; i < argc; ++i) {
if (i != 1){
out += "+";
}
out += argv[i];
}
string newout = "C:\\Program Files (x86)\\Google\\Chrome\\Application\\chrome.exe \"http://www.google.com/search?q=" + out + "\"";
// set the size of the structures
STARTUPINFO si;
PROCESS_INFORMATION pi;
ZeroMemory(&si, sizeof(si));
si.cb = sizeof(si);
ZeroMemory(&pi, sizeof(pi));
//set y to newout and convert
char *y = new char[newout.length() + 1];
strcpy(y, newout.c_str());
//Run Google Chrome with argument
CreateProcessA("C:\\Program Files (x86)\\Google\\Chrome\\Application\\chrome.exe", // the path
y, // Command line
NULL, // Process handle not inheritable
NULL, // Thread handle not inheritable
FALSE, // Set handle inheritance to FALSE
0, // No creation flags
NULL, // Use parent's environment block
NULL, // Use parent's starting directory
&si, // Pointer to STARTUPINFO structure
&pi // Pointer to PROCESS_INFORMATION structure
);
delete[] y;
cin.ignore();
}
I suspect you are not getting exactly the same error since you
stopped deleting the commandline buffer before using it, but
some different, equally unexpected result.
If you will read the documentation of CreateProcess
you will learn that the parameters:
_In_opt_ LPCTSTR lpApplicationName,
_Inout_opt_ LPTSTR lpCommandLine,
can be supplied in one of three ways, as illustrated:-
Way 1
lpApplicationName = "\path\to\executable"
lpCommandLine = "args for the executable"
which results in a process initiated with the command:
\path\to\executable args for the executable
Way 2
lpApplicationName = NULL
lpCommandLine = "\path\to\executable args for the executable"
which results in the same process as Way 1
Way 3
lpApplicationName = "\path\to\executable"
lpCommandLine = NULL
which results in a process initiated with the command \path\to\executable.
You are not using Way 1 or Way 2 or Way 3, but:
lpApplicationName = "\path\to\executable"
lpCommandLine = "\path\to\executable args for the executable"
which in your case results in a process initiated with the command:
"C:\\Program Files (x86)\\Google\\Chrome\\Application\\chrome.exe \
C:\\Program Files (x86)\\Google\\Chrome\\Application\\chrome.exe \
http://www.google.com/search?q=Stack+Overflow+Site"
in which the arguments passed to Chrome are:
C:\\Program Files (x86)\\Google\\Chrome\\Application\\chrome.exe \
http://www.google.com/search?q=Stack+Overflow+Site"
Of course this does not have the anticipated outcome.
Should you wish to correct this by adopting Way 2, bear particularly
in mind what the documentation says about lpCommandLine:
...
If lpApplicationName is NULL, the first white space–delimited token of the command line specifies the module name.
...

C++ Get Program files dir, append extra path and execute

I'm trying to write a few simple lines of code that will get the 'Program Files' dir path on both XP and Vista/7 (on vista/7 I need the path to the x86 folder), add some extra path to an application and execute it.
This is what I have so far, but it's not executing the external program, not giving an error as well..
wchar_t localAppData[MAX_PATH];
STARTUPINFO sInfo;
PROCESS_INFORMATION pInfo;
SHGetFolderPath(NULL, CSIDL_PROGRAM_FILESX86, 0, NULL, localAppData);
std::wstringstream ss;
ss << localAppData << L"/MyApp/MyExe.exe";
LPCWSTR str = ss.str().c_str();
CreateProcess(str, NULL,NULL, NULL,FALSE,NULL,NULL,NULL,&sInfo,&pInfo);
return str;
I've updated my code to this according to hmjd's suggestion:
wchar_t localAppData[MAX_PATH];
STARTUPINFO sInfo = { sizeof(STARTUPINFO), NULL, L"winsta0\\default" };
PROCESS_INFORMATION pInfo;
SHGetFolderPath(NULL, CSIDL_PROGRAM_FILESX86, 0, NULL, localAppData);
std::wstringstream ss;
ss << localAppData << L"/PacificPoker/bin/888poker.exe";
std::wstring ss_str = ss.str();
wchar_t* path = new wchar_t[ss_str.length() + 1]();
std::copy(ss_str.begin(), ss_str.end(), path);
CreateProcess(path, NULL,NULL, NULL,FALSE,NULL,NULL,NULL,&sInfo,&pInfo);
delete[] path;
return GetLastError();
Still getting '3' for GetLastError, but I can confirm that C:\Program Files\MyApp\MyExe.exe exists..
A few problems with the code:
sInfo is not initialised, you at least need to set the cb member
STARTUPINFO sInfo = { sizeof(STARTUPINFO), // 'cb'
NULL, // 'lpReserved'
L"winsta0\\default" };// 'lpDesktop'
See STARTUPINFO for more details.
the first argument to CreateProcess() should be non-const, but is being passed c_str() which would be a const if it was not a dangling pointer. The ss.str() method returns a std::string, and the c_str() is returning a pointer into that std::string but it is a temporary object and is destroyed at the end of the expression (the ;), making str a dangling pointer. Change to:
std::wstring ss_str = ss.str();
wchar_t* path = new wchar_t[ss_str.length() + 1]();
std::copy(ss_str.begin(), ss_str.end(), path);
CreateProcess(path, ...);
delete[] path;
Check return values of all your functions and query GetLastError() to determine failure reason.
You've probably tried this, but does localAppData get a valid string if you set the CSIDL to CSIDL_PROGRAM_FILES instead of CSIDL_PROGRAM_FILESX86?
If you're testing under XP, I don't know what CSIDL_PROGRAM_FILESX86 will return.

EnumProcessModulesEx fails returning error code 299 (ERROR_PARTIAL_COPY)

I am calling the function EnumProcessModulesEx and it fails. I running on a 64-bit machine. Here is the code below:
wchar_t* dest = new wchar_t[100];
int index = SendMessage(processes, LB_GETCURSEL, 0, 0);
SendMessage(processes, LB_GETTEXT, index, (LPARAM)dest);
HMODULE module;
unsigned long cbneeded;
EnableTokenPrivilege(hWnd, SE_DEBUG_NAME);
HANDLE h = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, 0, _wtoi(dest));
int errorcode = GetLastError();
BOOL ret = EnumProcessModulesEx(h, &module, sizeof module, &cbneeded, LIST_MODULES_ALL);
int err = GetLastError();
wchar_t* name = new wchar_t[MAX_PATH];
GetModuleBaseName(h, module, name, sizeof name);
MessageBox(hWnd, name, L"Process Name", 0);
delete dest;
delete name;
Most probably you are trying to open 32bit process from 64bit application or vice versa. You can only work with processes of the same kind.
BOOL ret = EnumProcessModulesEx(h, &module, sizeof module, &cbneeded, LIST_MODULES_ALL);
The 3rd argument is supposed to be the size of the array of HMODULES you pass in the 2nd argument. You only pass 1, not big enough. Note the lpcbNeeded, it tells you how large the array needs to be to not get the error.
If the target platform is x86, then you can try to change it to x64.
You can read the document: https://learn.microsoft.com/en-us/windows/win32/api/psapi/nf-psapi-enumprocessmodules
If this function is called from a 32-bit application running on WOW64, it can only enumerate the modules of a 32-bit process. If the process is a 64-bit process, this function fails and the last error code is ERROR_PARTIAL_COPY (299).
Well, what does GetLastError return? EDIT: my bad, I failed hard..
Do error-checking and make sure it's not SendMessage, EnableTokenPrivilege, or OpenProcess that's giving you the error.