为什么使用指针调用 GetWindowRect 会导致异常,而地址不会

Why does calling GetWindowRect with pointer cause exception but address doesn't

本文关键字:异常 地址 指针 调用 GetWindowRect 为什么      更新时间:2023-10-16

我在dll中有一个实用程序函数来将我的表单放在主机应用程序屏幕的中心。我使用的是RAD Studio XE2。我必须手动完成,因为主机应用程序是非vcl的,而且TForm的表单放置参数不能正常工作。下面的代码可以工作。这两个函数都被声明为静态的,我之前已经将Application handle属性设置为宿主应用程序。

   void MyClass::GetAppCenter(POINT * pos) {
      RECT Rect;
      GetWindowRect(Application->Handle, &Rect);
      pos->x = (Rect.left + Rect.right) / 2;
      pos->y = (Rect.top + Rect.bottom) / 2;
   }
   void MyClass::PlaceForm(TForm * f) {
      POINT pos;
      GetAppCenter(&pos);
      for (int i = 0; i < Screen->MonitorCount; i++) {
         TRect r = Screen->Monitors[i]->WorkareaRect;
         if (r.Contains(pos)) {
            f->Left = (r.Left + r.Right) / 2 - f->Width / 2;
            f->Top = (r.Top + r.Bottom) / 2 - f->Height / 2;
            return;
         }
      }
   }

我的初始GetAppCenter代码使用了Rect *,并返回了正确的值,但是当我设置f->Left时抛出了访问违反异常。有人能解释一下原因吗?

   // original version
   void OasisUtils::GetOasisCenter(POINT * pos) {
      RECT *Rect;
      GetWindowRect(Application->Handle, Rect);
      pos->x = (Rect->left + Rect->right) / 2;
      pos->y = (Rect->top + Rect->bottom) / 2;
      delete Rect; // tried with and without this
   }
  RECT *Rect;
  GetWindowRect(Application->Handle, Rect);
  //Rect->left 

这是不正确的。GetWindowRect需要一个有效的RECT*参数来填充这个指针指向的内存。相反,您传递的是一个未初始化的指针,期望通过某种魔法使其有效。相反,你会得到访问冲突。你需要:

  RECT Rect;
  GetWindowRect(Application->Handle, &Rect); // <<--- Note &
  //Rect.left 

gettwindowrect期望调用者拥有矩形结构

在你的原始版本中,你的*Rect没有指向任何有效的内存。所以当你试图使用它时,你是在访问一些不属于你的随机内存块。操作系统对此予以否认。我只是很惊讶对GetWindowRect的调用没有导致崩溃。

另一方面,您的更新版本声明RECT Rect,它在堆栈上分配内存。该内存在函数调用时自动分配,并在函数结束时清理。

澄清一下,这个问题与指针和引用之间的差异无关。这个问题完全是由内存分配/所有权引起的。