2016-05-23 25 views
2

Die Aufrufe von GetLogPen() und GetExtLogPen() schlagen beide fehl. Sie kehren Null ...Warum schlägt GetLogPen mit einem benutzerdefinierten Stift fehl?

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; 
} 

Der Ausfall wegen der PS_USERSTYLE zu sein scheint für den Stift Stil verwendet wird. Wenn ich dies mit einem PS_SOLID Stift mache, bekomme ich die LogPen Struktur ausgefüllt, wie ich es erwarte.

Irgendwelche Gedanken?

Antwort

2

Dies ist ein Fehler in der CPen::GetExtLogPen Umsetzung:

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

Die Implementierung ignoriert die nachlauf variabler Größe Array von DWORD s in der EXTLOGPEN Struktur. Diese Struktur ist wie folgt definiert:

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

Der Aufruf von CPen::GetExtLogPen erfolgreich ist, wenn die elpStyleEntry Array höchstens ein Element lang ist. Dies gilt für alle Stifte mit Ausnahme von Stiften mit der Stiftform PS_USERSTYLE. Wenn Sie den Stifttyp PS_USERSTYLE verwenden, hat der Eintrag elpStyleEntry mindestens zwei Einträge.

Die Abhilfe im Fall von Stiften mit dem PS_USERSTYLE Stift Stil ist den Windows-API GetObject Aufruf, zu verwenden und die MFC-Implementierung zu umgehen:

// 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()); 

Leider ist die solution posted by Mark Ransom das Problem nicht lösen, weil Die CPen::GetExtLogPen übergibt sizeof(EXTLOGPEN) an den GetObject Aufruf, nicht die wahre Größe des Arguments.


Hinweis: A bug report wurde an Microsoft Connect übermittelt.

0

Die EXTLOGPEN Struktur definiert Platz für nur einen Stilparameter, erlaubt aber bis zu 16. Es ist unklar, wie GetExtLogPen bestimmt, wie viel Platz verfügbar ist. Versuchen Sie es und sehen Sie, ob es hilft.

struct EXTLOGPEN16 : public EXTLOGPEN 
{ 
    DWORD elpStyleMore[15]; 

public: 
    EXTLOGPEN16() 
    { 
     elpNumEntries = 16; 
    } 
}; 

EXTLOGPEN16 ExtLogPen; 
if (CustomPen->GetExtLogPen(&ExtLogPen) == 0) 
    // ... 
+0

Dieser Vorschlag erinnert mich an Datenstrukturen, die einen Größenwert als ersten Eintrag haben. Ich habe das versucht, hatte aber kein Glück. Ich habe es auch mit einem einzigen Wert für das Style-Array versucht und es hat funktioniert! Anscheinend haben die MS-Programmierer, die den Code dafür geschrieben haben, entschieden, dass niemand die Funktion benötigt, um zu funktionieren, wenn sie einen komplizierteren Strich/Lücke-Stil für ihre Zeilen haben. –

+1

'GetExtLogPen' ruft vermutlich [GetObject] (https://msdn.microsoft.com/en-us/library/dd144904) auf. 'GetObject' gibt die Anzahl der Bytes zurück, die in den Rückgabepuffer kopiert wurden. Dieser Wert teilt Ihnen implizit die Anzahl der verwendeten Werte mit. @DavidRector: Dies ist ein sehr häufiges Muster, das in Strukturen variabler Größe verwendet wird. Das abschließende Array mit einer Größe ist erforderlich, damit der Compiler die korrekte Ausrichtung erzeugt. Dies löst ein anderes Problem als das, worüber Sie gesprochen haben; Strukturen, die ein explizites Größenfeld als ihren ersten Eintrag tragen, sind nützlich, um die Versionierung zu implementieren. – IInspectable

+0

@Intspectable, ich kenne das Strukturmuster mit variabler Größe aus älterem Windows-Code, das ich geschrieben habe.'GetExtLogPen' akzeptiert keinen Wert für die Strukturgröße und kann daher nur Daten zurückgeben, wenn es im Stil-Array null oder einen Eintrag gibt. Ich erkenne jetzt, dass ich 'GetObject' selbst aufrufen kann und ich vermute, dass es wie gewünscht funktioniert. Wenn Sie den 'GetObject'-Vorschlag als Antwort veröffentlichen, werde ich es versuchen und dann als Antwort markieren, da es offensichtlich ist, dass' GetExtLogPen' nicht mehr als ein Stilelement in der Struktur verarbeiten kann. –