मैं विंडोज एपीआई के लिए माइक्रोसॉफ्ट डॉक्स का पालन कर रहा हूं। मैं वर्तमान में अध्याय 4 पर हूं और एक अंडाकार खींचने की कोशिश कर रहा हूं। m_pRenderTarget को App.h वर्ग में घोषित किया गया है। फ़ंक्शन OnRender(HWND hwnd) में मैं इसका उपयोग ज्यामिति (दीर्घवृत्त) बनाने के लिए करने का प्रयास कर रहा हूं। हालांकि, मुझे निम्न त्रुटि मिल रही है:

अपवाद फेंका गया: पहुंच उल्लंघन पढ़ें। यह->m_pRenderTarget 0x38 था।

कुछ डिबगिंग के बाद, मैंने देखा कि HRESULT App::CreateDeviceResources(HWND hwnd) फ़ंक्शन में, m_pRenderTarget किसी कारण से NULL नहीं था, भले ही मैंने इसे इस तरह से प्रारंभ किया था और अभी तक इसे नहीं बदला था (मुझे नहीं लगता कम से कम ) मेरा अनुमान है कि यही समस्या है। संदर्भ के लिए, यहाँ प्रासंगिक कोड है:

#pragma once
#define MAX_LOADSTRING 100
#include "resource.h"
#include "pch.h"

class App
{
public:
    App();
    ~App();

    bool Init(HINSTANCE instance, int cmd);
    int RunMessageLoop();
    HINSTANCE getInstance() { return hInstance; }
private:
    HINSTANCE hInstance;
    TCHAR szTitle[MAX_LOADSTRING];
    TCHAR szWindowClass[MAX_LOADSTRING];

    ID2D1Factory* m_pD2DFactory; 
    ID2D1EllipseGeometry* m_pEllipseGeometry;
    ID2D1HwndRenderTarget* m_pRenderTarget;
    ID2D1SolidColorBrush* m_pBlackBrush;

    ATOM RegisterClass();
    BOOL InitInstance(int);
    static LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam);
    static INT_PTR CALLBACK About(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam);
    
    HRESULT CreateDeviceIndependentResources();
    HRESULT CreateDeviceResources(HWND hwnd);
    HRESULT OnRender(HWND hwnd);
};

यहाँ कार्यान्वयन हैं:

#include "pch.h"
#include "App.h"


App::App()
    : m_pRenderTarget(NULL)
{}
App::~App(){}

bool App::Init(HINSTANCE instance, int cmd)
{
    hInstance = instance;
    LoadString(hInstance, IDS_APP_TITLE, szTitle, MAX_LOADSTRING);
    LoadString(hInstance, IDC_PRACTICE, szWindowClass, MAX_LOADSTRING);

    RegisterClass();
    if (!InitInstance(cmd))
        return false;

    return true;
}

int App::RunMessageLoop()
{
    HACCEL hAccelTable;
    hAccelTable = LoadAccelerators(hInstance, MAKEINTRESOURCE(IDC_PRACTICE));

    MSG msg;
    while (GetMessage(&msg, NULL, 0, 0))
    {
        if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg))
        {
            TranslateMessage(&msg);
            DispatchMessage(&msg);
        }
    }
    return (int)msg.wParam;
}


//
//  FUNCTION: MyRegisterClass()
//
//  PURPOSE: Registers the window class.
//
ATOM App::RegisterClass()
{
    WNDCLASSEXW wcex;

    wcex.cbSize = sizeof(WNDCLASSEX);

    wcex.style = CS_HREDRAW | CS_VREDRAW;
    wcex.lpfnWndProc = WndProc;
    wcex.cbClsExtra = 0;
    wcex.cbWndExtra = 0;
    wcex.hInstance = hInstance;
    wcex.hIcon = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_PRACTICE));
    wcex.hCursor = LoadCursor(nullptr, IDC_ARROW);
    wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
    wcex.lpszMenuName = MAKEINTRESOURCEW(IDC_PRACTICE);
    wcex.lpszClassName = szWindowClass;
    wcex.hIconSm = LoadIcon(wcex.hInstance, MAKEINTRESOURCE(IDI_SMALL));

    return RegisterClassExW(&wcex);
}


BOOL App::InitInstance(int nCmdShow)
{
    HRESULT hr = CreateDeviceIndependentResources();
    if FAILED(hr) 
    {
        return FALSE;
    }

    HWND hWnd;

    hWnd = CreateWindow(szWindowClass, szTitle, WS_OVERLAPPEDWINDOW, CW_USEDEFAULT,
        CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, 0, NULL, NULL, hInstance, this);


    if (!hWnd)
    {
        return FALSE;
    }

    ShowWindow(hWnd, nCmdShow);
    UpdateWindow(hWnd);

    return TRUE;
}

//
//  FUNCTION: WndProc(HWND, UINT, WPARAM, LPARAM)
//
//  PURPOSE: Processes messages for the main window.
//
//  WM_COMMAND  - process the application menu
//  WM_PAINT    - Paint the main window
//  WM_DESTROY  - post a quit message and return
//
//

LRESULT CALLBACK App::WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
    App* pApp; 
    if (message == WM_CREATE) 
    {
        LPCREATESTRUCT pcs = (LPCREATESTRUCT)lParam;
        pApp = (App*)pcs->lpCreateParams; 
        ::SetWindowLongPtrW(hWnd, GWLP_USERDATA, PtrToUlong(pApp));
        return TRUE;
    }
    else
    {
        pApp = reinterpret_cast<App*>(static_cast<LONG_PTR>(::GetWindowLongPtrW(hWnd, GWLP_USERDATA)));
        if (!pApp)
            return DefWindowProc(hWnd, message, wParam, lParam); 
    }

    int wmld, wmEvent;
    PAINTSTRUCT ps;
    HDC hdc;

    switch (message)
    {
    case WM_COMMAND:
    {
        int wmId = LOWORD(wParam);
        // Parse the menu selections:
        switch (wmId)
        {
        case IDM_ABOUT: 
            DialogBox(NULL, MAKEINTRESOURCE(IDD_ABOUTBOX), hWnd, pApp->About);
            break;
        case IDM_EXIT:
            DestroyWindow(hWnd);
            break;
        default:
            return DefWindowProc(hWnd, message, wParam, lParam);
        }
    }
    break;
    case WM_PAINT:
    {
        hdc = BeginPaint(hWnd, &ps);
        pApp->OnRender(hWnd);
        EndPaint(hWnd, &ps);
        break;
    }
    break;
    case WM_DESTROY:
        PostQuitMessage(0);
        break;
    default:
        return DefWindowProc(hWnd, message, wParam, lParam);
    }
    return 0;
}

// Message handler for about box.
INT_PTR CALLBACK App::About(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam) 
{
    UNREFERENCED_PARAMETER(lParam); 
    switch (message) 
    {
        case WM_INITDIALOG: 
            return (INT_PTR)TRUE;

        case WM_COMMAND: 
            if (LOWORD(wParam) == IDOK || LOWORD(wParam) == IDCANCEL)
            {
                EndDialog(hDlg, LOWORD(wParam));
                return (INT_PTR)TRUE; 
            } 
            break; 
    } 
        return (INT_PTR)FALSE;
}

HRESULT App::CreateDeviceIndependentResources() 
{
    HRESULT hr; 
    // Create a Direct2D factory 
    hr = D2D1CreateFactory(D2D1_FACTORY_TYPE_SINGLE_THREADED, &m_pD2DFactory); 
    if (SUCCEEDED(hr))
    {
        // Create an ellipse geometry
        const D2D1_ELLIPSE ellipse = D2D1::Ellipse(D2D1::Point2F(105.0f, 105.0f), 25.0f, 25.0f); 
        hr = m_pD2DFactory->CreateEllipseGeometry(ellipse, &m_pEllipseGeometry); 
    }
    return hr;
}

HRESULT App::CreateDeviceResources(HWND hwnd) 
{
    //Notice that this causes HERE to be printed out, indicating that m_pRenderTarget != NULL
    if (m_pRenderTarget != NULL)
        OutputDebugStringA("\nHERE\n");
    else
        OutputDebugStringA("\nTHERE\n");

    HRESULT hr = S_OK; 
    if (!m_pRenderTarget) {
        
        RECT rc;
        GetClientRect(hwnd, &rc); 
        D2D1_SIZE_U size = D2D1::SizeU(rc.right - rc.left, rc.bottom - rc.top); 
        // Create a Direct2D render target 
        hr = m_pD2DFactory->CreateHwndRenderTarget( D2D1::RenderTargetProperties(), D2D1::HwndRenderTargetProperties(hwnd, size), &m_pRenderTarget ); 
        if (SUCCEEDED(hr)) 
        { // Create a black brush
            hr = m_pRenderTarget->CreateSolidColorBrush( D2D1::ColorF(D2D1::ColorF::Black), &m_pBlackBrush ); 
        }
    }

    return hr; 
}

HRESULT App::OnRender(HWND hwnd) 
{ 
    HRESULT hr;

    hr = CreateDeviceResources(hwnd); 
    if (SUCCEEDED(hr)) 
    { 
        if (!(m_pRenderTarget->CheckWindowState() & D2D1_WINDOW_STATE_OCCLUDED)) 
        {

            m_pRenderTarget->BeginDraw(); 
            m_pRenderTarget->Clear(D2D1::ColorF(D2D1::ColorF::White));
            m_pRenderTarget->FillGeometry(m_pEllipseGeometry, m_pBlackBrush); 
            hr = m_pRenderTarget->EndDraw(); 
            if (hr == D2DERR_RECREATE_TARGET) 
            {
                hr = S_OK; 
                m_pRenderTarget->Release();
                m_pRenderTarget = NULL;
                m_pBlackBrush->Release(); 
                m_pBlackBrush = NULL; 
            }
        }
    }
    return hr;
}

मैं जिस कोड की पेशकश कर रहा हूं उसके लिए मैं क्षमा चाहता हूं। मैं समस्या के बारे में पूरी तरह से भ्रमित हूं क्योंकि मैंने सोचा था कि मैं वही कर रहा हूं जो दस्तावेज़ों में लिखा गया था। मुझे लगता है कि मैंने ट्रांसक्रिप्शन में गलती की होगी। आप की हर मदद जो आप सकते हैं उसके के लिए धन्यवाद।

-1
john doe 25 नवम्बर 2020, 05:59

2 जवाब

सबसे बढ़िया उत्तर

इसका कारण यह है कि आपने CreateWindow फ़ंक्शन का उपयोग करते समय एक अतिरिक्त पैरामीटर लिखा था, जिसके कारण hInstance को lpCreateParams द्वारा अधिग्रहित किया गया था, जो एक एक्सेस अपवाद का कारण बना।

बस कोड को निम्नानुसार संशोधित करें:

hWnd = CreateWindow(szWindowClass, szTitle, WS_OVERLAPPEDWINDOW, CW_USEDEFAULT,
    CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, NULL, NULL, GetModuleHandle(NULL), this);

और यह मेरे लिए काम करता है:

enter image description here

1
Song Zhu 25 नवम्बर 2020, 10:32

इस तरह का मुद्दा निम्न में से एक चिल्लाता है:

  • आपका वर्ग सूचक नष्ट, अप्रारंभीकृत, या अन्यथा होने के कारण अमान्य है;
  • आपके पास ढेर या ढेर भ्रष्टाचार है उदा. बफर अतिप्रवाह या अन्य अपरिभाषित व्यवहार।

अब, आइए आपकी कक्षा में दिखाई देने वाले तारों को देखें, जो बफर ओवरफ्लो के लिए उम्मीदवार हैं। नहीं, ऐसा लगता है कि आप उन ठीक शुरू कर रहे हैं।

ठीक है, अधिक स्थिर विश्लेषण। जहां समस्या होती है, वहां से पीछे की ओर काम करें।

  • CreateDeviceResources को किसने बुलाया? यह OnRender था
  • OnRender को किसने बुलाया? यह WM_PAINT हैंडलर था।
  • वह कॉल बहुत आसान है: pApp->OnRender(hWnd);
  • तो, क्या pApp मान्य है? यह कहाँ आरंभ किया गया है?
  • यह खिड़की के लंबे सूचक में संग्रहीत है - वह कब संग्रहीत किया जाता है?

और यह मुझे इस लाइन पर ले जाता है:

::SetWindowLongPtrW(hWnd, GWLP_USERDATA, PtrToUlong(pApp));

ठीक है, इसमें क्या गड़बड़ है? ठीक है, PtrToULong एक फ़ंक्शन (या मैक्रो) नहीं है जिसका मैंने कभी उपयोग किया है, लेकिन इसके नाम के आधार पर, मुझे तुरंत संदेह होता है क्योंकि मुझे 64-बिट्स में प्रोग्रामिंग करने की आदत है और मुझे पता है कि टाइप ULONG विंडोज एपीआई में 32-बिट है।

तो, मैं जाता हूं और दस्तावेज़ों की जांच करता हूं, और निश्चित रूप से मुझे लगता है कि यह मामला है। इतना ही नहीं, लेकिन मुझे इस बारे में कई लेख मिलते हैं कि 64-बिट को पोर्ट करते समय प्रोग्राम को तोड़ने के लिए यह वास्तव में एक आम अपराधी कैसे है।

ध्यान दें कि आप यहां पहले ही पहुंच सकते थे यदि आपने अपना डिबगर संलग्न किया होता, जो पहुंच उल्लंघन होने पर टूट जाएगा। और तब आप कॉल स्टैक को देख सकते थे। फिर आप अपनी pApp कक्षा की अन्य सामग्री की जांच कर सकते हैं और शायद देख सकते हैं कि पूरी चीज दूषित है।

इस बिंदु पर, आप बस "अरे मुझे पता है कि यह स्केच है", और आप लाइन को कुछ इस तरह बदलते हैं:

::SetWindowLongPtrW(hWnd, GWLP_USERDATA, reinterpret_cast<LONG_PTR>(pApp));

अब आप अपना प्रोग्राम संकलित करें और पुनः प्रयास करें। मैं शर्त लगाने को तैयार हूं कि यह काम करता है। इतना ही कि मैंने यह पूरा उत्तर उस शर्त के आधार पर लिखा है।

जांच के इस विशेष मार्ग पर पहुंचने का एक और तरीका यह होता कि आप अपने App कंस्ट्रक्टर में this के मूल्य का प्रिंट आउट ले लेते, और OnRender में इसे फिर से जांचते जब आपने देखा कि चीजें खराब हो रही हैं। विंकी

2
paddy 25 नवम्बर 2020, 06:19