|
-
Dec 4th, 2001, 11:52 PM
#1
Thread Starter
Hyperactive Member
Event in C++
is it possible to have a function(like WinProc or TimerProc) that is part of a COM component, and have the client be able to supply code for it, like an event in VB? this is from SSubTimer. It contains a function called WinProc, but the "client" is able to put whatever code in by using SSubTimer_WinProc. How would I have a function that could act like this in C++? thanks
Amon Ra
The Power of Learning.
-
Dec 5th, 2001, 05:43 AM
#2
Frenzied Member
You're talking about callback functions. Basically you give the object that's going to be using your code a pointer to the function you want it to use. Usually the pointer is passed in on the creation or initialisation of the object. Then, whenever the object wants to, it can call your function via the pointer you gave it.
There is a CALLBACK modifier to function declarations where that function will be called by a pointer to it, if I remember right the WindowProc function of a window is a callback so you should already know how that works. You may need to use that
Harry.
"From one thing, know ten thousand things."
-
Dec 5th, 2001, 07:41 AM
#3
CALLBACK == __stdcall. It really means nothing, unless you are talking about a Win32API callback. You can define your own callbacks however you like, using __cdecl, __fastcall, etc. To get a callback running, use a typedef:
Code:
typedef void Func(int);
Func is now the type:
CornedBee says this is odd, so you mgiht want to typedef like:
Code:
typedef void (*Func)(int); // if im not mistaken;
The only difference is that defining a pointer is:
instead of the above. Its your choice. To call the function using either method, do what you normally do:
Easy? Yep.
Z.
-
Dec 5th, 2001, 10:22 AM
#4
Thread Starter
Hyperactive Member
ok i get what Harry said, but Z., how do I provide the code for that function outside of the component?
ok, Harry, so I need to put CALLBACK in front of my functions. Let's say for WinProc, i want the subclassed window to have its own usual one, but then the component would use another one for the real subclassing, right? SO i would have 2 winproc's: one would be the usual one for the window, and the other would be one calling other functions or somthing and then calling the original winproc?
Amon Ra
The Power of Learning.
-
Dec 5th, 2001, 10:27 AM
#5
Thread Starter
Hyperactive Member
ok there, the component is gonna be for owner-drawing menus. so i woul have an extra winproc used by the component to do all the menu work and then this same winporc would call the original one? so i would pass a pointer to the winproc for the menu ops., right?
thanks
Amon Ra
The Power of Learning.
-
Dec 5th, 2001, 10:42 AM
#6
This is a part of an old post by me:
Code:
// the function pointer must know which type of function it points to
// for example the WNDPROC pointer is defined like this:
typedef LRESULT (CALLBACK* WNDPROC)(HWND, UINT, WPARAM, LPARAM);
// the brackets around the function name are necessary.
// Function pointers don't need the typedefs, so this could happen:
// global function pointer or function?
int *FuncPtr(int);
// This is interpreted as a function named FuncPtr with int* return type
// this is a pointer named FuncPtr to functions with int return type:
int (*FuncPtr)(int);
// This is a little bit complicated, this is why there are typedefs like above
// Now it's easy to declare a pointer to a WNDPROC
WNDPROC pfnWndProc;
// such a pointer is a member of the WNDCLASS and WNDCLASSEX structs
// to assign a value to a function pointer, use the function name without a parameter list.
pfnWndProc = MyWndProc;
So in the header for your COM object you declare the function pointer type. You COM objects Init function (I'm sure you have one) takes as parameter such a pointer and saves it in the object.
The user needs to write the callback, let's call it UserCallback:
Code:
// assume you have your function pointer defined like this:
// typedef int (* comproc)(int, void*);
// assume a struct named COMINITSTRUCT
// assume a constant named CM_INIT
int UserCallback(int msg, void* pData)
{
COMINITSTRUCT *pCIS
switch(msg)
{
case CM_INIT:
pCIS = (COMINITSTRUCT*)pData;
pCIS->whatever = 3;
return 0;
...
}
return -1;
}
Now see the other code the user has:
Code:
void SomeFunction()
{
CoInitialize(); // to use COM
IYourMainInterface* pYMI;
CoCreateInstance(YOUR_OBJECT_GUID, NULL, CLSCTX_INPROC_SERVER, YOUR_INTERFACE_GUID, (void**)&pYMI);
pYMI->Init(someValue, otherValue, UserCallback);
// work with the object
...
}
You have a callback function.
Last edited by CornedBee; Dec 5th, 2001 at 10:53 AM.
All the buzzt
 CornedBee
"Writing specifications is like writing a novel. Writing code is like writing poetry."
- Anonymous, published by Raymond Chen
Don't PM me with your problems, I scan most of the forums daily. If you do PM me, I will not answer your question.
-
Dec 5th, 2001, 06:53 PM
#7
Thread Starter
Hyperactive Member
thank you very much! i should be able to implement this now...
btw, i now know one of the uses of function pointers...
Amon Ra
The Power of Learning.
-
Dec 5th, 2001, 11:45 PM
#8
Thread Starter
Hyperactive Member
man this is terrible...i am so lost..ok, i create my window with a normal winproc..then i want to have another winproc used only for the menu-realted operations, then this winproc calls the normal one in case there are new mesages..how would i tell the program to use the custom one instead of the normal one?
Amon Ra
The Power of Learning.
-
Dec 6th, 2001, 07:42 AM
#9
Like CornedBee said:
pYMI->Init(someValue, otherValue, UserCallback);
Just pass in the function as a parameter in the Init Function.
Z.
-
Dec 6th, 2001, 09:03 AM
#10
do you mean subclassing ( = replacing the original wndproc of a predefined window type)
All the buzzt
 CornedBee
"Writing specifications is like writing a novel. Writing code is like writing poetry."
- Anonymous, published by Raymond Chen
Don't PM me with your problems, I scan most of the forums daily. If you do PM me, I will not answer your question.
-
Dec 6th, 2001, 10:13 AM
#11
Thread Starter
Hyperactive Member
ok, so when i create my window with its normal winproc for creation, i write another one and make it a callback and have the component have a pointer to it, right? but how will the program know to use the one in the component for the menu-processing?
Amon Ra
The Power of Learning.
-
Dec 6th, 2001, 10:38 AM
#12
PHP Code:
WNDPROC pfnOldProc; // stores a pointer to the old window proc
pfnOldProc = SetWindowLong(hwnd, GWL_WNDPROC, (long)pfnNewProc);
// replace wndproc
This requires the user to do
CallWindowProc(pfnOldProc, hwnd, message, ...);
at the end of his wndproc.
You can as an alternative make your own wndproc and then first call the user proc, catch it's return value and if it is a special value you also call the old proc.
PHP Code:
LRESULT MyProc(HWND hwnd, UINT message,...)
{
LRESULT result = CallWindowProc(pfnUserProc, ...);
if(result == UNHANDLED)
{
result = CallWindowProc(pfnOldProc, ...);
}
return result;
}
This way you don't need to make the old wnd proc pointer available to the user.
All the buzzt
 CornedBee
"Writing specifications is like writing a novel. Writing code is like writing poetry."
- Anonymous, published by Raymond Chen
Don't PM me with your problems, I scan most of the forums daily. If you do PM me, I will not answer your question.
-
Dec 6th, 2001, 09:10 PM
#13
Thread Starter
Hyperactive Member
cornedbee, after this:
PHP Code:
LRESULT MyProc(HWND hwnd, UINT message,...)
{
LRESULT result = CallWindowProc(pfnUserProc, ...);
if(result == UNHANDLED)
{
result = CallWindowProc(pfnOldProc, ...);
}
return result;
}
after it does the checking, i can put my own message handling, right? like this:
PHP Code:
LRESULT MyProc(HWND hwnd, UINT message,...)
{
LRESULT result = CallWindowProc(pfnUserProc, ...);
if(result == UNHANDLED)
{
result = CallWindowProc(pfnOldProc, ...);
}
switch (msg)
{
case WM_LBUTTONDOWN: {
.....
return result;
}
what does it check for exactly? and would that be right? thanks..i think i almost got it..sorry for my inexpertise..
Amon Ra
The Power of Learning.
-
Dec 6th, 2001, 09:16 PM
#14
Thread Starter
Hyperactive Member
i found this on MSDN
PHP Code:
WNDPROC wpOrigEditProc;
LRESULT APIENTRY EditBoxProc(
HWND hwndDlg,
UINT uMsg,
WPARAM wParam,
LPARAM lParam)
{
HWND hwndEdit;
switch(uMsg)
{
case WM_INITDIALOG:
// Retrieve the handle to the edit control.
hwndEdit = GetDlgItem(hwndDlg, ID_EDIT);
// Subclass the edit control.
wpOrigEditProc = (WNDPROC) SetWindowLong(hwndEdit,
GWL_WNDPROC, (LONG) EditSubclassProc);
//
// Continue the initialization procedure.
//
return TRUE;
case WM_DESTROY:
// Remove the subclass from the edit control.
SetWindowLong(hwndEdit, GWL_WNDPROC,
(LONG) wpOrigEditProc);
//
// Continue the cleanup procedure.
//
break;
}
return FALSE;
UNREFERENCED_PARAMETER(lParam);
}
// Subclass procedure
LRESULT APIENTRY EditSubclassProc(
HWND hwnd,
UINT uMsg,
WPARAM wParam,
LPARAM lParam)
{
if (uMsg == WM_GETDLGCODE)
return DLGC_WANTALLKEYS;
return CallWindowProc(wpOrigEditProc, hwnd, uMsg,
wParam, lParam);
}
to have my component get the pointer to the original proc, i would have the client pass to the Init() function right? but then i would also have to have the client tell the normal winproc to call the one in my component?
Amon Ra
The Power of Learning.
-
Dec 6th, 2001, 09:33 PM
#15
Thread Starter
Hyperactive Member
ok i wrote a simple example that hopefully does subclass the window..it seems to work:
PHP Code:
#include <windows.h>
static char g_szClassName[] = "My Window Class";
static HINSTANCE g_hInst = NULL;
HWND hbtnDone; //bye bye
LRESULT CALLBACK SubclassWndProc(HWND hwnd, UINT Message, WPARAM wParam, LPARAM lParam);
WNDPROC wpOrigWinProc;
LRESULT CALLBACK WndProc(HWND hwnd, UINT Message, WPARAM wParam,
LPARAM lParam)
{
switch(Message) {
case WM_COMMAND:
{
if(LOWORD(wParam) == BN_CLICKED && (HWND)lParam == hbtnDone)
{
MessageBox(hwnd, "Message from original WinProc", "It works", MB_OK);
DestroyWindow(hwnd);
}
}
break;
case WM_DESTROY:
{
SetWindowLong(hwnd, GWL_WNDPROC, (LONG) wpOrigWinProc);
PostQuitMessage(0);
}
break;
default:
return DefWindowProc(hwnd,Message,wParam,lParam);
}
return 0;
}
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
LPSTR lpCmdLine, int nShowCmd)
{
WNDCLASSEX WndClass;
HWND hwnd;
MSG msg;
g_hInst = hInstance;
WndClass.cbSize = sizeof(WNDCLASSEX);
WndClass.style = NULL;
WndClass.lpfnWndProc = WndProc;
WndClass.cbClsExtra = 0;
WndClass.cbWndExtra = 0;
WndClass.hInstance = g_hInst;
WndClass.hIcon = LoadIcon(NULL, IDI_APPLICATION);
WndClass.hCursor = LoadCursor(NULL, IDC_ARROW);
WndClass.hbrBackground = (HBRUSH)(COLOR_WINDOW);
WndClass.lpszMenuName = NULL;
WndClass.lpszClassName = g_szClassName;
WndClass.hIconSm = LoadIcon(NULL, IDI_APPLICATION);
if(!RegisterClassEx(&WndClass)) {
MessageBox(0, "Window Registration Failed!","Error",
MB_ICONEXCLAMATION | MB_OK | MB_SYSTEMMODAL);
return 0;
}
//create the main window
hwnd = CreateWindowEx(
WS_BORDER,
g_szClassName,
"Modify a window by its caption",
NULL,
CW_USEDEFAULT, CW_USEDEFAULT, 320, 135,
NULL, NULL, g_hInst, NULL);
//check for null handle
if(hwnd == NULL) {
MessageBox(0, "Window Creation Failed", "Error",
MB_ICONEXCLAMATION | MB_OK | MB_SYSTEMMODAL);
return 0;
}
hbtnDone = CreateWindowEx(NULL,"BUTTON","Done",
WS_CHILD | WS_VISIBLE, 235, 61, 70, 20, hwnd,
NULL, g_hInst, NULL);
//check for error in creation
if(hbtnDone == NULL)
{
MessageBox(0, "Done Creation Failed", "Error",
MB_ICONEXCLAMATION | MB_OK | MB_SYSTEMMODAL);
return 0;
}
ShowWindow(hwnd, nShowCmd);
UpdateWindow(hwnd);
wpOrigWinProc = (WNDPROC) SetWindowLong(hwnd, GWL_WNDPROC, (LONG)SubclassWndProc);
while(GetMessage(&msg, NULL, 0, 0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return FALSE;
}
LRESULT CALLBACK SubclassWndProc(HWND hwnd, UINT Message, WPARAM wParam, LPARAM lParam)
{
switch(Message)
{
case WM_LBUTTONDOWN:
{
MessageBox(hwnd, "Message from SubclassWinProc", "It works", MB_OK);
}
break;
}
return (::CallWindowProcA(wpOrigWinProc, hwnd, Message, wParam, lParam));
}
does it?
thanks a lot
Amon Ra
The Power of Learning.
-
Dec 7th, 2001, 09:39 PM
#16
Thread Starter
Hyperactive Member
CornedBee, when i do:
PHP Code:
wpOldProc = SetWindowLong(hwnd, GWL_WNDPROC, (LONG) ESWindowProc);
it says
Code:
c:\my documents\subclasspractice\easysubclass.h(67) : error C2440: 'type cast' : cannot convert from 'long (__stdcall EasySubclass::*)(struct HWND__ *,unsigned int,unsigned int,long)' to 'long'
i did what you said above but i cant get it to work...
Amon Ra
The Power of Learning.
Posting Permissions
- You may not post new threads
- You may not post replies
- You may not post attachments
- You may not edit your posts
-
Forum Rules
|
Click Here to Expand Forum to Full Width
|