Verwendung von HINSTANCE__...



  • Jochen Kalmbach
    Was für Probleme? Die eine stelle, das war eine Sache von weniger als 1 Sekunde. Also bitte, wo ist das Problem? Gab keines. Und zu Win98 Zeiten hab ich nur eine Applikation für Win32 gemacht. Also keine Probleme.

    Und falsch ist er nicht, da es das selbe ist wie beim typedef. Dazu stimmt die Doku mit den Typen auch nicht immer 100%ig, in meiner MSDN steht z. B. noch immer das HINSTANCE ein void* ist.

    Also bitte, wie kann man sich nur an so etwas "aufgeilen"? Das ist doch genau der unsinn wie "Benutz ich nun D3DVALUE oder float in Direct3D?".

    Das bringt es doch nicht mal Ansatzweise. Und verwirrt? Hmn, wäre mir neu wenn das jemanden verwirrt hat? 😮



  • Das Problem ist nur:
    Du verwendest Dinge die nicht dokumentiert sind.

    Das mag für Dich kein Problem sein, aber jemand der neu anfängt, der fragt sich was denn das ganze sein soll...
    Auch kann MS die von dir verwendeten Definitionen ändern oder einfach entfernen. Das mag für Dich auch kein Problem sein, aber wenn Du grosse Projekte hast, hast Du einen ziemlich hohen Aufwand.
    Genau das ist ja mit LPARAM bzw. WPARAM passiert. MS hat hier die Definition mit Einführung von x64/IA64 geändert. Wer dann nicht konsequent das verwendet hat, hat ein Problem mit der Umstellung nach x64/IA64.

    Was Du den Leuten zeigst ist total verwirrend, da es mit keiner Doku von MS übereinstimt; das ist IMHO das Problem.



  • Jochen Kalmbach
    Also im privaten sowie gewerblichen Projekten gab es da bei mir und meinen Teams nie sonderliche Probleme. Um genau zu sein: Gar keine.

    Und ich bin ehrlich: Ich kenne bisher keinen der gesagt hat (registrierter User) "Hey, das verwirrt mich aber."

    Wie schon gesagt: Geschmackssache. Falsch ist der code nicht, da es der selbe Typ ist den Du auch benutzt und gut ist. Und das Microsoft noch tiefgründigere Änderungen macht in diesem Bereich mit _w64 bzw. _w128 halte ich für die nächsten Jahre mehr als nur unwahrscheinlich.



  • Es ist auf jeden Fall niemanden so zu Empfehlen wie Du programmierst. Und ich finde es schaden, dass Du dieses Screenshot in Deiner sonst guten Anleitung drin hast.



  • Patrick kann man eh nicht überzeugen. Die Diskussion mit ihm ist ziemlich sinnlos. 😃 👍



  • Jochen Kalmbach
    Jedem das Seine 😉 Ich bin mir sicher, würdest Du mir etwas Code von Dir geben, hätte ich auch was auszusetzen. Aber ist das nicht irgendwie normal bei jedem Code? Es soll jeder für sich selbst entscheiden wie er es macht, denn: Es gibt viele Wege die nach Rom führen 😉

    Kenner des Patrick
    Ziemlich subjektive Aussage, die nicht mal zutrifft 😉



  • Und was soll dann dieses hier?

    // Der Funktionspointer
    typedef int (__stdcall*msgbox)(HWND, LPCSTR, LPCSTR, UINT);
    

    Das verwirrt total. Warum schreibst du nicht:

    typedef int (__stdcall*msgbox)(HWND__*, const char*, const char*, unsigned int);
    

    Und überhaupt, wieso in aller Welt muß es ein typedef sein? Du sagtest doch, daß Du hinterher gar nicht mehr sehen kannst, worum es geht. Total unübersichtlich. Ein Cast an der richtigen Stelle löst das Problem sehr viel eleganter.

    Wenn Du schon nicht vernünftig programmieren willst, ziehe Deinen Style wenigstens durch. Mischmasch ist ja wohl das Allerletzte!



  • Und der Quellcode wird auch noch schlechter lesbar.



  • Pfosten
    Schau Dir das Datum der Codes an, bevor Du Dich noch lächerlich machst. Trollen ist öde, solltest Du wissen.

    Und das mit dem Thema "Vernünftig" stand bisher nicht zur Debatte. Aber bitte: Zeig mal einen "vernünftigen" Code von Dir, damit ich mich auch auf Deine Ebene herablassen kann. Sorry, aber für Kindergarten den Du veranstalten möchtest, habe ich keine Zeit.



  • Patrick schrieb:

    Aber bitte: Zeig mal einen "vernünftigen" Code von Dir, damit ich mich auch auf Deine Ebene herablassen kann.

    Gern, sehr vernünftig und ganz und gar ohne typedef:

    int (__stdcall* MyMessageBox)(HWND__*, const char*, const char*, unsigned int) = (int (__stdcall*)(HWND__*, const char*, const char*, unsigned int))GetProcAddress(dll, "MessageBoxA");
    

    Das ist völlig richtig so und in Richtung x64 wird sich bestimmt nichts weiter ändern. Und vor allem: Ohne typedef siehst Du sofort worum es sich dreht.



  • Ja, Nein, nun...als Anfänger möcht ich dazu sagen:
    "Das verwirrt mich" 😕

    Ich finde gerade die Typedefs machen die WinAPI Codes so kryptisch und unleserlich, und bauen eine Hemmschwelle für jemand der grad erst C++ gelern hat. Der denkt dann, "Wieso ist hier alles anders?"
    Ausserdem ist jegliches Codeschnippsel absolut unübertragbar ohne grössere Änderungsarbeiten.

    Darum:
    Wieso muss es ein UINT sein anstatt ein unsigned int ?
    oder noch übler ein VOID statt void
    und ein FALSE statt false?

    uawg



  • 1310-Logik
    Danke, das es mal einer auf den Punkt bringt. Danke.

    Pfosten
    Hast Du nicht eben gesagt, das dies nicht "vernünftiges Programmieren" ist? Komisch, das Du dann sowas vorweißt. Dazu: Wie wäre es mal registrieren? Als "Pfosten" kann sich ja jeder ausgeben. :p



  • Patrick schrieb:

    Das ist ein Allroundargument. Das wurde ich auch schon gefragt wieso ich anstatt eines LPARAMs einen long _w64 lParam benutze. Oder einen unsigned long anstatt eines DWORDs. Da wird mit absolut hoher Wahrscheinlichkeit nicht mehr so viel geändert wie zum Sprung von 3.11 auf 95, 98 und NT4. Das einzigste was sich im Laufe der Zeit geändert hat ist, dass ein __w64 dazu gekommen ist. Das ist aber auch alles.

    Ja, und irgendwann kommt _w128 und dann _w256 und dann ... Unter Portabilität versteht man eigentlich etwas anderes.

    Patrick schrieb:

    Außerdem hat das einen Vorteil: Bei Präsentationen muß man dann nicht mehr im Zeitdruck (15 Min für die gesamte Präsi) nicht noch erklären was ein LPARAM/WPARAM/DWORD usw. ist und begründen wieso man diese Namen gewählt hat usw.

    Du präsentierst deine Werke Linux Programmierern?

    Patrick schrieb:

    Klar das eine hat auch seine Vor- und Nachteile, aber das ist eine Diskusion die nichts bringt. Das ist genau so eine Diskusion wieso einige { direkt hinter dem Prozedur-/Funktionskopf schreiben oder andere erst einen Absatz einfügen bevor das { eingefügt wird.

    Naja, nicht wirklich. Das eine ist Codeformatierung, welche auf den Inhalt nicht den geringsten Einfluss hat. Du mit deinen Typen provozierst aber unnötig Inkonsistenz.

    Patrick schrieb:

    Und falsch ist er nicht, da es das selbe ist wie beim typedef. Dazu stimmt die Doku mit den Typen auch nicht immer 100%ig, in meiner MSDN steht z. B. noch immer das HINSTANCE ein void* ist.

    Genau deshalb nimmt man HINSTANCE, und nicht void*, HINSTANCE__ oder was auch immer. 😉 Stell dir den Typ wie eine black box vor, er hat einen bestimmten Zweck und wird situationsabhängig gebraucht. Was der Typ intern darstellt, weisst du aber nicht und hat dich auch überhaupt nicht zu interessieren. Zumal die Schnittstelle zur WinAPI ja nicht nur von Microsoft bereitgestellt wird (siehe zb MinGW). Du kannst also nicht immer davon ausgehen, dass der Typ HINSTANCE__ heisst. Der ist ja noch nicht mal dokumentiert. Vielleicht heisst er auch beim nächsten Release HINSTANCE___. Du siehst, verwende HINSTANCE und du entledigst dich all dieser Sorgen. Ausserdem sollte dir aufgefallen sein, dass der Bezeichner Unterstriche hat. Und solche Bezeichner sind idR der Implementation vorbehalten, also nicht dazu gedacht, von Clients benutzt zu werden.

    Patrick schrieb:

    Wie schon gesagt: Geschmackssache. Falsch ist der code nicht, da es der selbe Typ ist den Du auch benutzt und gut ist. Und das Microsoft noch tiefgründigere Änderungen macht in diesem Bereich mit _w64 bzw. _w128 halte ich für die nächsten Jahre mehr als nur unwahrscheinlich.

    Ja, und dass uns der Himmel auf den Kopf fällt auch. 🙄 Du solltest deine Argumentation wirklich nochmal überdenken.



  • groovemaster
    Nein, ich präsentiere das keinen Linuxprogrammierern sondern den Leutchen von der IHK, und ja: Ich musste das 1. mal begründen was das ist! Beim 2. mal hab ich Standardwerte genommen und Ruhe war.

    Und das mit "Ja, und dass uns der Himmel auf den Kopf fällt auch." empfinde ich als Wunschdenken. Dazu handelt es sich um eine Anfängerseite wo wie 1310-Logik es schon sagte, es ihn verwirrt das man UINT und co. benutzt.

    Also bitte, langsam wird es echt lächerlich mit dieser Diskusion. Das führt genau wieder zu so einer absurden Diskusion von wegen "size_t vs. unsigned long/int/short usw."



  • Aber ich mach es trotzdem so, wies in der MSDN steht.
    Weil sonst hab ich ein komplettes Durcheinander.
    Nur verstehn und einsehn, dass alles andere Namen bekommt, tu ich nicht.
    Ein Tisch ist ein Tisch und nicht ein MOEBEL_BRETTMITZWEIVIERODERSECHSBEINENAUFARBEITSHOEHEUNDMANCHMALAUCHHOEHERODERTIEFER



  • 1310-Logik schrieb:

    Ich finde gerade die Typedefs machen die WinAPI Codes so kryptisch und unleserlich, und bauen eine Hemmschwelle für jemand der grad erst C++ gelern hat.

    Auf den ersten Blick: Ja. Auf den zweiten Blick: Im Gegenteil.

    Du hälst Dich mit diesen ganzen typedefs portabel. Es ist Dir sogar beinahe egal, ob Du nun C oder C++ verwendest. Die älteren C Compiler kennen da z.B. kein bool, kein true und kein false. Verwendest Du durchgängig die typedefs, geht's überall, auch in Sprachen ohne C.

    Und wenn Du nun C verwendest, nicht C++, bleibt Dir ohne typedef sowieso nur Patricks Schreibweise. Aber an Übersicht gewinnst Du rein gar nichts. Wenn Du beispielsweise für eine Funktion eine Struktur des Typen RECT benötigst, schreibst Du

    // ohne typedef
    struct tagRECT rc;
    
    // oder eben mit
    RECT rc;
    

    Ich kann nicht sehen, wo mir das typedef Übersicht entzieht. Genauso ist das bei der HINSTANCE:

    struct HINSTANCE__* inst;
    

    Was bringt es mir bitteschön an Übersicht, wenn ich weiß, daß inst auf eine Struktur zeigt, die mit nur einem Member daherkommt, der sich treffenderweise unused nennt? Das bleibt genauso Opaque wie zuvor, schlauer bist Du nun auch nicht.

    Ungewohnt sind lediglich die vielen verschiedenen Typen. Da mußt Du aber durch. Aber Du hast ja die typedefs. Die helfen Dir dabei, die Übersicht zu wahren und schnell ins Thema zu finden.

    Ein typedef für VOID bringt Dir natürlich nichts ein. Es ist aber Konsequent. Ein fürchterliches Mischmasch wäre deutlich schlimmer gekommen. Das kannst Du schön bei Patrick sehen: Mal so, mal so, und am Ende weiß keiner mehr so genau, was eigentlich gemeint war. Und es macht doch auch nichts, Du hast doch auch so erkannt, daß VOID und void die selbe Wichse sind.



  • Das mit der Portabilität stimmt natürlich schon.
    Ja und bei HINSTANCE machts ja noch Sinn, auch HWND, die hat man im Standard ja sowieso nicht, aber bei den Standard Typen wie int und float ist es echt komisch, und schreckt am Anfang ab.
    In meinen eigenen Klassen verwend ich ja dann wieder die Standards, und somit wird das ganze echt inkonsistent. Ich hab da keine Lust, denn WINAPI Style komplett zu übernehmen.
    Oder macht ihr das so, dass ihr in eigenen Klassen FLOATs und DWORDs benutzt, wenn diese nichts Windowsspezifisches drin haben?



  • Kenner des Patrick schrieb:

    Patrick kann man eh nicht überzeugen. Die Diskussion mit ihm ist ziemlich sinnlos. 😃 👍

    Musste ich gerade auch feststellen.

    🙄



  • 1310-Logik schrieb:

    Wieso muss es ein UINT sein anstatt ein unsigned int ?

    Soll ja Leute geben, die lieber UINT schreiben. Einfach weil's kürzer und kompakter ist. Privat verwende ich auch eigene typedefs und schreibe halt lieber uint. Wirklich missverstehen kann man das eigentlich nicht.

    1310-Logik schrieb:

    oder noch übler ein VOID statt void

    Tja, ist mir ehrlich gesagt auch ein Rätsel. Vermutlich wollte Microsoft die eigene Typisierung komplett durchziehen. Man muss sich halt immer klarmachen, dass C/C++ case-sensitive arbeitet und die WinAPI Typen nicht zum Standard gehören.

    1310-Logik schrieb:

    und ein FALSE statt false?

    Dazu muss man ein bisschen in der Historie nachschauen. WinAPI ist eine C API, und zur damaligen Zeit hatte C noch kein bool. Dashalb wurde ein eigener Typ BOOL geschaffen, für welchen man logischerweise auch FALSE und TRUE brauchte. Und false bzw. true ist einfach nicht garantiert kompatibel zu BOOL. Warum eine Umwandlung trotzdem funktioniert, liegt an der impliziten Umwandlung, die C bzw. C++ definiert (da BOOL gleich int). Das ist aber ein anderes Thema. Grundsätzlich sollte man das jedenfalls nicht mischen. false und true gehören zu bool, FALSE und TRUE zu BOOL. Man kann ja trotzdem das eine dem anderen zuweisen, ohne auf die implizite Umwandlung angewiesen zu sein, zB

    BOOL a = /*...*/;
    bool b = a != FALSE;
    BOOL c = b ? TRUE : FALSE;
    

    Viele werden trotzdem den impliziten Weg bevorzugen, nur muss man dann mit Warnungen seitens des Compilers rechnen. Ich habe mir deshalb angewöhnt, zumindest bei BOOL nach bool immer das

    != FALSE
    

    zu schreiben.

    1310-Logik schrieb:

    Nur verstehn und einsehn, dass alles andere Namen bekommt, tu ich nicht.

    Dass die WinAPI oftmals seltsame Bezeichner hat, ist ja bekannt ➡ Thema UN. Das ist aber auch nicht das Problem.

    1310-Logik schrieb:

    Aber ich mach es trotzdem so, wies in der MSDN steht.
    Weil sonst hab ich ein komplettes Durcheinander.

    Genau das ist der springende Punkt, den Patrick halt nicht versteht.

    Patrick schrieb:

    Nein, ich präsentiere das keinen Linuxprogrammierern sondern den Leutchen von der IHK

    ROFL, naja dazu sag ich mal nichts. Ich hoffe nur, dass du deren Verhalten nicht als Standard interpretierst. Ein WinAPI Programmierer weiss jedenfalls, was LPARAM etc. bedeutet und ist eher verwirrt, wenn du die aufgelösten Typen verwendest.

    Patrick schrieb:

    Also bitte, langsam wird es echt lächerlich mit dieser Diskusion. Das führt genau wieder zu so einer absurden Diskusion von wegen "size_t vs. unsigned long/int/short usw."

    Naja, ich will jetzt nicht diese Diskussion anheizen. Das ist ein anderes Thema. Nur gibt es halt immer wieder Leute, die sowas für sinnlos halten und stupide das benutzen, was sie auch vorher benutzt haben oder fälschlicherweise für richtig ansehen. Und wer nicht glaubt, dass size_t sinnvoll ist und weiter unsigned int oder gar nur int benutzt, wird spätestens bei der Umstellung auf 64 Bit Probleme bekommen. Und genau das könnte dir mit deinen aufgedröselten Typen auch passieren. Das heisst nicht, dass es definitiv passieren wird. Aber die Möglichkeit besteht. Warum sich also vollkommen unnötig das Leben schwer machen?

    btw:
    Ich poste niemals als Unreg. Solche Beiträge also nicht mir zuordnen.



  • 1310-Logik schrieb:

    In meinen eigenen Klassen verwend ich ja dann wieder die Standards, und somit wird das ganze echt inkonsistent. Ich hab da keine Lust, denn WINAPI Style komplett zu übernehmen.
    Oder macht ihr das so, dass ihr in eigenen Klassen FLOATs und DWORDs benutzt, wenn diese nichts Windowsspezifisches drin haben?

    Nein, natürlich nicht. Zumindest kann ich da für mich sprechen. Schon deshalb nicht, weil du dann ja immer auf <windows.h> angewiesen bist und Plattformunabhängigkeit zum Fremdwort wird. Das Zauberwort heisst Abstraktion. Wenn ich WinAPI Sachen verwende (zB Threads oder Performance Counter), dann werden diese Sachen gekapselt. Intern verwende ich die WinAPI Typen, nach aussen werden aber Standard Typen weitergegeben, zB

    float foo()
    {
        /*...*/
        return IrgendeineWinAPIFunktiondieFLOATzurueckgibt(/*...*/);
    }
    

    Und ich sehe auch kein Problem darin, wenn du die primitiven Typen plain kopierst, also FLOAT nach float oder LONG nach long oder UNIT nach unsigned int oder ...


Anmelden zum Antworten