Freigeben über


Überlegungen zur Sicherheit: GDI+

Dieses Thema enthält Informationen über Sicherheitsüberlegungen im Zusammenhang mit der Programmierung mit Windows GDI+. Dieses Thema enthält nicht alles, was Sie über Sicherheitsprobleme wissen müssen - verwenden Sie es stattdessen als Ausgangspunkt und Referenz für diesen Technologiebereich.

Überprüfen des Erfolgs von Konstruktoren

Viele der GDI+-Klassen bieten eine Image::GetLastStatus-Methode, die Sie aufrufen können, um festzustellen, ob Methoden, die für ein Objekt aufgerufen wurden, erfolgreich waren. Sie können außerdem Image::GetLastStatus aufrufen, um festzustellen, ob ein Konstruktor erfolgreich ist.

Das folgende Beispiel zeigt, wie Sie ein Image-Objekt konstruieren und die Methode Image::GetLastStatus aufrufen, um festzustellen, ob der Konstruktor erfolgreich war. Die Werte Ok und InvalidParameter sind Elemente der Auflistung Status.

Image myImage(L"Climber.jpg");
Status st = myImage.GetLastStatus();

if(Ok == st)
   // The constructor was successful. Use myImage.
else if(InvalidParameter == st)
   // The constructor failed because of an invalid parameter.
else
   // Compare st to other elements of the Status 
   // enumeration or do general error processing.

Zuweisung von Puffern

Mehrere GDI+-Methoden geben numerische Daten oder Zeichendaten in einem Puffer zurück, der vom Aufrufer zugewiesen wird. Für jede dieser Methoden gibt es eine Begleitmethode, die die Größe des erforderlichen Puffers angibt. Zum Beispiel gibt die Methode GraphicsPath::GetPathPoints ein Array von Point-Objekten zurück. Bevor Sie GraphicsPath::GetPathPoints aufrufen, müssen Sie einen Puffer zuweisen, der groß genug ist, um dieses Array aufzunehmen. Die Größe des benötigten Puffers können Sie ermitteln, indem Sie die Methode GraphicsPath::GetPointCount eines GraphicsPath-Objekts aufrufen.

Das folgende Beispiel zeigt, wie Sie die Anzahl der Punkte in einem GraphicsPath-Objekt bestimmen, einen Puffer zuweisen, der groß genug ist, um so viele Punkte aufzunehmen, und dann GraphicsPath::GetPathPoints aufrufen, um den Puffer zu füllen. Bevor der Code GraphicsPath::GetPathPoints aufruft, überprüft er, ob die Pufferzuweisung erfolgreich war, indem er sicherstellt, dass der Pufferzeiger nicht NULL ist.

GraphicsPath path;
path.AddEllipse(10, 10, 200, 100);

INT count = path.GetPointCount();          // get the size
Point* pointArray = new Point[count];      // allocate the buffer

if(pointArray)  // Check for successful allocation.
{
   path.GetPathPoints(pointArray, count);  // get the data
   ...                                     // use pointArray
   delete[] pointArray;                    // release the buffer
   pointArray = NULL;
}

Das vorige Beispiel verwendet den neuen Operator, um einen Puffer zuzuweisen. Der neue Operator war praktisch, weil der Puffer mit einer bekannten Anzahl von Point-Objekten gefüllt wurde. In manchen Fällen schreibt GDI+ mehr in den Puffer als in ein Array von GDI+-Objekten. Manchmal wird ein Puffer mit einem Array von GDI+-Objekten gefüllt, zusammen mit zusätzlichen Daten, auf die Mitglieder dieser Objekte verweisen. Zum Beispiel gibt die Methode Image::GetAllPropertyItems ein Array von PropertyItem-Objekten zurück, eines für jedes im Image gespeicherte Eigenschaftselement (ein Teil der Metadaten). Bevor Sie Image::GetAllPropertyItems aufrufen, müssen Sie einen Puffer zuweisen, der groß genug ist, um das Array der PropertyItem -Objekte zusammen mit den zusätzlichen Daten aufzunehmen.

Bevor Sie Image::GetAllPropertyItems aufrufen, müssen Sie einen Puffer zuweisen, der groß genug ist, um das Array der PropertyItem-Objekte zusammen mit den zusätzlichen Daten aufzunehmen. Sie können die Methode Image::GetPropertySize eines Image-Objekts aufrufen, um die Gesamtgröße des benötigten Puffers zu ermitteln.

Das folgende Beispiel zeigt, wie Sie ein Image-Objekt erstellen und später die Methode Image::GetAllPropertyItems dieses Image-Objekts aufrufen, um alle im Image gespeicherten PropertyItems (Metadaten) abzurufen. Der Code weist einen Puffer zu, der auf einem Größenwert basiert, der von der Methode Image::GetPropertySize zurückgegeben wird. Image::GetPropertySize gibt auch einen Zählwert zurück, der die Anzahl der Eigenschaftselemente im Image angibt. Beachten Sie, dass der Code die Puffergröße nicht als count*sizeof(PropertyItem) berechnet. Ein auf diese Weise berechneter Puffer wäre zu klein.

UINT count = 0;
UINT size = 0;
Image myImage(L"FakePhoto.jpg");
myImage.GetPropertySize(&size, &count);

// GetAllPropertyItems returns an array of PropertyItem objects
// along with additional data. Allocate a buffer large enough to 
// receive the array and the additional data.
PropertyItem* propBuffer =(PropertyItem*)malloc(size);

if(propBuffer)
{
   myImage.GetAllPropertyItems(size, count, propBuffer);
   ...
   free(propBuffer);
   propBuffer = NULL;
}

Fehlerüberprüfung

Die meisten Code-Beispiele in der GDI+-Dokumentation enthalten keine Fehlerüberprüfung. Eine vollständige Fehlerprüfung macht ein Code-Beispiel viel länger und kann die Aussage des Beispiels verzerren. Sie sollten Beispiele aus der Dokumentation nicht direkt in den produktiven Code einfügen, sondern die Beispiele durch eine eigene Fehlerprüfung ergänzen.

Das folgende Beispiel zeigt eine Möglichkeit, die Fehlerprüfung mit GDI+ zu implementieren. Jedes Mal, wenn ein GDI+-Objekt konstruiert wird, überprüft der Code, ob der Konstruktor erfolgreich war. Diese Prüfung ist besonders wichtig für den Image-Konstruktor, der auf das Lesen einer Datei angewiesen ist. Wenn alle vier GDI+-Objekte (Graphics, GraphicsPath, Image und TextureBrush) erfolgreich konstruiert wurden, ruft der Code Methoden für diese Objekte auf. Jeder Methodenaufruf wird auf Erfolg geprüft, und im Falle eines Fehlers werden die restlichen Methodenaufrufe übersprungen.

Status GdipExample(HDC hdc)
{
   Status status = GenericError;
   INT count = 0;
   Point* points = NULL;

   Graphics graphics(hdc);
   status = graphics.GetLastStatus();
   if(Ok != status)
      return status;

   GraphicsPath path;
   status = path.GetLastStatus();
   if(Ok != status)
      return status;

   Image image(L"MyTexture.bmp");
   status = image.GetLastStatus();
   if(Ok != status)
      return status;

   TextureBrush brush(&image);
   status = brush.GetLastStatus();
   if(Ok != status)
      return status;

   status = path.AddEllipse(10, 10, 200, 100);

   if(Ok == status)
   {
      status = path.AddBezier(40, 130, 200, 130, 200, 200, 60, 200);
   }
  
   if(Ok == status)
   {
      count = path.GetPointCount();
      status = path.GetLastStatus();
   }

   if(Ok == status)
   {
      points = new Point[count];

      if(NULL == points)
         status = OutOfMemory;
   }

   if(Ok == status)
   {
      status = path.GetPathPoints(points, count);  
   }
  
   if(Ok == status)
   {
      status = graphics.FillPath(&brush, &path);
   }
   
   if(Ok == status)
   {
      for(int j = 0; j < count; ++j)
      {
         status = graphics.FillEllipse(
         &brush, points[j].X - 5, points[j].Y - 5, 10, 10);
      }
   }

   if(points)
   {
      delete[] points;
      points = NULL;
   }

   return status;
}

Threadsynchronisierung

Es ist möglich, dass mehr als ein Thread Zugriff auf ein einzelnes GDI+-Objekt hat. GDI+ bietet jedoch keinen automatischen Synchronisierungsmechanismus. Wenn also zwei Threads in Ihrer Anwendung einen Zeiger auf dasselbe GDI+-Objekt haben, liegt es in Ihrer Verantwortung, den Zugriff auf dieses Objekt zu synchronisieren.

Einige GDI+-Methoden geben ObjectBusy zurück, wenn ein Thread versucht, eine Methode aufzurufen, während ein anderer Thread gerade eine Methode auf demselben Objekt ausführt. Versuchen Sie nicht, den Zugriff auf ein Objekt auf der Grundlage des Rückgabewerts ObjectBusy zu synchronisieren. Platzieren Sie stattdessen bei jedem Zugriff auf einen Mitglied oder bei jedem Aufruf einer Methode des Objekts den Aufruf innerhalb eines kritischen Abschnitts oder verwenden Sie eine andere standardmäßige Synchronisierungstechnik.

Sicherheitsdokumentation für Entwickler*innen

Ressourcen zum Thema Sicherheit

Microsoft Security Response Center