Twitter iPhone pliant OnePlus 11 PS5 Disney+ Orange Livebox Windows 11

Intégrer une fonction WNDPROC dans une classe

5 réponses
Avatar
Miel
Bonjour,

Je souhaiterai intégrer une fonction WndProc à l'intérieur d'une classe
et la compilation me jette comme une merde à l'appel de la fonction
SetWindowLong .
Je refuse d'utiliser le MFC et l'afx , c'est trop lourd comme interface.
J'aurais besoin de votre aide pour corriger cet erreur C2440 sans
exclure le WndProc à l'extérieur de la classe

Franchement merci bcp

1>------ Build started: Project: cast2, Configuration: Debug Win32 ------
1>Compiling...
1>cast2.cpp
1>f:\projet\vc\recherche\cast2\cast2\cast2.cpp(30) : error C2440:
'reinterpret_cast' : cannot convert from 'LRESULT (__stdcall TCroix::*
)(HWND,UINT,WPARAM,LPARAM)' to 'long'
1> There is no context in which this conversion is possible
1>Build log was saved at
"file://f:\Projet\vc\recherche\cast2\cast2\Debug\BuildLog.htm"
1>cast2 - 1 error(s), 0 warning(s)
========== Build: 0 succeeded, 1 failed, 0 up-to-date, 0 skipped ==========


Source listing :

// cast2.cpp : Defines the entry point for the application.
//

#include "stdafx.h"
#include "cast2.h"

#define MAX_LOADSTRING 100

// Global Variables:
HINSTANCE hInst; // current instance
TCHAR szTitle[MAX_LOADSTRING]; // The title bar text
TCHAR szWindowClass[MAX_LOADSTRING]; // the main window class name

// Forward declarations of functions included in this code module:
ATOM MyRegisterClass(HINSTANCE hInstance);
BOOL InitInstance(HINSTANCE, int);
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
INT_PTR CALLBACK About(HWND, UINT, WPARAM, LPARAM);

class TCroix
{
public:
TCroix();
LRESULT CALLBACK CroixMsgProc(HWND hwnd, UINT message, WPARAM wParam,
LPARAM lParam);
void attach(HWND w);
};

void TCroix::attach(HWND w)
{
reinterpret_cast<WNDPROC>(::SetWindowLong(w, GWL_WNDPROC,
reinterpret_cast<long>(CroixMsgProc)));
}

TCroix::TCroix()
{
WNDCLASSEX wcex;
wcex.cbSize = sizeof(WNDCLASSEX);
wcex.style = CS_HREDRAW | CS_VREDRAW;

//HeaderWndProcPtr = reinterpret_cast<LONG>(
MakeObjectInstance(ConsoleMsgProc) );

wcex.lpfnWndProc = DefWindowProc;
wcex.cbClsExtra = 0;
wcex.cbWndExtra = 0;
wcex.hInstance = GetModuleHandle(
0);
wcex.hIcon = 0;
wcex.hCursor = LoadCursor(NULL, IDC_ARROW);
wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
wcex.lpszMenuName = 0;
wcex.lpszClassName = "TCROIX";
wcex.hIconSm = 0;;
RegisterClassEx(&wcex);
}

LRESULT CALLBACK TCroix::CroixMsgProc(HWND hwnd, UINT message, WPARAM
wParam, LPARAM lParam)
{
if (message==WM_PAINT)
{

PAINTSTRUCT ps;
HDC hdc = BeginPaint(hwnd, &ps);
// TODO: Add any drawing code here...
RECT rc;
GetClientRect(hwnd,&rc);
MoveToEx(hdc,0,0,NULL);
LineTo(hdc,rc.right,rc.top);
MoveToEx(hdc,rc.right,0,NULL);
LineTo(hdc,0,rc.top);
EndPaint(hwnd, &ps);


}
return DefWindowProc(hwnd,message,wParam,lParam);
}

int APIENTRY _tWinMain(HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPTSTR lpCmdLine,
int nCmdShow)
{
UNREFERENCED_PARAMETER(hPrevInstance);
UNREFERENCED_PARAMETER(lpCmdLine);

// TODO: Place code here.
MSG msg;
HACCEL hAccelTable;

// Initialize global strings
LoadString(hInstance, IDS_APP_TITLE, szTitle, MAX_LOADSTRING);
LoadString(hInstance, IDC_CAST2, szWindowClass, MAX_LOADSTRING);
MyRegisterClass(hInstance);

// Perform application initialization:
if (!InitInstance (hInstance, nCmdShow))
{
return FALSE;
}

hAccelTable = LoadAccelerators(hInstance, MAKEINTRESOURCE(IDC_CAST2));

// Main message loop:
while (GetMessage(&msg, NULL, 0, 0))
{
if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}

return (int) msg.wParam;
}



//
// FUNCTION: MyRegisterClass()
//
// PURPOSE: Registers the window class.
//
// COMMENTS:
//
// This function and its usage are only necessary if you want this code
// to be compatible with Win32 systems prior to the 'RegisterClassEx'
// function that was added to Windows 95. It is important to call
this function
// so that the application will get 'well formed' small icons associated
// with it.
//
ATOM MyRegisterClass(HINSTANCE hInstance)
{
WNDCLASSEX wcex;

wcex.cbSize = sizeof(WNDCLASSEX);

wcex.style = CS_HREDRAW | CS_VREDRAW;
wcex.lpfnWndProc = WndProc;
wcex.cbClsExtra = 0;
wcex.cbWndExtra = 0;
wcex.hInstance = hInstance;
wcex.hIcon = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_CAST2));
wcex.hCursor = LoadCursor(NULL, IDC_ARROW);
wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
wcex.lpszMenuName = MAKEINTRESOURCE(IDC_CAST2);
wcex.lpszClassName = szWindowClass;
wcex.hIconSm = LoadIcon(wcex.hInstance, MAKEINTRESOURCE(IDI_SMALL));

return RegisterClassEx(&wcex);
}

//
// FUNCTION: InitInstance(HINSTANCE, int)
//
// PURPOSE: Saves instance handle and creates main window
//
// COMMENTS:
//
// In this function, we save the instance handle in a global
variable and
// create and display the main program window.
//
BOOL InitInstance(HINSTANCE hInstance, int nCmdShow)
{
HWND hWnd;

hInst = hInstance; // Store instance handle in our global variable

hWnd = CreateWindow(szWindowClass, szTitle, WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, NULL, NULL, hInstance, NULL);

if (!hWnd)
{
return FALSE;
}

ShowWindow(hWnd, nCmdShow);
UpdateWindow(hWnd);

return TRUE;
}

//
// FUNCTION: WndProc(HWND, UINT, WPARAM, LPARAM)
//
// PURPOSE: Processes messages for the main window.
//
// WM_COMMAND - process the application menu
// WM_PAINT - Paint the main window
// WM_DESTROY - post a quit message and return
//
//
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM
lParam)
{
int wmId, wmEvent;
PAINTSTRUCT ps;
HDC hdc;

switch (message)
{
case WM_CREATE:
{
TCroix *croix;
croix=new TCroix;
HWND h = CreateWindow("TCROIX", "SampleCroix", WS_CHILD | WS_VISIBLE |
ES_LEFT ,
10, 10, 100, 100, hWnd, NULL, hInst, NULL);
croix->attach(h);
}
break;

case WM_PAINT:
hdc = BeginPaint(hWnd, &ps);
// TODO: Add any drawing code here...
EndPaint(hWnd, &ps);
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
return 0;
}

5 réponses

Avatar
antoine
"Miel" wrote in message
news:4902ece5$0$885$
Bonjour,

Je souhaiterai intégrer une fonction WndProc à l'intérieur d'une classe et
la compilation me jette comme une merde à l'appel de la fonction
SetWindowLong .



demander sur fr.comp.os.ms-windows.programmation
Avatar
Sylvain SF
Miel a écrit :

Je souhaiterai intégrer une fonction WndProc à l'intérieur d'une classe
et la compilation me jette comme une merde à l'appel de la fonction
SetWindowLong .



la fonction castée ne serait pas incorrecte ?

Je refuse d'utiliser le MFC et l'afx , c'est trop lourd comme interface.



certes.

J'aurais besoin de votre aide pour corriger cet erreur C2440 sans
exclure le WndProc à l'extérieur de la classe



il ne s'agit pas de l'exclure mais plutôt de renforcer la définition
objet d'une abstraction de HWND, enfin je suppose que c'est le but
puisque vous postez ici.

1>cast2.cpp
1>f:projetvcrecherchecast2cast2cast2.cpp(30) : error C2440:
'reinterpret_cast' : cannot convert from 'LRESULT (__stdcall TCroix::*
)(HWND,UINT,WPARAM,LPARAM)' to 'long'



SetWindowLong attend un 'long' (un 'LONG' selon MS) en 3ième param.
le "reinterpret_cast<long>" part d'un bon sentiment pour il est
inapplicable ici car la winproc doit être statique.

HINSTANCE hInst; // current instance



c'est p.e. la seule globale nécessaire, et encore.

TCHAR szTitle[MAX_LOADSTRING]; // The title bar text



devrait être un attribut de la fenêtre en question

TCHAR szWindowClass[MAX_LOADSTRING]; // the main window class name



devrait être un attribut static de la classe en question.

// Forward declarations of functions included in this code module:
ATOM MyRegisterClass(HINSTANCE hInstance);
BOOL InitInstance(HINSTANCE, int);
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
INT_PTR CALLBACK About(HWND, UINT, WPARAM, LPARAM);

class TCroix {
public:
TCroix();
LRESULT CALLBACK CroixMsgProc(HWND, UINT, WPARAM, LPARAM);
void attach(HWND w);
};



abstraction un peu légere.

void TCroix::attach(HWND w)
{
reinterpret_cast<WNDPROC>(::SetWindowLong(w, GWL_WNDPROC,
reinterpret_cast<long>(CroixMsgProc)));
}



pour suivre qlq usages, "attach" devrait être utilisé quand
vous subclassez des classes (ATOM) existants, quand vous
définissez entièrement une fenêtre avec sa propre winproc,
vous n'attachez pas (un traitement à un existant) mais
"définissez" (ce traitement).

TCroix::TCroix() {
WNDCLASSEX wcex;
...
RegisterClassEx(&wcex);
}



c'est incorrect, l'inscription de la classe doit être fait
une seule fois dans la vie de votre appli. (pas pour chaque
instance), le résultat doit absolument être pris en compte
car s'il échoue rien ne fonctionnera.

LRESULT CALLBACK TCroix::CroixMsgProc(HWND hwnd, UINT message, WPARAM
wParam, LPARAM lParam)
{
if (message==WM_PAINT){
...
}
return DefWindowProc(hwnd,message,wParam,lParam);
}



ce distaching - et le traitement de WM_PAINT - est typiquement
un process générique, il devrait être défini dans une classe de
base; la méthode paint(HDC [, RECT&]) sera une des méthodes
virtuelles évidentes.

int APIENTRY _tWinMain(HINSTANCE hInstance,
HINSTANCE, LPTSTR, int nCmdShow)
{
MSG msg;
MyRegisterClass(hInstance);
if (!InitInstance (hInstance, nCmdShow))
return FALSE;

while (GetMessage(&msg, NULL, 0, 0)){
if (!TranslateAccelerator(msg.hwnd, hAccel, &msg)){
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
return (int) msg.wParam;
}




ATOM MyRegisterClass(HINSTANCE hInstance)
{
WNDCLASSEX wcex;
...
return RegisterClassEx(&wcex);
}



?! ça doublonne avec le constructor précédent.

BOOL InitInstance(HINSTANCE hInstance, int nCmdShow)
{
hInst = hInstance; // Store instance handle in our global variable
HWND hWnd = CreateWindow(szWindowClass, szTitle, WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, NULL, NULL, hInstance, NULL);
if (!hWnd)
return FALSE;
ShowWindow(hWnd, nCmdShow);
UpdateWindow(hWnd);
return TRUE;
}



ici vous êtes dans un schéma C hyper classique, vous ne traitez que
des variables opaques (HWND etc), votre scéma C++ devrait y être présent
une initialisation étant par définition virtuelle.

LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM
lParam)
{
PAINTSTRUCT ps;
HDC hdc;

switch (message){
case WM_CREATE:{
TCroix* croix = new TCroix;



le constructeur rejoue le registerClass qui échouera,
mais heureusement (?) vous ne le testez pas dans ce cstr
l'instance 'croix' devrait être stockée dans une liste
des fenêtres.

HWND h = CreateWindow("TCROIX", "SampleCroix",
WS_CHILD | WS_VISIBLE |ES_LEFT ,
10, 10, 100, 100, hWnd, NULL, hInst, NULL);



c'est la première fenêtre créé, elle ne peut pas être child
sans parent.

croix->attach(h);



ce subclassing tardif est dommage.

}
break;

case WM_PAINT:
hdc = BeginPaint(hWnd, &ps);
// TODO: Add any drawing code here...



typiquement un traitement virtuel.

EndPaint(hWnd, &ps);
break;
case WM_DESTROY:
PostQuitMessage(0);



typiquement un traitement pour la fenêtre principale
(le frame), donc pas générique pour toutes les fenêtres.

break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
return 0;
}




donc, pour "intégrer une WndProc à l'intérieur d'une classe",
ou introduire un peu de C++ dans le monde Win32:

// --------------------------------

#define null NULL /* ça c'est juste pour ne pas crier */

// --------------------------------

class Window {
protected:
HWND handle; // the window handle

public:
Window(){
handle = null;
}
virtual ~Window(){
onDestroy();
}

bool create(HWND parent, HMENU, int x, int y, int width, int height,
DWORD style, DWORD exStyle, const char* caption, int icoID = 0);

operator HWND() const { return handle; }

virtual RECT clientRect() const{
RECT rect = { 0, 0, 0, 0 };
if (handle)
::GetClientRect(handle, &rect);
return rect;
}

protected:
// settings
virtual void setWindowClass(WNDCLASSEX&) {}
virtual const char* getClassName() = null;
// behaviors
virtual void paint(HDC, const RECT& dirtyRect) {}

// event handlers
virtual void onDestroy(){
handle = null;
}
virtual bool onPaint(){
PAINTSTRUCT ps;
HDC hdc = ::BeginPaint(handle, &ps);
if (hdc){
paint(hdc, ps.rcPaint);
::EndPaint(handle, &ps);
}
return true;
}

// manage creation in respose to WM_CREATE
virtual bool onCreate() { return true; }
// allow to close instance in response to WM_CLOSE
virtual bool onClose() { return true; }
// manage boudaries of child items after WM_SIZE
virtual bool onSize(long type, int width, int height) { return false; }
// manage WM_COMMAND messages
virtual bool onCommand(UINT msg, HWND ctrl, UINT id) { return false; }
// manage all unhandled msgs
virtual bool handleEvent(UINT, WPARAM, LPARAM, long&) { return false; }
// translate msgs (mainly used by modal dlg)
virtual bool translateMsg(MSG&) { return false; }

// implementation
// init instance after succesful creation
virtual bool initWindow(HWND hWnd){
if (hWnd == null)
return false;
// store HWND structure
handle = hWnd;
// store reference to this instance into HWND struct
::SetWindowLong(handle, GWL_USERDATA, reinterpret_cast<LONG>(this));
return true;
}

static LRESULT __stdcall customProc(HWND, UINT, WPARAM, LPARAM);
friend class FrameWnd;
};

// --------------------------------

bool Window::create(HWND parent, HMENU menu, int x, int y, int width,
int height,
DWORD dwStyle, DWORD dwExStyle, const char* caption, int icoID)
{
// search existing registration for class's name
const char* className = getClassName();
WNDCLASSEX wndclass;
HINSTANCE instance = ::GetModuleHandle(null);
::ZeroMemory(&wndclass, sizeof(wndclass));
if (::GetClassInfoEx(instance, className, &wndclass) == 0){
// register a new window class
wndclass.cbSize = sizeof(wndclass);
wndclass.style = 0;
wndclass.lpfnWndProc = customProc;
wndclass.cbClsExtra = 0;
wndclass.cbWndExtra = 0;
wndclass.hInstance = instance;
wndclass.hIcon = (icoID == 0) ? null : (HICON)
::LoadImage(instance, MAKEINTRESOURCE(icoID), IMAGE_ICON,
::GetSystemMetrics(SM_CXICON),
::GetSystemMetrics(SM_CYICON), LR_SHARED);
// apply default cursor
wndclass.hCursor = ::LoadCursor(null, IDC_ARROW);
// apply default or colored-solid brush background
wndclass.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
wndclass.lpszMenuName = null;
wndclass.lpszClassName= className;
wndclass.hIconSm = (icoID == 0) ? null : (HICON)
::LoadImage(instance, MAKEINTRESOURCE(icoID), IMAGE_ICON,
::GetSystemMetrics(SM_CXSMICON),
::GetSystemMetrics(SM_CYSMICON), LR_SHARED);
// setup virtual attributes
setWindowClass(wndclass);
// register this class
if (::RegisterClassEx(&wndclass) == null)
return false;
}
// create this window
HWND wnd = ::CreateWindowEx(
dwExStyle, className, caption, dwStyle,
x, y, width, height, parent, menu, instance, this);
// init window (HWND struct is tested by initWindow)
if (!initWindow(wnd)){
onDestroy();
return false;
}
return true;
}

LRESULT CALLBACK Window::customProc(HWND hWnd, UINT msg, WPARAM wParam,
LPARAM lParam)
{
// WM_NCCREATE & WM_CREATE are called before instance initialisation
if (msg == WM_NCCREATE)
return ::DefWindowProc(hWnd, WM_NCCREATE, wParam, lParam);
if (msg == WM_CREATE){
// recover instance
Window* window = (Window*)
((CREATESTRUCT*) lParam)->lpCreateParams;
if (window == null)
return -1;
// store HWND in window instance
window->handle = hWnd;
// store reference to instance into HWND objet
::SetWindowLong(hWnd, GWL_USERDATA, (LONG) window);
// perform virtual creation
if (!window->onCreate())
return -1; // fail
return 0; // continue window creation
}

// recover target window
Window* window = reinterpret_cast<Window*>(
::GetWindowLong(hWnd, GWL_USERDATA));
if (window == null)
return ::DefWindowProc(hWnd, msg, wParam, lParam);

// message processing, all generic msg (mouse, keyboard, ...)
// should be processed hereafter to invoke a virtual process.
LRESULT result = FALSE; // result of processing
switch (msg){
case WM_DESTROY: // 0x0002
window->onDestroy();
return 0;
case WM_SIZE: // 0x0005
if (window->onSize((long) wParam, LOWORD(lParam), HIWORD(lParam)))
return 0;
break;
case WM_PAINT: // 0x000F
if (window->onPaint())
return 0;
break;
case WM_CLOSE: // 0x0010
// does window accept to be closed?
if (!window->onClose())
return 0;
::DestroyWindow(*window);
return 0;
case WM_COMMAND: // 0x0111
if (window->onCommand(HIWORD(wParam), (HWND) lParam, LOWORD(wParam)))
return 0;
break;
default:
// virtual message handling
if (window->handleEvent(msg, wParam, lParam, result))
return result;
}
// default msg handling
return ::DefWindowProc(hWnd, msg, wParam, lParam);
}

// --------------------------------

pour définir une fenetre child en croix:

class CrossWnd : public Window {
public:
CrossWnd() {}
~CrossWnd(){}

bool create(HWND parent, RECT& rect, int id, int style = 0)
{
return Window::create(parent, (HMENU) id,
rect.left, rect.top, rect.right, rect.bottom,
style | WS_CHILD, 0, null, 0);
}

protected:
// settings
virtual void setWindowClass(WNDCLASSEX& wndClass){
wndClass.style = CS_HREDRAW | CS_VREDRAW;
}
const char* getClassName() { return "CrossWindow"; }
// event handlers
virtual bool onSize(long type, int width, int height){
::UpdateWindow(*this);
return true;
}
// behaviors
void paint(HDC hdc, const RECT& dirtyRect){
RECT rc = clientRect();
HGDIOBJ old = ::SelectObject(hdc,
::CreatePen(PS_SOLID, 1, RGB(0,0,0)));
MoveToEx(hdc, 0, 0, null);
LineTo(hdc, rc.right, rc.bottom);
MoveToEx(hdc, 0, rc.bottom, null);
LineTo(hdc, rc.right, rc.top);
old = ::SelectObject(hdc, old);
::DeleteObject(old);
}
};

// --------------------------------

pour définir le cadre (SDI) principal

class FrameWnd : public Window {
protected:
Window* child;
HWND status;
long statusHeight;

public:
FrameWnd(){
child = null;
status = null;
statusHeight = 0;
}
virtual ~FrameWnd(){
if (child)
delete child;
}

bool create(const char* caption, int width = CW_USEDEFAULT, int
height = CW_USEDEFAULT,
int style = 0, UINT menuID = 0)
{
// apply styles for a frame window
DWORD dwStyle = style | WS_OVERLAPPEDWINDOW | WS_VISIBLE;
DWORD exStyle = WS_EX_APPWINDOW | WS_EX_DLGMODALFRAME |
WS_EX_WINDOWEDGE;
// apply default size
if (width == CW_USEDEFAULT)
width = 600;
if (height == CW_USEDEFAULT)
height = 400;
// load menu if any, accelerators, ...
HMENU menu = null;
if (menuID)
menu = ::LoadMenu(::GetModuleHandle(null),
MAKEINTRESOURCE(menuID));
// and finalize HWND creation
return Window::create(null, menu, 20, 20,
width, height, dwStyle, exStyle, caption);
}

virtual RECT clientRect() const {
RECT rect = { 0, 0, 0, 0 };
if (::GetClientRect(handle, &rect) && status != null){
RECT client;
::GetClientRect(status, &client);
rect.bottom -= client.bottom;
}
return rect;
}

virtual void run(){
for (;;){
MSG msg;
BOOL result = ::GetMessage(&msg, null, 0, 0);
if (result == 0)
break;
if (result == -1)
break;
if (!(child && child->translateMsg(msg))){
::TranslateMessage(&msg);
::DispatchMessage(&msg);
}
}
}

protected:
// virtual behaviors
virtual const char* getClassName() { return "FrameWindow"; }

virtual bool onCreate(){
if (!Window::onCreate())
return false;
// create status bar
status = ::CreateWindow(
STATUSCLASSNAME, "Ready", WS_VISIBLE | WS_CHILD,
CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
handle, (HMENU) 1001, ::GetModuleHandle(null), null);
if (status){
RECT rect;
::GetClientRect(status, &rect);
statusHeight = rect.bottom;
}
return true;
}

virtual void onDestroy(){
Window::onDestroy();
::PostQuitMessage(0);
}

virtual bool initWindow(HWND hWnd){
if (!Window::initWindow(hWnd))
return false;
RECT rc = clientRect();
CrossWnd* cross = new CrossWnd();
if (!cross->create(*this, rc, 101, WS_VISIBLE)){
delete cross;
return false;
}
child = cross;
return true;
}

virtual bool onSize(long type, int width, int height){
if (width == 0 || height == 0)
return false;
// move status bar along lower side
if (status)
::SetWindowPos(status, null, 0, height - statusHeight,
width, statusHeight, SWP_NOZORDER);
// resize child, if any
if (child){
height -= statusHeight;
::SetWindowPos(*child, null, 0, 0, width, height,
SWP_NOMOVE | SWP_NOZORDER | SWP_FRAMECHANGED);
}
return true;
}
};

// --------------------------------

pour jouer le tout

int __stdcall WinMain(HINSTANCE instance, HINSTANCE, LPSTR, int cmd)
{
INITCOMMONCONTROLSEX ctrl = {
sizeof(INITCOMMONCONTROLSEX), ICC_WIN95_CLASSES
};
::InitCommonControlsEx(&ctrl);

FrameWnd frame;
if (frame.create("SampleCroix"))
frame.run();
return 0;
}

Sylvain.
Avatar
James Kanze
On Oct 25, 10:54 am, Miel wrote:
Bonjour,

Je souhaiterai intégrer une fonction WndProc à l'intérieur
d'une classe et la compilation me jette comme une merde à
l'appel de la fonction SetWindowLong .



Ne connaissant cette fonction, c'est difficile à dire. Et ton
extrait de code n'est vraiment pas ce que j'appelle « minimal ».
Néanmoins...


1>------ Build started: Project: cast2, Configuration: Debug Win32 ------
1>Compiling...
1>cast2.cpp
1>f:projetvcrecherchecast2cast2cast2.cpp(30) : error C2440:
'reinterpret_cast' : cannot convert from 'LRESULT (__stdcall TCroix::*
)(HWND,UINT,WPARAM,LPARAM)' to 'long'



Je ne sais pas à quelle ligne ce message rapporte, mais il me
semble assez clair. Tu as un pointeur à une fonction membre
(c-à-d quelque chose du genre : &ClassName::functionName), et tu
essaies à le convertir à un long, ce qui n'est pas possible.
Dans l'ensemble, j'ai du mal à suivre ton code, parce qu'il se
sert de tellement des extensions Microsoft (probablement
nécessaire, si tu fais une GUI), mais...

1>        There is no context in which this conversion is possibl e
1>Build log was saved at
"file://f:Projetvcrecherchecast2cast2DebugBuildLog.htm"
1>cast2 - 1 error(s), 0 warning(s)
========== Build: 0 succeeded, 1 failed, 0 up-to-date , 0 skipped ==========

Source listing :

// cast2.cpp : Defines the entry point for the application.
//

#include "stdafx.h"
#include "cast2.h"

#define MAX_LOADSTRING 100

// Global Variables:
HINSTANCE hInst;                                                                // c urrent instance
TCHAR szTitle[MAX_LOADSTRING];                                  // The title bar text
TCHAR szWindowClass[MAX_LOADSTRING];                    // the main window class name

// Forward declarations of functions included in this code module:
ATOM                            MyRegisterCla ss(HINSTANCE hInstance);
BOOL                            InitInstance( HINSTANCE, int);
LRESULT CALLBACK        WndProc(HWND, UINT, WPARAM, LPARAM);
INT_PTR CALLBACK        About(HWND, UINT, WPARAM, LPARAM);

class TCroix
{
public:
        TCroix();
        LRESULT CALLBACK CroixMsgProc(HWND hwnd, UINT message, WP ARAM wParam,
LPARAM lParam);



Je ne sais pas ce que c'est ni LRESULT, ni CALLBACK, mais je
suppose que ce sont des macros, et qu'ici, tu déclares une
fonction membre.

        void attach(HWND w);
};



void TCroix::attach(HWND w)
{
        reinterpret_cast<WNDPROC>(::SetWindowLong(w, GWL_WNDPROC,
reinterpret_cast<long>(CroixMsgProc)));



Et ici, tu utilises le nom de cette fonction membre sans
l'appeler, ni explicitement en prendre l'adresse. Ce qui n'est
pas légal en C++. Mais il me semble avoir entendu dire que VC++
a une extensionn qui le permet. Dans ce cas-là, et que mon
soupçon ci-dessus sur la declaration de CroixMsgProc est
correct, c'est ici l'erreur. Je ne sais pas ce que tu essaies de
faire, mais c'est sur que avec les coups de reinterpret_cast, ça
ne va pas marcher, même si tu réussis à le faire avaler par le
compilateur. (Mais dans ce cas-ci, je ne vois pas du tout
comment tu t'attends à ce que ça marche. Un pointeur à fonction
membre est prèsque toujours plus grand qu'un long, et contient
plus d'information que ne peut contenir un long. C'est donc
impossible que la conversion marche.)

J'ai jeté un coup d'oeil à la documentation de SetWindowLong ;
malheureusement, ce n'en est pas clair ce que signifie ce long
qu'on positionne. (Je me démande si ce n'est pas une information
client, ce pour laquelle beaucoup de fonctions utilise un void*.
Si c'est le cas, et l'information client que tu veux maintenir,
c'est un pointeur à fonction membre, il n'y a pas d'autre
solution que de créer et gérer un map entre les long et les
pointeurs.)

--
James Kanze (GABI Software) email:
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34
Avatar
Sylvain SF
James Kanze a écrit :

void TCroix::attach(HWND w)
{
reinterpret_cast<WNDPROC>(::SetWindowLong(w, GWL_WNDPROC,
reinterpret_cast<long>(CroixMsgProc)));



Et ici, tu utilises le nom de cette fonction membre sans
l'appeler, ni explicitement en prendre l'adresse. Ce qui n'est
pas légal en C++. Mais il me semble avoir entendu dire que VC++
a une extensionn qui le permet. Dans ce cas-là, et que mon
soupçon ci-dessus sur la declaration de CroixMsgProc est
correct, c'est ici l'erreur.



le cast sur le retour est inutile.
le cast sur le paramètre est invalide car la méthode
est non statique (comme tu l'indiquais plus haut).

ici le PO veux simplement faire:

::SetWindowLong(w, GWL_WNDPROC, (long) CroixMsgProc);

où le 3ième paramètre est l'adresse d'une méthode définie comme:

static long __stdcall CroixMsgProc(HWND,
unsigned int, unsigned int, long);

HWND est une structure opaque, __stdcall un modifier
appliquant la convention d'appel "standard" de microsoft,
à savoir:
<quote>
STDCALL passes arguments right-to-left, and returns the value in eax.
The called function cleans the stack, unlike CDECL. This means that
STDCALL doesn't allow variable-length argument lists.
</quote>

J'ai jeté un coup d'oeil à la documentation de SetWindowLong ;
malheureusement, ce n'est pas clair ce que signifie ce long
qu'on positionne.



en effet cela (ce 3ième param.) peut être très différent (un int
16 ou 32 bits ou un pointeur de fonction selon le 2nd param.)
(avec évidemment aucun contrôle de type possible, comme cela
n'est pas rare avec les APIs MS).

Sylvain.
Avatar
James Kanze
On Oct 26, 4:19 pm, Sylvain SF wrote:
James Kanze a écrit :
>> void TCroix::attach(HWND w)
>> {
>> reinterpret_cast<WNDPROC>(::SetWindowLong(w, GWL_WNDPROC,
>> reinterpret_cast<long>(CroixMsgProc)));



> Et ici, tu utilises le nom de cette fonction membre sans
> l'appeler, ni explicitement en prendre l'adresse. Ce qui
> n'est pas légal en C++. Mais il me semble avoir entendu dire
> que VC++ a une extensionn qui le permet. Dans ce cas-là, et
> que mon soupçon ci-dessus sur la declaration de CroixMsgProc
> est correct, c'est ici l'erreur.

le cast sur le retour est inutile.
le cast sur le paramètre est invalide car la méthode
est non statique (comme tu l'indiquais plus haut).



ici le PO veux simplement faire:



::SetWindowLong(w, GWL_WNDPROC, (long) CroixMsgProc);



Est-ce que ça marche sous Windows 64 Bits ? J'ai entendu dire
que même en 64 Bits, VC++ fait de long une valeur de 32 Bits. Ce
qui veut dire que la conversion est illégale.

où le 3ième paramètre est l'adresse d'une méthode définie comme :



static long __stdcall CroixMsgProc(HWND,
unsigned int, unsigned int, long);



HWND est une structure opaque, __stdcall un modifier
appliquant la convention d'appel "standard" de microsoft, à
savoir:
<quote>
STDCALL passes arguments right-to-left, and returns the value
in eax. The called function cleans the stack, unlike CDECL.
This means that STDCALL doesn't allow variable-length argument
lists.
</quote>



Jusque là, je suis sans problème. Ce que je ne saisis pas
réelement, c'est ce long. Pourquoi un long ? La convention
quasi-universelle, depuis les tout premières implémentations de
C, c'est d'utiliser void* pour des données clients (et je
suppose ici qu'il s'agit d'une donnée client, pour lui permettre
de retrouver la contexte lors du callback). L'idée étant que le
client peut donc faire ce qu'il veut, en passant un pointeur à
une struct quelconque. L'utilisation d'un long pose un problème
si long est plus petit qu'un pointeur.

> J'ai jeté un coup d'oeil à la documentation de SetWindowLong
> ; malheureusement, ce n'est pas clair ce que signifie ce
> long qu'on positionne.



en effet cela (ce 3ième param.) peut être très différent (un
int 16 ou 32 bits ou un pointeur de fonction selon le 2nd
param.) (avec évidemment aucun contrôle de type possible,
comme cela n'est pas rare avec les APIs MS).



Ils se sont sans doute inspirés de Unix, par exemple ioctl.
Seulement, sous Unix, la signature est :
int ioctl( int fildes, int request, ... ) ;
Note que ioctl exige en fait toujours exactement trois
paramètres. Bien que pour certain requêtes, le troisième
paramètre ne peut être que 0. Dans d'autres cas, c'est soit un
int, soit un char*, soit un pointeur à divers types de struct.
Historiquement, cette fonction date d'une époque où un pointeur
était un int, avec conversion implicite, et qu'il n'y avait pas
de prototype de fonction. Mais au moins Posix a corrigé la
signature pour dire la vérité.

Il y a bien une justification pour ce genre de fonction au
niveau de l'interface système. Grosso modo, ioctl signifie
« fais quelque chose » sur la périphérique désignée par le
premier paramètre, où ce qu'il faut faire, c'est indiqué par le
deuxième paramètre. Et c'est ouvert ; un nouveau type de
périphérique pourrait définir une nouvelle opération, sans qu'on
ait besoin d'ajouter des fonctions à l'API système.) Mais dans
ces cas, la solution, c'est bien varargs, comme pour ioctl.
(Remarque, c'est une solution dangéreuse aussi. Avec vararg's,
sans le reinterpret_cast, son code aurait compilé. Pour faire
des choses réelement bizarre à l'exécution.)

--
James Kanze (GABI Software) email:
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34