[C++/win32] Dialog uit .rc file gebruiken als main?

Pagina: 1
Acties:

  • tdm
  • Registratie: Juli 2002
  • Laatst online: 25-01 12:21
Ik ben sinds kort begonnen met het leren van C++ i.c.m. de Win32 API te programmeren, maar nou wil ik een dialog die ik in het .rc bestand heb gemaakt gebruiken als het hoofdvenster van het programma.

Hoe kan ik dit doen?

  • .oisyn
  • Registratie: September 2000
  • Laatst online: 15:56

.oisyn

Moderator Devschuur®

Demotivational Speaker

CreateDialog () of DialogBox () :?

[ Voor 31% gewijzigd door .oisyn op 25-04-2004 20:12 ]

Give a man a game and he'll have fun for a day. Teach a man to make games and he'll never have fun again.


  • tdm
  • Registratie: Juli 2002
  • Laatst online: 25-01 12:21
Oke, ik heb CreateDialog even geprobeerd en nou krijg ik de volgende foutmelding:

code:
1
2
error C2664: 'CreateDialogParamA' : cannot convert parameter 4 from 'int (struct HWND__ *, unsigned int, unsigned int,long)' to 'int (__stdcall *) (struct HWND__ *, unsigned int, unsigned in
t,long)'


Bij de volgende code:
code:
1
m_hWnd = CreateDialog( this->m_hInstance, MAKEINTRESOURCE( IDF_MAIN ), NULL, DialogProc );

Terwijl ik de DialogProc toch goed gedefinieerd heb (C&P uit MSDN :)):
code:
1
2
3
BOOL CALLBACK DialogProc( HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam )
{
}


Enig idee?

  • .oisyn
  • Registratie: September 2000
  • Laatst online: 15:56

.oisyn

Moderator Devschuur®

Demotivational Speaker

vervang dat CALLBACK eens door __stdcall?

Give a man a game and he'll have fun for a day. Teach a man to make games and he'll never have fun again.


  • tdm
  • Registratie: Juli 2002
  • Laatst online: 25-01 12:21
nog steeds dezelfde foutmelding

  • .oisyn
  • Registratie: September 2000
  • Laatst online: 15:56

.oisyn

Moderator Devschuur®

Demotivational Speaker

Ik vind het maar vaag, als ik je code gebruik dan werkt het perfect. Welke VC++ gebruik je?

[ Voor 16% gewijzigd door .oisyn op 25-04-2004 21:23 ]

Give a man a game and he'll have fun for a day. Teach a man to make games and he'll never have fun again.


  • tdm
  • Registratie: Juli 2002
  • Laatst online: 25-01 12:21
Ms Visual C++ 6.0 Enterprise Edition

Ik vind het ook raar, want enkele voorbeeld codes die ik van het internet heb geplukt werken ook niet.. die geven een melding als:
code:
1
2
LIBCD.lib(crt0.obj) : error LNK2001: unresolved external symbol _main
Debug/sample.exe : fatal error LNK1120: 1 unresolved externals


Terwijl eerdere Win32 testjes die ik heb gedaan geen problemen hebben met de WinMain entry

Dus ik weet niet of het aan mijn versie ligt, ik krijg precies dezelfde foutmeldingen op 2 verschillende PC's (beiden wel dezelfde VC++ versie), maar lijkt mij iets met de code te maken hebben :(

[ Voor 101% gewijzigd door tdm op 25-04-2004 21:44 . Reden: aanvulling ]


  • tdm
  • Registratie: Juli 2002
  • Laatst online: 25-01 12:21
Oke, ik post mijn basis code wel ff...
Misschien dat je daar wat verkeerds aan kunt zien.

C++:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
//////////////////////////////////////////////////////////////////
//////         WIN.H
//////////////////////////////////////////////////////////////////
#ifndef WIN_H
#define WIN_H

#include <windows.h>


class CWin
{
protected:
    static HINSTANCE m_hInstance;
    HWND  m_hWnd;
    
    DWORD m_PosX;
    DWORD m_PosY;
    TCHAR * m_strClassName;
    DWORD m_dwWindowStyle;
    DWORD m_dwExWindowStyle;
    DWORD m_dwCreationFlags;
    DWORD m_dwCreationHeight;
    DWORD m_dwCreationWidth;
    TCHAR * m_strWindowTitle;
    HBRUSH m_hbrWindowColor;
    HICON  m_hIcon;
    HMENU  m_hMenu;
    HACCEL m_hAccelTable;

public:
     CWin();
     HRESULT Create();
     int Run();
     virtual ~CWin();
     virtual LRESULT MsgProc( HWND, UINT, WPARAM, LPARAM );
     virtual BOOL CALLBACK DlgProc( HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam );
};

#endif


//////////////////////////////////////////////////////////////////
//////         WIN.CPP
//////////////////////////////////////////////////////////////////

#include "Win.h"
#include <tchar.h>

#include "resource.h"

//////////////////////////////////////////////////////////////////
// Static Initialisatie
//////////////////////////////////////////////////////////////////
static CWin * g_pCWin       = NULL;
HINSTANCE CWin::m_hInstance = GetModuleHandle(NULL);

//////////////////////////////////////////////////////////////////
// Koppeling WIN32 -> Klasse
//////////////////////////////////////////////////////////////////
LRESULT CALLBACK WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
    return g_pCWin->MsgProc(hWnd, uMsg, wParam, lParam);
}

//////////////////////////////////////////////////////////////////
// Constructors/Destructors
//////////////////////////////////////////////////////////////////
CWin::CWin()
{
    g_pCWin      = this;

    this->m_hWnd = NULL;
    this->m_strClassName     = "TijdReg";
    this->m_dwWindowStyle    = WS_OVERLAPPEDWINDOW;
    this->m_dwExWindowStyle  = WS_EX_OVERLAPPEDWINDOW;
    this->m_dwCreationFlags  = SW_SHOW;
    this->m_PosX             = CW_USEDEFAULT;   
    this->m_PosY             = CW_USEDEFAULT;   
    this->m_dwCreationWidth  = CW_USEDEFAULT;
    this->m_dwCreationHeight = CW_USEDEFAULT;
    this->m_hbrWindowColor   = (HBRUSH)(COLOR_WINDOW+1);
    this->m_hIcon            = LoadIcon(m_hInstance, (LPCTSTR)IDI_APPLICATION);
    this->m_strWindowTitle   = _T("TijdReg");
    this->m_hMenu            = NULL;    
}

CWin::~CWin()
{
}


//////////////////////////////////////////////////////////////////
// Methoden
//////////////////////////////////////////////////////////////////
int CWin::Run()
{
    MSG msg;

    while (GetMessage(&msg, NULL, 0, 0)) 
    {
        if (!TranslateAccelerator(msg.hwnd, m_hAccelTable, &msg)) 
        {
            TranslateMessage(&msg);
            DispatchMessage(&msg);
        }

    }   return msg.wParam;
}

HRESULT CWin::Create()
{
    WNDCLASSEX wcex;

    wcex.cbSize = sizeof(WNDCLASSEX); 

    wcex.style          = CS_HREDRAW | CS_VREDRAW;
    wcex.lpfnWndProc    = (WNDPROC)WndProc;
    wcex.cbClsExtra     = 0;
    wcex.cbWndExtra     = 0;
    wcex.hInstance      = m_hInstance;
    wcex.hIcon          = m_hIcon;
    wcex.hCursor        = LoadCursor(NULL, IDC_ARROW);
    wcex.hbrBackground  = m_hbrWindowColor;
    wcex.lpszMenuName   = NULL;
    wcex.lpszClassName  = _T("TijdReg");
    wcex.hIconSm        = NULL;

    ::RegisterClassEx(&wcex);

//  m_hWnd = ::CreateWindowEx(m_dwExWindowStyle, this->m_strClassName, m_strWindowTitle, m_dwWindowStyle,
//    m_PosX, m_PosY, m_dwCreationWidth, m_dwCreationHeight, NULL, m_hMenu, m_hInstance, NULL);

    m_hWnd = CreateDialog( this->m_hInstance, MAKEINTRESOURCE( IDF_MAIN ), NULL, DlgProc );

    if (!m_hWnd)
    {
        MessageBox( NULL, "Failed to create window", "Error", 0 );
        return FALSE;
    }

    ::ShowWindow(m_hWnd, m_dwCreationFlags);
    ::UpdateWindow(m_hWnd);

    return TRUE;

}

LRESULT MsgProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
    int wmId;
    int wmEvent;

    if (!m_hWnd)
        m_hWnd = hWnd;

    switch (uMsg) 
    {
        case WM_COMMAND:
            wmId    = LOWORD(wParam); 
            wmEvent = HIWORD(wParam); 
            break;
        case WM_DESTROY:
            PostQuitMessage(0);
            break;
        default:
            return DefWindowProc(hWnd, uMsg, wParam, lParam);
   }
   return 0;
}

BOOL CALLBACK DlgProc( HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam )
{
    switch( message )
    {
        case WM_INITDIALOG:
            return FALSE;
    }
    return TRUE;
}

  • .oisyn
  • Registratie: September 2000
  • Laatst online: 15:56

.oisyn

Moderator Devschuur®

Demotivational Speaker

tdm schreef op 25 april 2004 @ 21:31:
Ms Visual C++ 6.0 Enterprise Edition

Ik vind het ook raar, want enkele voorbeeld codes die ik van het internet heb geplukt werken ook niet.. die geven een melding als:
code:
1
2
LIBCD.lib(crt0.obj) : error LNK2001: unresolved external symbol _main
Debug/sample.exe : fatal error LNK1120: 1 unresolved externals


Terwijl eerdere Win32 testjes die ik heb gedaan geen problemen hebben met de WinMain entry
dat is het verschil tussen een console applicatie en een GUI applicatie. Dan moet je het subsystem wijzigen bij je linker settings

Give a man a game and he'll have fun for a day. Teach a man to make games and he'll never have fun again.


  • tdm
  • Registratie: Juli 2002
  • Laatst online: 25-01 12:21
.oisyn schreef op 25 april 2004 @ 21:58:
[...]


dat is het verschil tussen een console applicatie en een GUI applicatie. Dan moet je het subsystem wijzigen bij je linker settings
Oke, thanks!
1 probleem opgelost :)

Nou me CreateDialog probleem nog :'(

  • .oisyn
  • Registratie: September 2000
  • Laatst online: 15:56

.oisyn

Moderator Devschuur®

Demotivational Speaker

Dat is gewoon krom, dat hoort niet. Werkt het als je &DlgProc gebruikt? Dus de & ervoor als je 'm passed als parameter?

En probeer anders eens expliciet te casten naar DLGPROC

Give a man a game and he'll have fun for a day. Teach a man to make games and he'll never have fun again.


  • MSalters
  • Registratie: Juni 2001
  • Laatst online: 09-04 22:08
Functions decayen naar pointers in expressies, dus DlgProc==&DlgProc. Dat zal het probeelm niet zijn. Een cast levert ernstige problemen op, je negeert actief een verschil in calling conventies. Dat is nooit gezond. De suggestie om BOOL CALLBACK DlgProc te vervangen door BOOL __stdcall DlgProc lijkt me wel zinnig.

Man hopes. Genius creates. Ralph Waldo Emerson
Never worry about theory as long as the machinery does what it's supposed to do. R. A. Heinlein


  • Dim
  • Registratie: Januari 2000
  • Laatst online: 09-05 19:58

Dim

Het probleem is dat jouw DialogProc functie een non-static member is van je CWin class. Dat kan helaas niet voor callback functies zoals event handlers, dat moeten namelijk altijd globaal benaderbare functies zijn, terwijl je een class member functie alleen kunt aanspreken als je een object (en dus een this pointer) hebt.

Probeer de methode die je hebt gebruikt voor de gewone WndProc, namelijk een globale wrapper functie die g_pcWin->MsgProc aanroept, ook voor je DlgProc, dus zo:
C++:
1
2
3
4
5
6
7
//////////////////////////////////////////////////////////////////
// Nog zo'n koppeling van Win32 -> klasse
//////////////////////////////////////////////////////////////////
LRESULT CALLBACK DlgProcWrapper(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
    return g_pCWin->DlgProc(hWnd, uMsg, wParam, lParam);
}


En dan later bij de CreateDialog de globale wrapper functie meegeven:
C++:
1
m_hWnd = CreateDialog( m_hInstance, MAKEINTRESOURCE( IDF_MAIN ), NULL, DlgProcWrapper );


Overigens, het is een beetje onzin om RegisterClass te gaan doen, want dat is helemaal niet nodig voor CreateDialog en dialog boxes in het algemeen. Je zou zelfs heel simpel kunnen doen:
C++:
1
2
3
4
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPTSTR lpCmdLine, int nCmdShow)
{
    return DialogBox(hInstance, MAKEINTRESOURCE(IDF_MAIN), NULL, DlgProcWrapper);
}


maar ik weet natuurlijk niet wat je wilt bereiken. :)

My other computer is your windows box.


  • tdm
  • Registratie: Juli 2002
  • Laatst online: 25-01 12:21
MSalters schreef op 25 april 2004 @ 22:23:
Functions decayen naar pointers in expressies, dus DlgProc==&DlgProc. Dat zal het probeelm niet zijn. Een cast levert ernstige problemen op, je negeert actief een verschil in calling conventies. Dat is nooit gezond. De suggestie om BOOL CALLBACK DlgProc te vervangen door BOOL __stdcall DlgProc lijkt me wel zinnig.
BOOL __stdcall DlgProc en &DlgProc helpen ook niet.

Ik zie net dat de foutmelding eigenlijk 1 regel langer is 8)7
Dus hier dan de volledige foutmelding:
C++:
1
2
3
win.cpp(86) : error C2664: 'CreateDialogParamA' : cannot convert parameter 4 from 'int (struct HWND__ *,unsigned int,unsigned int,long)' to 'int (__stdcall *)(struct HWND__ *,unsigned int,unsigned i
nt,long)'
        None of the functions with this name in scope match the target type

  • .oisyn
  • Registratie: September 2000
  • Laatst online: 15:56

.oisyn

Moderator Devschuur®

Demotivational Speaker

MSalters schreef op 25 april 2004 @ 22:23:
Functions decayen naar pointers in expressies, dus DlgProc==&DlgProc. Dat zal het probeelm niet zijn. Een cast levert ernstige problemen op, je negeert actief een verschil in calling conventies. Dat is nooit gezond. De suggestie om BOOL CALLBACK DlgProc te vervangen door BOOL __stdcall DlgProc lijkt me wel zinnig.
Dat is juist het hele probleem, die CALLBACK is gewoon een macro voor __stdcall, dus het zou moeten werken, maar dat was het dus ook niet. Vandaar ook dat ik hier zei dat het krom was, maar ja, VC++ 6.0 he ;)

Ik vermoedde een thiscall, maar de compiler laat dat meestal zien met een __thiscall calling convention, dus ik dacht dat het dat niet zou zijn. Nu ik naar z'n gehele code kijk zie ik idd dat het daaraan ligt

tdm: Je functie is niet static, hij is verbonden aan een object. Die kun je dus niet zomaar converteren naar een statische functie. Declareer 'm dus als static. Je zult dan helaas wel wat werk moeten doen om de juiste CWin instance bij de HWND te vinden. Opties zijn userdata in de window-long (Get-/SetWindowLong), een lookuptable (bijvoorbeeld een std::map[nohtml]<HWND, CWin *>), of zogenaamde thunks (een stukje asm code gecodeerd als memberdata die je gebruikt als windowproc, dus vervolgens de this pointer op de stack pusht en een algemene functie aanroept zodat je de CWin * ook gewoon als parameter in je windowproc hebt. Voor de gevorderden ;))

.edit: euh wat Dim ook al zei dus ;)
Dim schreef op 25 april 2004 @ 22:42:
Het probleem is dat jouw DialogProc functie een non-static member is van je CWin class. Dat kan helaas niet voor callback functies zoals event handlers, dat moeten namelijk altijd globaal benaderbare functies zijn, terwijl je een class member functie alleen kunt aanspreken als je een object (en dus een this pointer) hebt.

Probeer de methode die je hebt gebruikt voor de gewone WndProc, namelijk een globale wrapper functie die g_pcWin->MsgProc aanroept, ook voor je DlgProc, dus zo:
C++:
1
2
3
4
5
6
7
//////////////////////////////////////////////////////////////////
// Nog zo'n koppeling van Win32 -> klasse
//////////////////////////////////////////////////////////////////
LRESULT CALLBACK DlgProcWrapper(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
    return g_pCWin->DlgProc(hWnd, uMsg, wParam, lParam);
}


En dan later bij de CreateDialog de globale wrapper functie meegeven:
C++:
1
m_hWnd = CreateDialog( m_hInstance, MAKEINTRESOURCE( IDF_MAIN ), NULL, DlgProcWrapper );
Twee "fouten" aan deze aanpak. Of tenminste, de eerste is echt fout, de tweede is meer dat het gewoon niet netjes is ;)

CreateDialog returnt een hWnd, die je vervolgens kunt assignen. Echter, er worden al window messages verzonden naar je windowproc voordat CreateDialog retourneert, zoals WM_CREATE voor een window, en WM_INITDIALOG voor een dialog. Aangezien de pointer dan naar iets anders wijst naar de juiste window gaat dit fout (typisch een access violation als je voor het eerst een window aanmaakt in je app)

De tweede fout is niet echt een technische fout, maar meer ontwepfout: je kunt met een globale pointer namelijk maar 1 window tegelijk hebben, wat niet altijd iets is dat je wilt :)
Overigens, het is een beetje onzin om RegisterClass te gaan doen, want dat is helemaal niet nodig voor CreateDialog en dialog boxes in het algemeen.
Maar wel voor CreateWindow uiteraard. En aangezien de aanroep naar CreateWindow er ook in staat maar uitgecomment is, denk ik dat ie het registreren van de class ook simpelweg is vergeten uit te commenten ;)

[ Voor 45% gewijzigd door .oisyn op 25-04-2004 23:36 ]

Give a man a game and he'll have fun for a day. Teach a man to make games and he'll never have fun again.

Pagina: 1