错误“访问冲突读取位置 0x00000008"在 SetWindowSubclass 中使用 msftedit.dll RichEdit 控件 [英] Error "Access violation reading location 0x00000008" with msftedit.dll RichEdit control inside SetWindowSubclass
问题描述
我在单独的子类文件中有编辑控件.开始使用 SetWindowSubclass 函数后(我是 C++ 新手,之前我使用 SetWindowLongPtr 进行子类化,它工作正常,但有人建议我开始使用 SetWindowSubclass),我遇到了这个问题:
I have edit control in separate subclass file. After getting to work SetWindowSubclass function (I am new to C++ and previously I used SetWindowLongPtr for subclassing where it worked fine but I was given advice to start using SetWindowSubclass), I got this issue:
编译程序后,应用程序绘制空窗口,该窗口立即停止响应(我必须通过任务管理器关闭它).输出窗口中的结果错误:
After compiling the program, application draws the empty window, which immediately stops responding (and I have to close it via Task Manager). The result error in Output window:
在 TaskTracklist.exe 中的 0x635F3DEF (msftedit.dll) 处抛出异常:0xC0000005:访问冲突读取位置0x00000008.
Exception thrown at 0x635F3DEF (msftedit.dll) in TaskTracklist.exe: 0xC0000005: Access violation reading location 0x00000008.
完整代码:
#include "stdafx.h"
#include <windows.h>
#include <commctrl.h>
#include <richedit.h>
#include <string.h>
#include "SearchEditBox.h"
/*global vars*/
LPCWSTR SearchEditBox::editBoxDefText = L"Search...";
bool SearchEditBox::firstLoad = false;
int SearchEditBox::width = 0;
int SearchEditBox::height = 0;
HWND SearchEditBox::editBox;
/*functions*/
LRESULT CALLBACK EditBoxProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam, UINT_PTR uint_ptr, DWORD dwRefData);
void ChangeEdit(const HWND hwnd, const bool change);
/*set-get functions*/
HWND SearchEditBox::getEditBox()
{
return SearchEditBox::editBox;
}
SearchEditBox * SearchEditBox::CreateEditBox(HINSTANCE hInst, HWND hwnd, int pos_x, int pos_y, int width, int height) {
SearchEditBox * p_SearchEditBox = new SearchEditBox;
LoadLibrary(TEXT("Msftedit.dll")); //enables RichEdit field
SearchEditBox::editBox = CreateWindowEx(0, (L"RICHEDIT50W"), editBoxDefText, WS_VISIBLE | WS_CHILD, pos_x + 6, pos_y + 4, width, height, hwnd, NULL, (HINSTANCE)GetWindowLong(hwnd, GWL_HINSTANCE), p_SearchEditBox);
SearchEditBox::width = width;
SearchEditBox::height = height;
if (SearchEditBox::editBox == NULL)
{
delete p_SearchEditBox;
MessageBox(NULL, L"Problem creating the Search box.", L"Error", 0);
return 0;
}
SetWindowSubclass(SearchEditBox::editBox, SearchEditBox::EditBoxProc, 0, 0);
return p_SearchEditBox;
}
LRESULT CALLBACK SearchEditBox::EditBoxProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam, UINT_PTR uIdSubclass, DWORD dwRefData)
{
PAINTSTRUCT ps;
HDC hdc;
switch (uMsg)
{
case WM_SETFOCUS:
{
LPWSTR getText = new TCHAR[10];
GetWindowText(hwnd, getText, 10);
if (_tcscmp(getText, editBoxDefText) == 0)
{
SearchEditBox::ChangeEdit(hwnd, 1);
}
delete getText;
break;
}
case WM_KILLFOCUS:
{
LPWSTR getText = new TCHAR[10];
if (GetWindowText(hwnd, getText, 10) == 0)
{
SearchEditBox::ChangeEdit(hwnd, 0);
}
::SetFocus(NULL);
delete getText;
break;
}
case WM_LBUTTONDBLCLK:
SearchEditBox::ChangeEdit(hwnd, 1);
break;
case WM_PAINT:
{
hdc = BeginPaint(hwnd, &ps);
RECT rc;
InvalidateRect(hwnd, &rc, 0);
if (SearchEditBox::firstLoad == false)
{
SearchEditBox::ChangeEdit(hwnd, 0);
::SetFocus(NULL);
SearchEditBox::firstLoad = true;
}
HBRUSH hBrush = CreateSolidBrush(RGB(33, 33, 33));
SelectObject(hdc, hBrush);
RoundRect(hdc, -6, -4, SearchEditBox::width + 7, SearchEditBox::height + 4, 5, 5);
EndPaint(hwnd, &ps);
break;
}
}
return DefSubclassProc(hwnd, uMsg, lParam, wParam);
}
我很清楚问题出在带有 SetWindowSubclass 函数的 RichEdit 控件上.
It is clear to me that the problem is with RichEdit control on line with SetWindowSubclass function.
尽管我没有找到任何与 Msftedit.dll 相关的错误相关的主题,但我从这些文章中了解到(此处 和此处 和此处) 我可能会引用 NULL 指针,但这对我来说没有意义,因为那样我会从 SetWindowSubclass 函数上方的这个位得到错误(我没有):
Even though I did not find any topic related specifically to this error in connection to Msftedit.dll, I understood from these articles (here and here and here) that I may be referencing to NULL pointer, but that does not make sense to me because then I would get error from this bit just above SetWindowSubclass function (which I don't):
if (SearchEditBox::editBox == NULL)
{
delete p_SearchEditBox;
MessageBox(NULL, L"Problem creating the Search box.", L"Error", 0);
return 0;
}
我还认为问题可能出在外部函数(意思是在 comctl32 中定义的函数而不是在类内部)访问类特定变量(指针不是为 NULL,但它可能无法访问)以某种方式添加到函数中)所以我尝试仅为 SetWindowSubclass 函数创建局部变量(这也不起作用):
I also thought the problem may be with external function (meaning function defined in comctl32 and not inside class) accessing class specific variable (the pointer would not be NULL, but it just may not be accessible to the function somehow) so I tried creating local variable just for the SetWindowSubclass function (which did not work either):
HWND newHWND = SearchEditBox::editBox;
SetWindowSubclass(newHWND, SearchEditBox::EditBoxProc, 0, 0);
使用函数 getEditBox() 也没有解决这个问题.
Using function getEditBox() did not solve that problem either.
我还尝试在控件声明中使用 MSFTEDIT_CLASS 而不是 (L"RICHEDIT50W")(认为问题可能出在控件本身内部),但这也无济于事,尝试不同的版本(例如 RICHEDIT51W 或 RICHEDIT80W)导致错误(因此我必须使用适用于 VS2015 的正确 RichEdit 版本).
I also tried using MSFTEDIT_CLASS instead of (L"RICHEDIT50W") in control declaration (thinking the problem may be inside the control itself) but that did not help either, and trying different versions (for example RICHEDIT51W or RICHEDIT80W) resulted in errors (so I must be working with the correct RichEdit version for VS2015).
我也尝试在 CreateEditBox 中声明 HWND editBox(使其成为局部变量),但这也无济于事.
I also tried declaring HWND editBox inside CreateEditBox (making it local variable), but that did not help either.
我使用 VS 的免费社区版.
I use free Community version of VS.
从代码中清除了我未成功尝试的一些剩余部分.
cleared some remains of my unsuccessful tries from the code.
推荐答案
在 TaskTracklist.exe 中的 0x635F3DEF (msftedit.dll) 处引发异常:0xC0000005:读取位置 0x00000008 的访问冲突.
Exception thrown at 0x635F3DEF (msftedit.dll) in TaskTracklist.exe: 0xC0000005: Access violation reading location 0x00000008.
地址 0 附近的访问冲突通常意味着正在通过 NULL 对象指针访问类/记录数据成员.
An Access Violation near address 0 usually means that a class/record data member is being accessed via a NULL object pointer.
尽管我没有找到任何与 Msftedit.dll 相关的错误特别相关的主题,但我从这些文章中了解到 (...) 我可能引用了 NULL 指针,但这对我来说没有意义因为那样我会从 SetWindowSubclass 函数上方的这个位得到错误(我没有)
Even though I did not find any topic related specifically to this error in connection to Msftedit.dll, I understood from these articles (...) that I may be referencing to NULL pointer, but that does not make sense to me because then I would get error from this bit just above SetWindowSubclass function (which I don't)
问题与访问 NULL HWND
句柄无关.它与访问 NULL 对象指针有关.而且您的代码中确实有对象指针,因此您需要确定哪个是 NULL.当 AccessViolation 发生时,使用调试器查看在内存地址 0x635F3DEF 处运行的代码,这应该会引导您找到代码中的哪一行崩溃.
The problem is not related to accessing a NULL HWND
handle. It is related to accessing a NULL object pointer instead. And you do have object pointers in your code, so you need to figure out which one is NULL. When the AccessViolation happens, use the debugger to look at the code that is running at memory address 0x635F3DEF, that should lead you to which line in your code is crashing.
话虽如此,EditBoxProc()
的最后一个参数需要是 DWORD_PTR
而不是 DWORD
,并且您正在传递wParam
和 lParam
值到 DefSubclassProc()
的顺序错误.
With that said, the last parameter of EditBoxProc()
needs to be a DWORD_PTR
instead of a DWORD
, and you are passing the wParam
and lParam
values to DefSubclassProc()
in the wrong order.
此外,您的 WM_KILLFOCUS
和 WM_PAINT
处理程序不应调用 SetFocus()
和您的 WM_PAINT
处理程序不应该调用 InvalidateRect()
.
Also, your WM_KILLFOCUS
and WM_PAINT
handlers should not be calling SetFocus()
, and your WM_PAINT
handler should not be calling InvalidateRect()
.
我建议您重新编写 SearchEditBox
类,使其数据成员不再是 static
.在类中将它们设为 static
可防止您使用单独的 HWND
创建多个 SearchEditBox
对象.数据成员不必是static
.您可以将 SearchEditBox*
指针作为子类的 dwRefData
参数传递,以便 EditBoxProc()
可以访问 SearchEditBox
> 对象及其非静态成员.
I suggest you re-write your SearchEditBox
class so that its data members are not static
anymore. Making them static
in the class prevents you from creating multiple SearchEditBox
objects with individual HWND
s. The data members do not need to be static
. You can pass the SearchEditBox*
pointer as the dwRefData
parameter of the subclass so EditBoxProc()
has access to the SearchEditBox
object and its non-static members.
尝试更像这样的事情:
SearchEditBox.h
SearchEditBox.h
#ifndef SearchEditBoxH
#define SearchEditBoxH
class SearchEditBox
{
private:
bool firstPaint;
int width;
int height;
HWND editBox;
SearchEditBox();
void ChangeEdit(const bool change);
static LRESULT CALLBACK EditBoxProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam, UINT_PTR uint_ptr, DWORD_PTR dwRefData);
public:
~SearchEditBox();
HWND getEditBox()
static SearchEditBox* CreateEditBox(HINSTANCE hInst, HWND hwnd, int pos_x, int pos_y, int width, int height);
};
#endif
SearchEditBox.cpp
SearchEditBox.cpp
#include "stdafx.h"
#include <windows.h>
#include <commctrl.h>
#include <richedit.h>
#include <string.h>
#include "SearchEditBox.h"
/*global vars*/
static LPCTSTR editBoxDefText = TEXT("Search...");
SearchEditBox::SearchEditBox()
{
firstPaint = false;
width = 0;
height = 0;
editBox = NULL;
}
SearchEditBox::~SearchEditBox()
{
if (editBox)
DestroyWindow(editBox);
}
void SearchEditBox::ChangeEdit(const bool change)
{
//...
}
HWND SearchEditBox::getEditBox()
{
return editBox;
}
SearchEditBox* SearchEditBox::CreateEditBox(HINSTANCE hInst, HWND hwnd, int pos_x, int pos_y, int width, int height)
{
// make sure RichEdit 4.1 is enabled
if (!GetModuleHandle(TEXT("Msftedit.dll")))
{
if (!LoadLibrary(TEXT("Msftedit.dll")))
{
MessageBox(NULL, L"Problem loading Msftedit.dll.", L"Error", 0);
return 0;
}
}
SearchEditBox *pSearchEditBox = new SearchEditBox;
pSearchEditBox->editBox = CreateWindowEx(0, MSFTEDIT_CLASS, editBoxDefText, WS_VISIBLE | WS_CHILD, pos_x + 6, pos_y + 4, width, height, hwnd, NULL, (HINSTANCE) GetWindowLong(hwnd, GWL_HINSTANCE), p_SearchEditBox);
if (!pSearchEditBox->editBox)
{
delete pSearchEditBox;
MessageBox(NULL, L"Problem creating the Search box.", L"Error", 0);
return 0;
}
if (!SetWindowSubclass(pSearchEditBox->editBox, SearchEditBox::EditBoxProc, 0, (DWORD_PTR)p_SearchEditBox))
{
delete pSearchEditBox;
MessageBox(NULL, L"Problem subclassing the Search box.", L"Error", 0);
return 0;
}
pSearchEditBox->width = width;
pSearchEditBox->height = height;
return pSearchEditBox;
}
LRESULT CALLBACK SearchEditBox::EditBoxProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam, UINT_PTR uIdSubclass, DWORD_PTR dwRefData)
{
SearchEditBox *pSearchEditBox = (SearchEditBox*) dwRefData;
switch (uMsg)
{
case WM_NCDESTROY:
RemoveWindowSubclass(hwnd, SearchEditBox::EditBoxProc, uIdSubclass);
pSearchEditBox->editBox = NULL;
break;
case WM_SIZE:
pSearchEditBox->width = LOWORD(lParam);
pSearchEditBox->height = HIWORD(lParam);
break;
case WM_SETFOCUS:
{
TCHAR getText[10];
GetWindowText(hwnd, getText, 10);
if (_tcscmp(getText, editBoxDefText) == 0)
pSearchEditBox->ChangeEdit(true);
break;
}
case WM_KILLFOCUS:
{
TCHAR getText[10];
if (GetWindowText(hwnd, getText, 10) == 0)
pSearchEditBox->ChangeEdit(false);
break;
}
case WM_LBUTTONDBLCLK:
pSearchEditBox->ChangeEdit(true);
break;
case WM_PAINT:
{
if (!pSearchEditBox->firstPaint)
{
pSearchEditBox->firstPaint = true;
pSearchEditBox->ChangeEdit(false);
}
PAINTSTRUCT ps;
HDC hdc = BeginPaint(hwnd, &ps);
HBRUSH hBrush = CreateSolidBrush(RGB(33, 33, 33));
SelectObject(hdc, hBrush);
RoundRect(hdc, -6, -4, pSearchEditBox->width + 7, pSearchEditBox->height + 4, 5, 5);
EndPaint(hwnd, &ps);
break;
}
}
return DefSubclassProc(hwnd, uMsg, wParam, lParam);
}
这篇关于错误“访问冲突读取位置 0x00000008"在 SetWindowSubclass 中使用 msftedit.dll RichEdit 控件的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!