我不知道c ++和我在尝试将字符串名称附加到SHELLEXECUTEINFO的lpFile时遇到问题。我从Installshield获得一个以分号分隔的字符串,然后将其拆分并循环遍历它。我试图然后附加从字符串中拆分的每个“功能”,并通过shell执行将其发送到dism.exe。
它在template<typename Out>
void split(const std::string &s, char delim, Out result) {
std::stringstream ss;
ss.str(s);
std::string item;
while (std::getline(ss, item, delim)) {
*(result++) = item;
}
}
HRESULT __stdcall SplitString(IDispatch *pAction) {
// Create a pointer to the IsSuiteExtension COM interface
CComQIPtr<ISuiteExtension2> spSuiteExtension2 = pAction;
// Turn on notifications for both the progress bar(epfProgressValid) and the ui message(epfMessageValid).
EnumProgressFlags pf = EnumProgressFlags(EnumProgressFlags::epfMessageValid | EnumProgressFlags::epfProgressValid);
BSTR bstrFeatureList(_T("ENABLE_FEATURES")); // Property name to get. This should be a semi-colon delimeted list of features to enable for windows.
BSTR FeatureList = ::SysAllocStringLen(NULL, 2 * 38); // Where to store the property value
HRESULT hRet = spSuiteExtension2->get_Property(bstrFeatureList, &FeatureList); // Get the property value and store it in the 'FeatureList' variable
CW2A pszConverted(FeatureList);
using namespace std;
string strConverted(pszConverted);
vector<string> tokens;
split(strConverted, ';', back_inserter(tokens));
int numTokens = tokens.size();
for (int i = 0; i < numTokens; i++)
{
string t = tokens.at(i);
TCHAR buf[1024];
SHELLEXECUTEINFO ShExecInfo = { 0 };
ShExecInfo.cbSize = sizeof(SHELLEXECUTEINFO);
ShExecInfo.fMask = SEE_MASK_NOCLOSEPROCESS;
ShExecInfo.hwnd = NULL;
ShExecInfo.lpVerb = NULL;
// Convert ANSI to Unicode
ATL::CA2W wc(tokens.at(i).c_str());
swprintf_s(buf, _T("Dism.exe /Online /Enable-Feature /FeatureName:%s"), sizeof(buf), wc); // HAVING ISSUES HERE. NEED TO APPEND tokens.at(i) AT %S
ShExecInfo.lpFile = buf;
ShExecInfo.lpParameters = _T("");
ShExecInfo.lpDirectory = _T("C:\\Windows\\SysNative");
ShExecInfo.nShow = SW_SHOW;
ShExecInfo.hInstApp = NULL;
ShellExecuteEx(&ShExecInfo);
WaitForSingleObject(ShExecInfo.hProcess, INFINITE);
}
//MessageBoxA(NULL, strConverted.c_str(), "testx", MB_OK);
return ERROR_SUCCESS;
}
失败如果我评论outh然后它将至少触发dll并抛出dism.exe错误,所以我知道呼叫正常工作。
$ perl -e'CORE::say "100" =~ s/1*/\*/rg'
**0*0*
答案 0 :(得分:2)
由于您的代码使用的是TCHAR
个字符串,因此您应该使用_stprintf_s()
代替swprintf_s()
。正如Adrian McCarthy所说,你的参数传递顺序错误,所以你的代码甚至不应该编译开始。
但更重要的是,根本不需要ANSI或TCHAR
。你有Unicode输入,STL和ShellExecuteEx()
都支持Unicode,所以只保留所有的Unicode。
您还泄露了为BSTR
分配的FeatureList
,以及HANDLE
返回的流程ShellExecuteEx()
。
尝试更像这样的东西:
template <typename Out>
void split(const std::wstring &s, wchar_t delim, Out result) {
std::wistringstream iss(s);
std::wstring item;
while (std::getline(iss, item, delim)) {
*(result++) = item;
}
}
HRESULT __stdcall SplitString(IDispatch *pAction) {
// Create a pointer to the IsSuiteExtension COM interface
CComQIPtr<ISuiteExtension2> spSuiteExtension2 = pAction;
// Turn on notifications for both the progress bar(epfProgressValid) and the ui message(epfMessageValid).
EnumProgressFlags pf = EnumProgressFlags(EnumProgressFlags::epfMessageValid | EnumProgressFlags::epfProgressValid);
CComBSTR FeatureList;
HRESULT hRet = spSuiteExtension2->get_Property(CComBSTR(L"ENABLE_FEATURES"), &FeatureList); // Get the property value and store it in the 'FeatureList' variable
std::vector<std::wstring> tokens;
split(static_cast<BSTR>(FeatureList), L';', std::back_inserter(tokens));
int numTokens = tokens.size();
for (int i = 0; i < numTokens; i++)
{
std::wstring params = L"/Online /Enable-Feature /FeatureName:" + tokens.at(i);
SHELLEXECUTEINFOW ShExecInfo = { 0 };
ShExecInfo.cbSize = sizeof(ShExecInfo);
ShExecInfo.fMask = SEE_MASK_NOCLOSEPROCESS;
ShExecInfo.lpFile = L"Dism.exe";
ShExecInfo.lpParameters = params.c_str();
ShExecInfo.lpDirectory = L"C:\\Windows\\SysNative";
ShExecInfo.nShow = SW_SHOW;
if (ShellExecuteExW(&ShExecInfo))
{
WaitForSingleObject(ShExecInfo.hProcess, INFINITE);
CloseHandle(ShExecInfo.hProcess);
}
}
//MessageBoxW(NULL, FeatureList, L"testx", MB_OK);
return ERROR_SUCCESS;
}
话虽如此,在启动EXE时,您应该直接使用CreateProcess()
代替ShellExecuteEx()
:
for (int i = 0; i < numTokens; i++)
{
std::wstring cmd = L"Dism.exe /Online /Enable-Feature /FeatureName:" + tokens.at(i);
STARTUPINFO si = {0};
PROCESS_INFORMATION pi = {0};
si.cb = sizeof(si);
si.dwFlags = STARTF_USESHOWWINDOW;
si.wShowWindow = SW_SHOW;
if (CreateProcessW(NULL, &cmd[0], NULL, NULL, FALSE, 0, NULL, L"C:\\Windows\\SysNative", &si, &pi))
{
CloseHandle(pi.hThread);
WaitForSingleObject(pi.hProcess, INFINITE);
CloseHandle(pi.hProcess);
}
}
答案 1 :(得分:1)
您好像已经改变了swprintf_s调用中参数的顺序。缓冲区大小应该在缓冲区之后和格式字符串之前。
来自MSDN:
int swprintf_s(
wchar_t *buffer,
size_t sizeOfBuffer,
const wchar_t *format,
...
);
从你的代码:
swprintf_s(buf, _T("Dism.exe /Online /Enable-Feature /FeatureName:%s"), sizeof(buf), wc);
我不确定你是如何编译的。它应该是这样的:
swprintf_s(buf, sizeof(buf), _T("Dism.exe /Online /Enable-Feature /FeatureName:%s"), wc);
UPDATE:这就是为什么用错误的顺序编译参数的原因:
除了MSDN文档中描述的swprintf_s之外,还有一个带有如下签名的模板化版本:
template <std::size_t N>
int swprintf_s(wchar_t (&Buffer)[N], const wchar_t * format, ...);
由于buf
参数确实是固定长度数组(与指向缓冲区的指针相对),因此选择此签名版本(N
从{{1}的长度推导出来}),因此buf
参数被视为与sizeof(buf)
对应的字符串,并忽略实际的字符串参数(%s
)。
您要么忽略或禁止编译器警告。遗憾的是,VC ++在这种情况下发出的(非常好的)诊断不会被视为错误:
wc