安全注意事项:GDI+
本主题提供有关使用 Windows GDI+ 编程的安全注意事项的信息。 本主题并未提供你需要了解的关于安全问题的所有信息 - 此技术领域从本主题开始,主题中的内容仅供参考。
验证构造函数是否成功
许多 GDI+ 类都提供了 Image::GetLastStatus 方法,你可以调用该方法来确定在对象上调用的方法是否成功。 还可以调用 Image::GetLastStatus 来确定构造函数是否成功。
以下示例演示如何构造 Image 对象并调用 Image::GetLastStatus 方法来确定构造函数是否成功。 Ok 和 InvalidParameter 值是 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.
分配缓冲区
多个 GDI+ 方法在调用方分配的缓冲区中返回数字或字符数据。 对于上述每个方法,都有一个配套方法,可提供所需缓冲区的大小。 例如,GraphicsPath::GetPathPoints 方法返回 Point 对象的数组。 在调用 GraphicsPath::GetPathPoints 之前,必须分配足够大的缓冲区来保存该数组。 可以通过调用 GraphicsPath 对象的 GraphicsPath::GetPointCount 方法来确定所需缓冲区的大小。
以下示例演示如何确定 GraphicsPath 对象中的点的数量,分配一个足够大的缓冲区来容纳这些点,然后调用 GraphicsPath::GetPathPoints 来填充缓冲区。 在代码调用 GraphicsPath::GetPathPoints 之前,它通过确保缓冲区指针不为 NULL 来验证缓冲区分配是否成功。
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;
}
前面的示例使用 new 运算符分配缓冲区。 new 运算符很方便,因为缓冲区填充了已知数量的 Point 对象。 在某些情况下,GDI+ 在缓冲区中写入的内容比 GDI+ 对象数组多。 有时,有时缓冲区会填充 GDI+ 对象数组以及这些对象的成员指向的其他数据。 例如,Image::GetAllPropertyItems 方法返回 PropertyItem 对象的数组,每个对象对应存储在映像中的属性项(元数据片段)。 但 Image::GetAllPropertyItems 返回的不仅仅是 PropertyItem 对象的数组;它为数组添加了额外的数据。
在调用 Image::GetAllPropertyItems 之前,必须分配一个足够大的缓冲区,以容纳 PropertyItem 对象数组以及其他数据。 可以调用 Image::GetPropertySize 方法来确定所需缓冲区的总大小。
以下示例演示如何创建 Image 对象,然后调用 Image 对象的 Image::GetAllPropertyItems 方法,以检索存储在映像中的所有属性项(元数据)。 代码根据 Image::GetPropertySize 方法返回的大小值分配缓冲区。
Image::GetPropertySize 还返回一个计数值,该计数值给出了映像中的属性项数量。 请注意,代码不会将缓冲区大小计算为 count*sizeof(PropertyItem)
。 以这种方式计算的缓冲区太小了。
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;
}
错误检查
GDI+ 文档中的大多数代码示例都不显示错误检查。 完整的错误检查会使代码示例变得更长,并可能掩盖示例所说明的要点。 不应将文档中的示例直接粘贴到生产代码中;相反,应通过添加自己的错误检查来增强示例。
以下示例显示了使用 GDI+ 实现错误检查的一种方法。 每次构造 GDI+ 对象时,代码都会检查构造函数是否成功。 该检查对于依赖于读取文件的 Image 构造函数尤其重要。 如果所有四个 GDI+ 对象(Graphics、GraphicsPath、Image 和 TextureBrush)都已成功构造,则代码将调用这些对象的方法。 检查每个方法调用是否成功;如果失败,则跳过其余的方法调用。
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;
}
线程同步
多个线程可以访问单个 GDI+ 对象。 但是,GDI+ 不提供任何自动同步机制。 因此,如果应用程序中的两个线程有一个指向同一 GDI+ 对象的指针,那么你有责任同步对该对象的访问。
如果一个线程试图调用一个方法,而另一个线程正在对同一个对象执行一个方法,则一些 GDI+ 方法将返回 ObjectBusy。 不要尝试根据 ObjectBusy 返回值同步对对象的访问。 相反,每次访问对象的成员或调用对象的方法时,请将调用放在关键部分内,或使用其他标准同步技术。
相关主题
Microsoft Security Response Center(Microsoft 安全响应中心)