2011-01-26 2 views
1

поэтому я только что начал программирование Windows с помощью C++. Сначала я рисую несколько строк, и это было ОК, , тогда я попытался создать класс для рисования некоторых фигур, и он отлично работает, когда я использую обычный метод для создания объекта (в коде эти части закомментированы), но когда я использую указатель для создания нового объекта, я получаю ошибку Access violation.Ошибка нарушения доступа с помощью указателя на объект creat

Вот мой класс (Я удалил часть кода, так что, возможно, кажется, упрощена в некоторых частях):

class shapes { 
public: 
    shapes(void); 
    void setstartp(POINT& p0); 
    void setendp(POINT& p1); 

    void draw(HDC hdc); 
    ~shapes(void); 

    POINT x0; 
    POINT x1; 
}; 

shapes::shapes(){} 

void shapes::setstartp(POINT& p0){ 
    x0=p0; 
} 

void shapes::setendp(POINT& p1){ 
    x1=p1; 
} 

void shapes::draw(HDC hdc){ 
    MoveToEx(hdc,x0.x ,x0.y ,0); 
    LineTo(hdc ,x1.x ,x1.y); 
} 

shapes::~shapes(void) {} 

И это моя программа, или, по крайней мере, winproc часть:

//shapes sh; 
shapes* sh =0; 
bool mousdown =false; 

LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) 
{ 
    POINT p0; 
    POINT p1; 
    int wmId, wmEvent; 
    PAINTSTRUCT ps; 
    HDC hdc; 

    switch (message) 
    { 
     case WM_LBUTTONDOWN : 
      SetCapture(hWnd); 
      mousdown = true; 

      p0.x = LOWORD(lParam); 
      p0.y = HIWORD(lParam); 

      // sh.setstartp(p0); 
      sh = new shapes(); 
      sh->setstartp(p0); 
      break;  
    case WM_MOUSEMOVE : 
     if(mousdown) { 
      p1.x = LOWORD(lParam); 
      p1.y = HIWORD(lParam); 
      // sh.setendp(p1); 
      sh->setendp(p1); 
      InvalidateRect(hWnd ,0,true); 
     } 
     break;  
    case WM_LBUTTONUP : 
     ReleaseCapture(); 
     mousdown = false; 
     p1.x = LOWORD(lParam); 
     p1.y = HIWORD(lParam); 

     // sh.setendp(p1); 
     sh->setendp(p1); 
     InvalidateRect(hWnd ,0,true); 
     break; 
    case WM_PAINT: 
     hdc = BeginPaint(hWnd, &ps); 
     // TODO: Add any drawing code here... 
     //sh.draw(hdc); 
     sh->draw(hdc); 
     EndPaint(hWnd, &ps); 
     break; 
    case WM_COMMAND: 

Здесь моя Access violation ошибка:

Unhandled exception at 0x00411fda in NEWWIN.exe: 0xC0000005: Access violation reading location 0x00000004.

И ошибка указывает на класс реализации:

void shapes::draw(HDC hdc) {   
    MoveToEx(hdc,x0.x ,x0.y ,0); 
    LineTo(hdc ,x1.x ,x1.y); 
} 

Видимо есть проблема с моими свойствами класса x0 и x1:

this 0x00000000 {x0={...} x1={...} } shapes * const

x0 {x=??? y=???} tagPOINT

x CXX0030: Error: expression cannot be evaluated

y CXX0030: Error: expression cannot be evaluated

x1 {x=??? y=???} tagPOINT

x CXX0030: Error: expression cannot be evaluated

y CXX0030: Error: expression cannot be evaluated

+0

Это ваш собственный выбор для разработки win32 в C++? Сначала я создал прототип в C#, а затем вернул обратно то, что оказалось актуальным. –

+0

Да, моя цель - начать программирование directx. – max

ответ

3

Проблема заключается в том, что вы не создаете объект shapes до получения (и обработки события WM_LBUTTONDOWN). Так что, если любое другое событие (. Например WM_MOUSEMOVE) обрабатывается раньше, то sh еще будет 0.

Кроме того, обратите внимание, что у вас есть утечка памяти здесь: вы звоните sh = new shapes(); для каждого WM_LBUTTONDOWN события, никогда не удаляя ранее выделенные объекты ,

Я предлагаю вам выделить свой shape объект в WM_CREATE обработчика, и что вы delete его в WM_DESTROY обработчика.

+0

thanx идея состоит в том, чтобы создавать разные классы для рисования разных форм, а класс «фигуры» является абстрактным родителем для этих классов, поскольку я сказал, что удалил эти части, чтобы разобраться в сути проблемы, теперь пользователь будет выбирать форму из меню, так что объект должен быть создан на WM_LBUTTONDOWN, я думаю, я мог бы использовать «if (sh! = 0)», чтобы проверить объект на WM_PAINT – max

+0

Ок - да, 'if (sh) {...}' в порядке. И я предполагаю, что вы сохраняете список объектов формы вокруг, и в вашей реальной программе нет утечки памяти. –

+0

Да, есть вектор, который я собираюсь хранить в своих объектах, или я должен сказать, что мои указатели на нем, так что мне нужно удалить объект «sh», а также мой вектор на WM_DESTROY? пользователь может нарисовать 20 строк перед закрытием окна. Нужно ли мне уничтожать объект «sh» после рисования каждой строки или удаления его один раз на WM_DESTROY будет достаточно? – max

1
sh->setendp(p1); 

Да, это будет kaboom. Вы всегда будете получать сообщение WM_MOUSEMOVE, прежде чем получите сообщение WM_LBUTTONDOWN. Вы еще не создали объект sh. Изменение

shapes* sh =0; 

в

shapes sh; 

для исправления первого порядка.

0

Только представьте, что произойдет, если ваша программа получает события в таком порядке:

  1. WM_PAINT
  2. WM_MOUSEMOVE
  3. WM_BUTTONDOWN
  4. WM_PAINT
  5. WM_MOUSEMOVE
  6. WM_BUTTONUP
  7. WM_PAINT

Объект shapes не создается, пока не наступит событие 3, но вы уже пытаетесь нарисовать фигуру в первом случае.

Самое простое исправление, чтобы избавиться от аварии - проверить, что sh не является нулевым указателем (if (sh != 0) /* use sh */), или вернуться к использованию без указателя.

Но есть большие проблемы в вашем коде:

  • В настоящее время у вас есть утечка памяти, потому что вы создаете новый shapes объект для каждого WM_BUTTONDOWN события, но вы никогда не удалить любой из них
  • Что делать вы хотите нарисовать, если вы получаете событие WM_PAINT до того, как будут установлены оба угла формы? В настоящее время вы рисуете строку в неопределенном месте.
+0

thanx man я думал, что WM_MOUSEMOVE станет первым событием – max

+0

@max: Это проблема с событиями. Они могут прийти совершенно неожиданно. Вы можете только предположить, что событие B следует за событием A, если обработчик события B сгенерировал это событие. И даже тогда могут произойти другие события. –

Смежные вопросы