相同的C++代码有时也能工作,有时也不行。 我的C++代码工作了几次,执行很少,它突然停止工作,抛出异常,没有任何改变!我不知道为什么
这是代码中有问题的部分:相同的C++代码有时也能工作,有时也不行。 我的C++代码工作了几次,执行很少,它突然停止工作,抛出异常,没有任何改变!我不知道为什么,c++,winapi,C++,Winapi,这是代码中有问题的部分: STARTUPINFO si; PROCESS_INFORMATION pi; ZeroMemory(&si, sizeof(si)); si.cb = sizeof(si); ZeroMemory(&pi, sizeof(pi)); TCHAR *path; SHGetKnownFolderPath(FOLDERID_Startup, KF_FLAG_CREATE, NULL, &path); lstrcat(path, L"\\calc.ex
STARTUPINFO si;
PROCESS_INFORMATION pi;
ZeroMemory(&si, sizeof(si));
si.cb = sizeof(si);
ZeroMemory(&pi, sizeof(pi));
TCHAR *path;
SHGetKnownFolderPath(FOLDERID_Startup, KF_FLAG_CREATE, NULL, &path);
lstrcat(path, L"\\calc.exe");
if (CreateProcess(NULL, path, NULL, NULL, TRUE, 0, NULL, NULL, &si, &pi))
{
WaitForSingleObject(pi.hProcess, INFINITE);
CloseHandle(pi.hProcess);
CloseHandle(pi.hThread);
}
执行几次之后,CreateProcess行上会抛出两个异常,第一个异常:
Unhandled exception at 0x779D8829 (ntdll.dll) in PS_Down.exe: 0xC0000374: A heap has been corrupted (parameters: 0x77A15890).
第二点:
Exception thrown at 0x77946111 (ntdll.dll) in PS_Down.exe: 0xC0000005: Access violation reading location 0x00000069.
这发生在我的一些其他项目中,这些项目不包括CreateProcess func,iv'e注意到,当涉及TCHAR和SHGetKnownFolderPath时,总是会发生这种情况。
如果您能帮助您了解如何解决此问题,我们将不胜感激,提前感谢
p.S-我不熟悉cpp编码,因此请尝试相应地解释lstrcatpath,L\\calc.exe;将导致缓冲区溢出。path是指向数组的指针,该数组只能包含文件夹路径,仅此而已。您需要分配一个宽字符串,附加文件夹路径,然后是文件路径。此外,您还需要检查SHGetKnownFolderPath的结果,以确定该路径是否包含有效指针,然后通过调用CoTaskMemFree释放它。lstrcatpath,L\\calc.exe;将导致缓冲区溢出。path是指向数组的指针,该数组只能包含文件夹路径,仅此而已。您需要分配一个宽字符串,附加文件夹路径,然后是文件路径。您还需要检查SHGetKnownFolderPath的结果,以确定该路径是否包含有效指针,然后通过调用CoTaskMemFree释放它。SHGetKnownFolderPath为路径分配了固定长度,因此您无法将可执行文件直接连接到该路径。首先需要使用CoTaskMemRealloc来扩展空间。您还需要在使用完内存后释放内存。类似地,您需要关闭CreateProcess创建的句柄
因此,您可以创建支持类来自动处理资源:
#include "pch.h"
#include <iostream>
#include <windows.h>
#include <Shlobj.h>
#include <wchar.h>
// A wide string exception class. perhaps something like this already exist in VS?
class werror {
std::wstring text;
public:
werror(const wchar_t* Text) : text(Text) {}
const wchar_t* what() const { return text.c_str(); }
};
class ConCatToKnownFolderPath {
PWSTR m_path;
public:
ConCatToKnownFolderPath(REFKNOWNFOLDERID rfid, DWORD dwFlags, HANDLE hToken, const WCHAR* AddToPath = nullptr) :
m_path(nullptr)
{
if (SHGetKnownFolderPath(rfid, dwFlags, hToken, &m_path) != S_OK)
throw werror(L"SHGetKnownFolderPath failed");
if (AddToPath) {
size_t newlen = wcslen(m_path) + wcslen(AddToPath) + sizeof(WCHAR); // place for \0
size_t newbufsize = newlen * sizeof(WCHAR);
auto newPtr = CoTaskMemRealloc(m_path, newbufsize);
if (!newPtr) {
CoTaskMemFree(m_path);
throw werror(L"CoTaskMemRealloc failed");
}
m_path = reinterpret_cast<PWSTR>(newPtr);
wcscat_s(m_path, newlen, AddToPath);
}
}
// move works fine
ConCatToKnownFolderPath(ConCatToKnownFolderPath&& other) noexcept :
m_path(other.m_path)
{
other.m_path = nullptr;
}
ConCatToKnownFolderPath& operator=(ConCatToKnownFolderPath&& other) noexcept {
if (m_path) CoTaskMemFree(m_path);
m_path = other.m_path;
other.m_path = nullptr;
return *this;
}
// copy not supported (but could easily be added
ConCatToKnownFolderPath(const ConCatToKnownFolderPath&) = delete;
ConCatToKnownFolderPath& operator=(const ConCatToKnownFolderPath&) = delete;
// automatic free when it goes out of scope
~ConCatToKnownFolderPath() {
if (m_path) CoTaskMemFree(m_path);
}
PWSTR data() const { return m_path; }
operator LPCWSTR () const { return m_path; }
};
struct WProcessWithInfo : PROCESS_INFORMATION {
WProcessWithInfo(LPCWSTR lpApplicationName, LPWSTR lpCommandLine, LPCWSTR lpCurrentDirectory) {
STARTUPINFOW si;
ZeroMemory(&si, sizeof(STARTUPINFOW));
si.cb = sizeof(si);
si.dwFlags = STARTF_USESHOWWINDOW;
si.wShowWindow = SW_SHOWNORMAL;
if (!CreateProcessW(lpApplicationName, lpCommandLine, NULL, NULL, FALSE, 0, NULL, lpCurrentDirectory, &si, *this))
throw werror(L"CreateProcessWCreateProcessW failed");
CloseHandle(hThread);
}
WProcessWithInfo(const WProcessWithInfo&) = delete;
WProcessWithInfo(WProcessWithInfo&&) = delete;
WProcessWithInfo& operator=(const WProcessWithInfo&) = delete;
WProcessWithInfo& operator=(WProcessWithInfo&&) = delete;
~WProcessWithInfo() {
CloseHandle(hProcess);
}
DWORD Wait(DWORD dwMilliseconds=INFINITE) {
return WaitForSingleObject(*this, dwMilliseconds);
}
operator HANDLE () { return hProcess; }
operator LPPROCESS_INFORMATION () { return this; }
};
int main() {
try {
ConCatToKnownFolderPath path(FOLDERID_System, KF_FLAG_CREATE, NULL, L"\\calc.exe");
std::wcout << L"Starting " << path.data() << L"\n";
WProcessWithInfo proc(path, NULL, NULL);
std::wcout << L"Process started\n";
proc.Wait();
std::wcout << L"Process done\n";
}
catch (const werror& ex) {
std::wcerr << L"Exception: " << ex.what() << L"\n";
}
return 0;
}
SHGetKnownFolderPath为路径分配了固定长度,因此您无法将可执行文件直接连接到该路径。首先需要使用CoTaskMemRealloc来扩展空间。您还需要在使用完内存后释放内存。类似地,您需要关闭CreateProcess创建的句柄
因此,您可以创建支持类来自动处理资源:
#include "pch.h"
#include <iostream>
#include <windows.h>
#include <Shlobj.h>
#include <wchar.h>
// A wide string exception class. perhaps something like this already exist in VS?
class werror {
std::wstring text;
public:
werror(const wchar_t* Text) : text(Text) {}
const wchar_t* what() const { return text.c_str(); }
};
class ConCatToKnownFolderPath {
PWSTR m_path;
public:
ConCatToKnownFolderPath(REFKNOWNFOLDERID rfid, DWORD dwFlags, HANDLE hToken, const WCHAR* AddToPath = nullptr) :
m_path(nullptr)
{
if (SHGetKnownFolderPath(rfid, dwFlags, hToken, &m_path) != S_OK)
throw werror(L"SHGetKnownFolderPath failed");
if (AddToPath) {
size_t newlen = wcslen(m_path) + wcslen(AddToPath) + sizeof(WCHAR); // place for \0
size_t newbufsize = newlen * sizeof(WCHAR);
auto newPtr = CoTaskMemRealloc(m_path, newbufsize);
if (!newPtr) {
CoTaskMemFree(m_path);
throw werror(L"CoTaskMemRealloc failed");
}
m_path = reinterpret_cast<PWSTR>(newPtr);
wcscat_s(m_path, newlen, AddToPath);
}
}
// move works fine
ConCatToKnownFolderPath(ConCatToKnownFolderPath&& other) noexcept :
m_path(other.m_path)
{
other.m_path = nullptr;
}
ConCatToKnownFolderPath& operator=(ConCatToKnownFolderPath&& other) noexcept {
if (m_path) CoTaskMemFree(m_path);
m_path = other.m_path;
other.m_path = nullptr;
return *this;
}
// copy not supported (but could easily be added
ConCatToKnownFolderPath(const ConCatToKnownFolderPath&) = delete;
ConCatToKnownFolderPath& operator=(const ConCatToKnownFolderPath&) = delete;
// automatic free when it goes out of scope
~ConCatToKnownFolderPath() {
if (m_path) CoTaskMemFree(m_path);
}
PWSTR data() const { return m_path; }
operator LPCWSTR () const { return m_path; }
};
struct WProcessWithInfo : PROCESS_INFORMATION {
WProcessWithInfo(LPCWSTR lpApplicationName, LPWSTR lpCommandLine, LPCWSTR lpCurrentDirectory) {
STARTUPINFOW si;
ZeroMemory(&si, sizeof(STARTUPINFOW));
si.cb = sizeof(si);
si.dwFlags = STARTF_USESHOWWINDOW;
si.wShowWindow = SW_SHOWNORMAL;
if (!CreateProcessW(lpApplicationName, lpCommandLine, NULL, NULL, FALSE, 0, NULL, lpCurrentDirectory, &si, *this))
throw werror(L"CreateProcessWCreateProcessW failed");
CloseHandle(hThread);
}
WProcessWithInfo(const WProcessWithInfo&) = delete;
WProcessWithInfo(WProcessWithInfo&&) = delete;
WProcessWithInfo& operator=(const WProcessWithInfo&) = delete;
WProcessWithInfo& operator=(WProcessWithInfo&&) = delete;
~WProcessWithInfo() {
CloseHandle(hProcess);
}
DWORD Wait(DWORD dwMilliseconds=INFINITE) {
return WaitForSingleObject(*this, dwMilliseconds);
}
operator HANDLE () { return hProcess; }
operator LPPROCESS_INFORMATION () { return this; }
};
int main() {
try {
ConCatToKnownFolderPath path(FOLDERID_System, KF_FLAG_CREATE, NULL, L"\\calc.exe");
std::wcout << L"Starting " << path.data() << L"\n";
WProcessWithInfo proc(path, NULL, NULL);
std::wcout << L"Process started\n";
proc.Wait();
std::wcout << L"Process done\n";
}
catch (const werror& ex) {
std::wcerr << L"Exception: " << ex.what() << L"\n";
}
return 0;
}
这是一个未定义行为的教科书案例。因为问题可能出在其他地方,所以要做出决定。您还需要检查当前未检查的地方是否存在错误。e、 如何知道路径有效?SHGetKnownFolderPath如何处理&path参数?传入空ptr时是否保留内存;如果参数不为NULL,它会使用它作为缓冲区吗?这是一个未定义行为的教科书案例。因为问题可能出在其他地方,所以要做出决定。您还需要检查当前未检查的地方是否存在错误。e、 如何知道路径有效?SHGetKnownFolderPath如何处理&path参数?传入空ptr时是否保留内存;如果参数不为NULL,它会使用它作为缓冲区吗?谢谢你的回答,但是你介意在我使用完它后,再详细说明一下如何生成完整字符串和释放路径的内存吗?@Apex类似::std::wstring full_path{};full_path.appendpath;完整路径append\\calc.exe;和::CoTaskMemFreepath@apexOr更简单:std::wstring full_path{path};完整路径。append\\calc.exe;::CoTaskMemFreepath@VTT当我这样做并在CreateProcess func中将path更改为full_path时,我得到一个错误:不存在从'std::wstring'到'LPWSTR'的适当转换,如何在func中包含full_path?@Jabberwocky谢谢,你知道如何解决我在执行此操作后遇到的问题吗?谢谢你的回答,但是,当我处理完完整字符串和空闲路径时,您是否介意详细说明一下如何生成完整字符串和空闲路径的内存?@Apex类似::std::wstring full_path{};full_path.appendpath;完整路径append\\calc.exe;和::CoTaskMemFreepath@apexOr更简单:std::wstring full_path{path};完整路径。append\\calc.exe;::CoTaskMemFreepath@VTT当我这样做并在CreateProcess func中将path更改为full_path时,我得到一个错误:不存在从'std::wstring'到'LPWSTR'的适当转换,我如何在func中包含full_path?@Jabberwocky谢谢,你知道如何解决我执行此操作后遇到的问题吗?现在它正在工作。我有一只愚蠢的虫子。请注意,我已经将路径作为CreateProcessW的第一个参数,以避免必须围绕程序开始…是的,计算器对我来说启动很好。我改为FOLDERID_系统,但您最初使用FOLDERID_启动。你们试过改变它吗?是的,我注意到并改变了它,但计算器仍然不能为我启动。然而,我注意到,如果我改为使用CLI exe,它在主控制台OK下工作正常,它会写异常吗?我已经更新了上面的代码以打印出异常,这样你就可以看到它失败的地方。是的,它与notepad.exe一起工作很好,那么calc.exe是问题所在吗?现在它工作了。我得了一个sil
小虫子。请注意,我已经将路径作为CreateProcessW的第一个参数,以避免必须围绕程序开始…是的,计算器对我来说启动很好。我改为FOLDERID_系统,但您最初使用FOLDERID_启动。你们试过改变它吗?是的,我注意到并改变了它,但计算器仍然不能为我启动。然而,我注意到,如果我改为使用CLI exe,它在主控制台OK下工作正常,它会写异常吗?我已经更新了上面的代码以打印出异常,这样您就可以看到它失败的地方。是的,它与notepad.exe一起工作很好,那么calc.exe是问题所在吗?