2009-05-10 6 views
3

Ich brauche FormatMessage() für ein Projekt, aber ich mag seine unheimliche Schnittstelle nicht. Kennt jemand eine Fassade, die es aufräumt und dennoch die Austauschparameter berücksichtigt?Sichere/flexible Fassade für Windows FormatMessage

Ich habe gerade gelesen die second part of the FastFormat introduction, und bin am überlegen für FormatMessage() eine Verlängerung schriftlich (oder fragen Sie das FastFormat Projektteam, wenn sie einen in den Werken haben), aber ich bin daran interessiert, so schnell wie möglich, etwas zu bekommen, so dass, wenn es etwas gibt, Sonst würde ich das wahrscheinlich lieber nehmen.

Was ich will, ist in der Lage sein, Code zu schreiben, wie zum Beispiel:

HINSTANCE netevent = ::LoadLibrary("netevent.dll"); 
std::string msg = LookupError(netevent, EVENT_SERVICE_START_FAILED_II, 
    "child-svr", "parent-svr", "ship happens"); 
::puts(msg.c_str()); 

die das Ergebnis geben würde:

The child-svr service depends on the parent-svr service which failed to start be cause of the following error: 
ship happens 

Die aktuellen Wrapper ich gebaut habe, haben die Schnittstelle:

std::string LookupError(HINSTANCE hinst, DWORD id, ...); 

Es gibt zwei Probleme damit:

  • Es ist nicht typsicher, da es einfach ist, jede Art passieren - int, std::string, void* - das ist nicht const char*
  • Es ist einfach, die Anzahl der Argumente mit der Nummer von dem Format-String erforderlich ist, um Mismatch den Fehler darstellt

die Fähigkeiten FastFormat in Bezug auf die Typsicherheit gegeben, möchte ich wissen, ob es eine Möglichkeit gibt, ihre Mechanismen zu folgen mit FormatMessage() beschäftigen.

+3

Sie möchten in der Lage sein, etwas wie ... zu schreiben? Was? –

+0

Doh! Es tut uns leid. Wird das momentan beheben ... – dcw

Antwort

1

Da die Anzahl der in die Formatzeichenfolge einzufügenden Parameter nicht vom Compiler überprüft werden kann, ist es nicht möglich, diese zur Kompilierungszeit wirklich typsicher zu machen.

Sie können den größten Teil des Weges dorthin zurücklegen, indem Sie nur einige Überladungen für verschiedene Anzahlen von eingefügten Parametern haben und dann die eingefügten Werte mit etwas flexiblem wie boost::any spezifizieren. So ist die Überlastung für zwei Parameter wäre:

std::string FormatMessage(HINSTANCE hinst, DWORD id, const boost::any &arg1, const boost::any &arg2); 

Wenn Sie den Wert von arg1 abrufen, auftrieb werfen, wenn Sie versuchen, die falsche Art zu bekommen, so brauchen Sie nur die Formatzeichenfolge zu untersuchen und versuchen, das bekommen erforderlicher Typ von jedem Argument.

Alternativ könnten Sie Templates und std :: ostringstream (oder boost :: lexical_cast) für eine sehr flexible Version verwenden; wieder gäbe es Überlastungen kann die Anzahl der Argumente zu ermöglichen, zu variieren, also hier ist die Single-Argument Version:

template <class TArg1> 
std::string FormatMessage(HINSTANCE hinst, DWORD id, const TArg1 &arg1) 
{ 
    std::ostringstream arg1Stream; 
    arg1Stream << arg1; 
    std::string arg1String = arg1Stream.str(); 

    DWORD_PTR argArray = reinterpret_cast<DWORD_PTR>(arg1String.c_str()); 

    // ... etc 
} 

diese Weise können Sie so lange eine Zeichenfolge von jedem Argument bekommen kann als die übergebene Typ gestreamt werden kann, und nichts anderes sollte erforderlich sein, solange die Formatzeichenfolgen nur das Einfügen von Zeichenfolgen erwarten.

+1

Interessante Idee. FormatMessage() benötigt entweder eine va_list von Argumenten oder ein Array von 32-Bit-Argumenten. Im ersten Fall benötigen wir also eine variadische Funktion, die jedoch in einer Funktion wie der von Ihnen beschriebenen Funktion enthalten sein könnte, und boost :: any würde die Typ-Sicherheit übernehmen. Alternativ könnten wir das Array von Argumenten direkt erstellen. Aber einer der Gründe, warum ich an FastFormat interessiert war, ist seine Fähigkeit, mit beliebigen Argumenten zu arbeiten, was bedeuten würde, dass jeder Typ übergeben und dann vor dem Aufruf von FormatMessage() in char * konvertiert werden könnte. Ich denke nicht, dass boost :: any es zulassen würde – dcw

+0

Siehe Update, etwas flexibler. –

0

The C++ Format library ermöglicht die Formatierung nativer Windows-Fehlermeldungen, die Fehlercodes entsprechen, die von GetLastError() und POSIX-Fehlermeldungen zurückgegeben werden, die Fehlern entsprechen, die von errno angegeben werden.Zum Beispiel:

// This throws a WindowsError with the description 
// cannot open file 'madeup': The system cannot find the file specified. 
// or similar (system message may vary). 
const char *filename = "madeup"; 
LPOFSTRUCT of = LPOFSTRUCT(); 
HFILE file = OpenFile(filename, &of, OF_READ); 
if (file == HFILE_ERROR) 
    throw fmt::WindowsError(GetLastError(), "cannot open file '{}'", filename); 

Windows-Fehlermeldung wird mit der Funktion FormatMessage API erhalten. Sie können auch eine Fehlermeldung mit fmt::format_windows_error formatieren, die keine Ausnahme auslöst. Weitere Informationen finden Sie unter System Errors.

Haftungsausschluss: Ich bin der Autor von C++ - Format

Verwandte Themen