Popen.cppの修正
以前の記事C++ Builder CE 外部プログラムの利用で掲載したpopen.cppですが、プロジェクトの設定によってはコンパイルエラーが出ることがあります。要は、
[bcc32c エラー] popen.cpp(55): no matching function for call to 'CreateProcessW'
processthreadsapi.h(373): candidate function not viable: no known conversion from 'char *' to 'LPWSTR' (aka 'wchar_t *') for 2nd argument
というようなことです。これはプロジェクトオプションの設定の、
上図の_TCHARのマップ先がcharないしwchar_tかに依存するエラーなのですが、デフォルトの設定はwchar_tなので、それに合わせて、wchar_tにすべきという意味を込めて、Popen.cppを修正しました。原理は、wchar_tでない場合は、コンパイルエラーを発生させて注意を喚起するという観点です。修正した結果のpopen.cppを掲載します。
#include <iostream>
#include <fstream>
#include <string>
#include <memory>
#include <array>
#include <Windows.h>
#if !defined(UNICODE)
#error Please set _TCHAR mapping to wchar_t in project option C++(common option)
#endif
String Popen(const String command, const String arguments,DWORD& rc)
{
SECURITY_ATTRIBUTES sa;
HANDLE read, write;
std::string rtn;
const String cmd_str = command + " " + arguments + "\0";
std::shared_ptr<char> cmd(new char[cmd_str.Length() + 1], std::default_delete<char[]>());
std::copy(cmd_str.begin(), cmd_str.end(), cmd.get());
cmd.get()[cmd_str.Length()] = '\0';
sa.nLength = sizeof(SECURITY_ATTRIBUTES);
sa.bInheritHandle = TRUE;
sa.lpSecurityDescriptor = NULL;
if (!CreatePipe(&read, &write, &sa, 0))
{
std::cerr << "CreatePipe is Error!" << std::endl;
return String("");
}
STARTUPINFOA si = {};
si.cb = sizeof(STARTUPINFO);
si.dwFlags = STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW;
si.wShowWindow = SW_HIDE;
si.hStdInput = GetStdHandle(STD_INPUT_HANDLE);
si.hStdOutput = write;
si.hStdError = write;
if (si.hStdOutput == INVALID_HANDLE_VALUE || si.hStdError == INVALID_HANDLE_VALUE)
{
std::cerr << "GetStdHandle is Error!" << std::endl;
return String("");
}
PROCESS_INFORMATION pinfo = {};
if (!CreateProcessA(NULL, cmd.get(), NULL, NULL, TRUE, DETACHED_PROCESS, NULL, NULL, &si, &pinfo))
{
std::cerr << "CreateProcess is Error!" << std::endl;
return String("");
}
HANDLE child = pinfo.hProcess;
if (!CloseHandle(pinfo.hThread))
{
std::cerr << "CloseHandle(hThread) is Error!" << std::endl;
return String("");
}
DWORD r = WaitForSingleObject(child, INFINITE);
switch (r)
{
case WAIT_FAILED:
std::cerr << "WaitResult:WAIT_FAILED" << std::endl;
return String("");
case WAIT_ABANDONED:
std::cerr << "WaitResult:WAIT_ABANDONED" << std::endl;
return String("");
case WAIT_OBJECT_0:
GetExitCodeProcess(child,&rc);
break;
case WAIT_TIMEOUT:
std::cerr << "WaitResult:WAIT_TIMEOUT" << std::endl;
return String("");
default:
std::cerr << "WaitResult:" << r << std::endl;
return String("");
}
if (!CloseHandle(write))
{
std::cerr << "CloseHandle(write) is Error!" << std::endl;
return String("");
}
write = NULL;
std::array<unsigned char, 1024> buf = { 0 };
DWORD rlen = 0;
while (ReadFile(read, buf.data(), buf.size(), &rlen, NULL))
{
std::copy(buf.begin(), buf.begin() + rlen, std::back_inserter(rtn));
}
if (!CloseHandle(read))
{
std::cerr << "CloseHandle(read) is Error!" << std::endl;
return String("");
}
read = NULL;
return rtn.c_str();
}
デフォルトに合わせて、CreateProcessを明示的にCreateProcessAに、STARTUPINFOを明示的にSTARTUPINFOAに変更しました。
コメント