为什么GetLogPen使用自定义笔失败?

GetLogPen()GetExtLogPen()的调用都失败。 他们返回零…

 CBrush Brush; Brush.CreateSolidBrush( COLOR_MINORSELECTION ); Brush.GetLogBrush( &lBrush ); DWORD Style[] = { 3, 1 }; CPen CustomPen; CustomPen.CreatePen( PS_USERSTYLE, 1, &lBrush, 2, Style ); CPen *pOldPen = pDC->SelectObject( &CustomPen ); LOGPEN LogPen; if( CustomPen->GetLogPen( &LogPen ) == 0 ) { EXTLOGPEN ExtLogPen; if( CustomPen->GetExtLogPen( &ExtLogPen ) == 0 ) return; } 

失败似乎是因为PS_USERSTYLE被用于笔风格。 如果我用PS_SOLID笔进行此操作, LogPen按照我的预期填充LogPen结构。

有什么想法吗?

这是CPen :: GetExtLogPen实现中的一个错误:

 int CPen::GetExtLogPen(EXTLOGPEN* pLogPen) { return ::GetObject(m_hObject, sizeof(EXTLOGPEN), pLogPen); } 

该实现忽略EXTLOGPEN结构中的尾随变量大小的DWORD数组。 这个结构被定义为:

 typedef struct tagEXTLOGPEN { DWORD elpPenStyle; DWORD elpWidth; UINT elpBrushStyle; COLORREF elpColor; ULONG_PTR elpHatch; DWORD elpNumEntries; DWORD elpStyleEntry[1]; } EXTLOGPEN, *PEXTLOGPEN; 

如果elpStyleEntry数组最多只有一个元素,则调用CPen::GetExtLogPen成功。 除了那些具有PS_USERSTYLE钢笔风格的笔之外,所有钢笔都是如此。 使用PS_USERSTYLE钢笔样式时, elpStyleEntry条目将至少有2个条目。

使用PS_USERSTYLE笔样式的笔的解决方法是使用Windows API GetObject调用,并绕过MFC实现:

 // Query for required buffer size int sizeRequired = ::GetObject(CustomPen.m_hObject, 0, nullptr); // Allocate buffer (may not be properly aligned) std::vector<byte> buffer(sizeRequired); // Retrieve the entire EXTLOGPEN structure int ret = ::GetObject(CustomPen.m_hObject, static_cast<int>(buffer.size()), buffer.data()); assert(ret == static_cast<int>(buffer.size()); // Cast to const ref for convenient access const EXTLOGPEN& elp = *reinterpret_cast<const EXTLOGPEN*>(buffer.data()); 

不幸的是, 由Mark Ransom发布的解决方案没有解决问题,因为CPen::GetExtLogPensizeof(EXTLOGPEN)传递给GetObject调用,而不是其参数的真实大小。


注意:一个错误报告已经提交给Microsoft Connect。

EXTLOGPEN结构仅为一个样式参数定义了空间,但最多允许为16个。不清楚GetExtLogPen如何确定有多少可用空间。 试试这个,看看是否有帮助。

 struct EXTLOGPEN16 : public EXTLOGPEN { DWORD elpStyleMore[15]; public: EXTLOGPEN16() { elpNumEntries = 16; } }; EXTLOGPEN16 ExtLogPen; if (CustomPen->GetExtLogPen(&ExtLogPen) == 0) // ...