Problem bei: Button soll CreateWindow aufrufen: Error



  • Hallo allerseits!

    Ich habe das folgende Problem:
    DAs Klicken auf einen Button einer windows forms application soll mittels CreateWindow ein neues Fenster erzeugen (das benötigt wird um dort DirectX Inhalt darzustellen).

    Leider gelang mir das nicht.

    Das beste, was ich erreichte, war nur ein Error, aber das ist ja immernoch einer zuviel....

    Mein Vorgehen war:
    Visual Studio > Neues Projekt: CLR / windows forms application > in (Standard) Form1.h (Design) ein Button zugefügt und diesem verswucht das Create Window Ereignis zuzuordnen.

    Form1.h sieht also etwa so aus:

    #pragma once
    #include <windows.h> 
    ...
    #pragma endregion
    	private: System::Void button1_Click(System::Object^  sender, System::EventArgs^  e) {
    
    	// Create a window
    	HWND hWnd = CreateWindow( "Fensterklasse", "Fenstername",  // das ist Zeile 95
                                  WS_OVERLAPPEDWINDOW, 100, 100, 300, 300,
                                  NULL, NULL, NULL, NULL );
    
            // Show the window
            ShowWindow( hWnd, SW_SHOWDEFAULT );
            UpdateWindow( hWnd );
    			 }
    	};
    }
    

    Ich erhalte allerdings folgenden Error beim builden:

    Form1.h(95) : error C2664: 'CreateWindowExW' : cannot convert parameter 2 from 'const char [14]' to 'LPCWSTR'
    Types pointed to are unrelated; conversion requires reinterpret_cast, C-style cast or function-style cast

    Was ich nicht so ganz verstehe:
    In diesem Beispiel ist doch der Fenstername auch einfach als String gesetzt.

    (Entschuldigung wenn ich mich blöd anstelle, bin eben noch ein Anfänger... ...mit diesen in der Error Meldung erwähnten Cast Funktionen habe ich auch rumprobiert, allerdings erfolglos, ich weiß aber nicht, ob ich das richtig machte....)

    Was mache ich falsch und wie kann ich doch noch durch den Button ein Fenster erzeugen?

    Danke und Gruß,
    Dong



  • HWND hWnd = CreateWindow( "Fensterklasse", "Fenstername",  // das ist Zeile 95
                                  WS_OVERLAPPEDWINDOW, 100, 100, 300, 300,
                                  NULL, NULL, NULL, NULL );
    

    Du rufst (indirekt) CreateWindowExW auf (Unicode ist im Projekt eingestellt).
    Die Funktion erwartet 2 Byte chars (wchar_t). Du ergibst mit "Fensterklasse" / "Fenstername" aber nur 1 Byte chars (char).
    Du musst, um den String in 2 Byte chars umzuwandeln, dem String DIREKT ein L voranstellen (L"Hallo"), damit wird der String umgewandelt.

    Da du aber die Windows-Macros verwendest, würde ich dir raten, deine Strings in das _T(x) bzw. TEXT(x) Macro einzubetten:

    // Bei Unicode
    #define _T(x) L ## (x)
    // Unicode aus
    #define _T(x) (x)
    

    Bei TEXT(x) sieht das ähnlich aus, ist nur ein Alias.



  • Danke, plusman, das hat aber leider nicht geholfen:

    Jetzt verwende ich

    HWND hWnd = CreateWindow( "Fensterklasse", L"Fenstername", // das ist immernoch Zeile 95
                                  WS_OVERLAPPEDWINDOW, 100, 100, 300, 300,
                                  NULL, NULL, NULL, NULL );
    

    und beim builden erhalte ich immer noch

    Form1.h(95) : error C2664: 'CreateWindowExW' : cannot convert parameter 2 from 'const char [14]' to 'LPCWSTR'
    Types pointed to are unrelated; conversion requires reinterpret_cast, C-style cast or function-style cast
    Generating Code...

    Was jetzt?

    Danke und Gruß,
    dong



  • Ich empfehle Dir:
    Mixe bitte nicht C++/CLI (Windows-Forms) mit unmanaged C (Win32-API).
    Das führt nur zu Problemen und es ist sehr undurchsichtig für Dich...

    Verwende also bitte:

    Form ^frm = gcnew Form();
    frm->Show();
    


  • Jochen Kalmbach schrieb:

    Ich empfehle Dir:
    Mixe bitte nicht C++/CLI (Windows-Forms) mit unmanaged C (Win32-API).
    Das führt nur zu Problemen und es ist sehr undurchsichtig für Dich...

    Verwende also bitte:

    Form ^frm = gcnew Form();
    frm->Show();
    

    Das geht, danke! -- Allerdings weiß ich dann nicht, wie ich dieses Fenster ansprechen soll, um dort eine DirectX Ausgabe hervorzurufen.

    Das machte ich bisher (dem DirectX SDK Tutorial gemäß) mit der Funktion InitD3D:

    HRESULT InitD3D( HWND hWnd )
    

    welche dann so aufgerufen werden konnte:

    // Create the application's window
        HWND hWnd = CreateWindow( "D3D Tutorial", "D3D Tutorial 01: CreateDevice", 
                                  WS_OVERLAPPEDWINDOW, 100, 100, 300, 300,
                                  NULL, NULL, wc.hInstance, NULL );
    
        // Initialize Direct3D
        if( SUCCEEDED( InitD3D( hWnd ) ) ) ....
    

    Mit dem so

    Form ^frm = gcnew Form();
    frm->Show();
    

    erzeugten Fenster weiß ich nicht, welchen HWND Parameter ich InitD3D übergeben kann.

    Zugegeben:
    Der DirectX Code ist nicht managed sondern native C++.
    Von managed DirectX wurde mir allerdings abgeraten.

    Meine neuen Fragen lauten daher:
    1. Ist auch bereits von einer Kombination Managed Code und nativ C++ ausschließlich für DirectX abzuraten?
    2. Wenn 1. = nein: Welchen Parameter der Sorte HWND kann ich dann InitD3D übergeben, damit DirectX in das mit gcnew Form() erzeugte Fenster reinschreibt.
    3. Wenn 1. = ja: Welche (möglichst anfängerfreundliche) Alternativen bleiben dann zur Erstellung einer Anwendung mit DirectX, die aber im wesentlichen ein "normales" Windows-Fenster (also nicht Fullscreen, mit ein paar Eingabefeldern und Buttons...) verwendet?

    Danke und Gruß!



  • dong schrieb:

    Der DirectX Code ist nicht managed sondern native C++.

    Ich Rate Dir davon ab managed-Code mit Unmanaged DirectX zu verwenden. Da wirst Du nur mit noch mehr Probleme zu kämpfen haben als schon ohne managed.

    dong schrieb:

    Von managed DirectX wurde mir allerdings abgeraten.

    Diese Meinung kann ich nicht teilen. Es ist immer eine Frage, mit was man sich auskennt. Wenn jemand schon native-DirectX kann, ist es immer leichter zu sagen, dass sich der Umstieg nicht lohnt.
    IMHO ist es managed aber viel "einfacher" und die Performance ist fast gleich.
    Also ich sehe keinen Grund in einem Windows-Forms Applikation managed DirectX nicht zu verwenden...

    PS: Um an das Handle des Fensters zu kommen, kannst Du einfach "frm->Handle" verwenden. Ob das allerdings mit unmanaged DirectX geht, mag ich zu bezweifeln.



  • Na gut, dann werde ich mir die Managed Sache etwas näher ansehen....

    Ist halt nur blöd, weil

    • ich den DirectX Teil quasi schon fertig habe, und zwar in native C++,
    • ich Managed DirectX noch nicht kenne und zusätzlich
    • alle Beispiele des DirectX SDKs in managed Code in C# statt in C++ geschrieben sind, was ich auch noch nicht kenne....

    Daher will ich der möglicherweise etwas unsauberen Alternative (aber nur etwas: Die Fenster des managed Bereichs und des nativ Bereichs sind ja getrennt...) noch eine Chance geben und hake hier mal nach:

    Jochen Kalmbach schrieb:

    PS: Um an das Handle des Fensters zu kommen, kannst Du einfach "frm->Handle" verwenden. Ob das allerdings mit unmanaged DirectX geht, mag ich zu bezweifeln.

    Das ist mir leider nicht gelungen, wahrscheinlich habe ich es falsch verstanden.
    Ich probierte folgendes:

    private: System::Void button1_Click(System::Object^  sender, System::EventArgs^  e) {
    
    				Form ^frm = gcnew Form();
    				frm->Show();
    				HWND hWnd = frm->Handle; // Das ist Zeile 105
    			 }
    

    und erhielt:

    Form1.h(105) : error C2440: 'initializing' : cannot convert from 'System::IntPtr' to 'HWND'
    No user-defined-conversion operator available that can perform this conversion, or the operator cannot be called]

    Und wie kann ich das also konvertieren? Oder geht das ganz anders?

    Danke und Gruß!



  • Du kommst um ein casten nicht drum rum...

    HWND hWnd = (HWND) frm->Handle.ToPointer();
    


  • Jochen Kalmbach schrieb:

    Du kommst um ein casten nicht drum rum...

    HWND hWnd = (HWND) frm->Handle.ToPointer();
    

    Danke schön, ich wußte noch nicht, wie das "casten" geht.

    Damit läßt sich der Code kompilieren, aber eine Ausführung des ganzen führt zu einem Fehler.

    Wahrscheinlich muss ich dann wohl doch in den sauren Apfel beißen und mich mit managed C# (/ managed C# für DirectX) anfreunden...

    Form1.h:

    #pragma once
    #include <windows.h> 
    #include <d3d9.h>
    
    //-----------------------------------------------------------------------------
    // Global variables
    //-----------------------------------------------------------------------------
    LPDIRECT3D9             g_pD3D       = NULL; // Used to create the D3DDevice
    LPDIRECT3DDEVICE9       g_pd3dDevice = NULL; // Our rendering device
    
    ....
    ....
    
    private: System::Void button1_Click(System::Object^  sender, System::EventArgs^  e) {
    
    				Form ^frm = gcnew Form();
    				frm->Show();
    				HWND hWnd = (HWND) frm->Handle.ToPointer();
    
    				D3DPRESENT_PARAMETERS d3dpp; 
    				ZeroMemory( &d3dpp, sizeof(d3dpp) );
    				d3dpp.Windowed = TRUE;
    				d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;
    				d3dpp.BackBufferFormat = D3DFMT_UNKNOWN;
    
    				g_pD3D->CreateDevice( D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, hWnd,
                                          D3DCREATE_SOFTWARE_VERTEXPROCESSING,
                                           &d3dpp, &g_pd3dDevice); //das ist Zeile 108
    			 }
    

    führt beim Anwenden zu folgender Fehlermeldung:

    Unhandeled exeption has occured in your application.
    ....
    Details:
    ************** Exception Text **************
    System.NullReferenceException: Object reference not set to an instance of an object.
    at pureWFA.Form1.button1_Click(Object sender, EventArgs e) in f:\....\form1.h:line 108
    at System.Windows.Forms.Control.OnClick(EventArgs e)
    at System.Windows.Forms.Button.OnClick(EventArgs e)
    at System.Windows.Forms.Button.OnMouseUp(MouseEventArgs mevent)
    at System.Windows.Forms.Control.WmMouseUp(Message& m, MouseButtons button, Int32 clicks)
    at System.Windows.Forms.Control.WndProc(Message& m)
    at System.Windows.Forms.ButtonBase.WndProc(Message& m)
    at System.Windows.Forms.Button.WndProc(Message& m)
    at System.Windows.Forms.Control.ControlNativeWindow.OnMessage(Message& m)
    at System.Windows.Forms.Control.ControlNativeWindow.WndProc(Message& m)
    at System.Windows.Forms.NativeWindow.Callback(IntPtr hWnd, Int32 msg, IntPtr wparam, IntPtr lparam)

    Trotzdem Danke soweit! 🙂



  • Noch eine ganz dumme Frage:

    Ist MFC auch managed?
    Sonst könnte ich ja auch MFC statt CLR verwenden...



  • dong schrieb:

    Ist MFC auch managed?

    MFC ist Prinzipiell unmanaged (man kann sie aber auch mit /clr übersetzen und Windows-Forms in MFC verwenden 😉 )

    dong schrieb:

    Sonst könnte ich ja auch MFC statt CLR verwenden...

    MFC ist aber nicht bei der VC2005 Express-Edition dabei...

    Die Frage ist: Warum verwendet der OP nicht WinAPI?????



  • Jochen Kalmbach schrieb:

    dong schrieb:

    Ist MFC auch managed?

    MFC ist Prinzipiell unmanaged (man kann sie aber auch mit /clr übersetzen und Windows-Forms in MFC verwenden 😉 )

    Sehr schön, ich sehe, Du hast meinen Versuch auch schon gefunden...

    Jochen Kalmbach schrieb:

    dong schrieb:

    Sonst könnte ich ja auch MFC statt CLR verwenden...

    MFC ist aber nicht bei der VC2005 Express-Edition dabei...

    Die Frage ist: Warum verwendet der OP nicht WinAPI?????

    Ich kann eine Vollversion verwenden.
    Und Deine Frage habe ich leider nicht verstanden...(siehe Signatur..;)) 😕

    Gruß,
    Dong



  • dong schrieb:

    Und Deine Frage habe ich leider nicht verstanden...(siehe Signatur..;)) 😕

    Warum verwendest Du Windows-Forms, wenn Du den DirectX-Part schon in unmanaged C++ gemacht hast?
    Windows-Forms ist C++/CLI mit managed-Code.
    MFC ist (i.d.R.) unmanaged Code; und dann sollte es auch keine Probleme mit der native DirectX-Anbindung geben.



  • dong schrieb:

    das hat aber leider nicht geholfen:

    Jetzt verwende ich

    HWND hWnd = CreateWindow( "Fensterklasse", L"Fenstername", // das ist immernoch Zeile 95
                                  WS_OVERLAPPEDWINDOW, 100, 100, 300, 300,
                                  NULL, NULL, NULL, NULL );
    

    und beim builden erhalte ich immer noch

    Form1.h(95) : error C2664: 'CreateWindowExW' : cannot convert parameter 2 from 'const char [14]' to 'LPCWSTR'
    Types pointed to are unrelated; conversion requires reinterpret_cast, C-style cast or function-style cast
    Generating Code...

    Was jetzt?

    Hallo, habe auch gerade an dem Problem rumgeknabbert, immer nur den Fehler C2664 zu bekommen, wenn ich einen Button machen wollte. Die Lösung ist:

    HWND hWnd = CreateWindow( L"Fensterklasse", L"Fenstername", // das ist immernoch Zeile 95
                                  WS_OVERLAPPEDWINDOW, 100, 100, 300, 300,
                                  NULL, NULL, NULL, NULL );
    

    also auch ein L vor "Fensterklasse". Er sagt zwar "Parameter 2" in der Fehlermeldung, meint aber "Parameter 1", weil er sich ja auf CreateWindowExW bezieht und nicht auf CreateWindow, wo "LPCTSTR lpClassName" Parameter Nr.1 statt Nr.2 wäre. Kann man auch daran sehen, daß er nicht char[12] sondern char[14] sagt, also die Länge 13 von "Fensterklasse", also dem ersten Parameter, zzgl +1 für die 0.

    Das kommt davon, weil "Microsoft Visual C++ 2005 Express Edition" defaultmäßig überall Unicode erwartet. Also muß man ständig mit L und (LPWSTR) rumcasten. Hier ein paar Tips dazu:http://www.a-m-i.de/tips/strings/strings.php

    Man kann das aber auch abstellen, wenn man am Anfang des Projektes im Menü unter: Projekt/MeinProg-Eigenschaften/Konfigurationseigenschaften/Allgemein
    den Parameter "Zeichensatz" von "Unicode-Zeichensatz verwenden" auf "Nicht festgelegt" umstellt.



  • Kurze Frage nebenbei (passt gerade zum Thema):
    Ist denn managed directx im aktuellen SDK schon wieder unterstützt?
    Das wurde doch leider herausgenommen und die älteren Versionen sind mit einer Timebomb Ausnahme versehen.
    Oder geht es hier um die alte Version (also v1 - ich weiss nicht mehr genau, wie das hiess - habe mich nur damit befasst... bis zur timebomb).
    Managed directx soll doch dann in das neue SDK kommen (XNA) - nur leider unterstützt dieses bisher nur c#, soweit ich weiss.


Anmelden zum Antworten