错误“访问冲突读取位置 0x00000008"在 SetWindowSubclass 中使用 msftedit.dll RichEdit 控件 [英] Error "Access violation reading location 0x00000008" with msftedit.dll RichEdit control inside SetWindowSubclass

查看:26
本文介绍了错误“访问冲突读取位置 0x00000008"在 SetWindowSubclass 中使用 msftedit.dll RichEdit 控件的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我在单独的子类文件中有编辑控件.开始使用 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,并且您正在传递wParamlParam 值到 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_KILLFOCUSWM_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 HWNDs. 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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆