Results 1 to 16 of 16

Thread: Event in C++

  1. #1

    Thread Starter
    Hyperactive Member Amon Ra's Avatar
    Join Date
    Feb 2001
    Location
    In some cave on Uranus...
    Posts
    500

    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.

  2. #2
    Frenzied Member HarryW's Avatar
    Join Date
    Jan 2000
    Location
    Heiho no michi
    Posts
    1,827
    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."

  3. #3
    Zaei
    Guest
    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:
    Code:
    Func* myFunc;
    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:
    Code:
    Func myFunc;
    instead of the above. Its your choice. To call the function using either method, do what you normally do:
    Code:
    myFunc(10);
    Easy? Yep.

    Z.

  4. #4

    Thread Starter
    Hyperactive Member Amon Ra's Avatar
    Join Date
    Feb 2001
    Location
    In some cave on Uranus...
    Posts
    500
    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.

  5. #5

    Thread Starter
    Hyperactive Member Amon Ra's Avatar
    Join Date
    Feb 2001
    Location
    In some cave on Uranus...
    Posts
    500
    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.

  6. #6
    Kitten CornedBee's Avatar
    Join Date
    Aug 2001
    Location
    In a microchip!
    Posts
    11,594
    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.

  7. #7

    Thread Starter
    Hyperactive Member Amon Ra's Avatar
    Join Date
    Feb 2001
    Location
    In some cave on Uranus...
    Posts
    500

    Talking

    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.

  8. #8

    Thread Starter
    Hyperactive Member Amon Ra's Avatar
    Join Date
    Feb 2001
    Location
    In some cave on Uranus...
    Posts
    500
    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.

  9. #9
    Zaei
    Guest
    Like CornedBee said:
    pYMI->Init(someValue, otherValue, UserCallback);
    Just pass in the function as a parameter in the Init Function.

    Z.

  10. #10
    Kitten CornedBee's Avatar
    Join Date
    Aug 2001
    Location
    In a microchip!
    Posts
    11,594
    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.

  11. #11

    Thread Starter
    Hyperactive Member Amon Ra's Avatar
    Join Date
    Feb 2001
    Location
    In some cave on Uranus...
    Posts
    500
    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.

  12. #12
    Kitten CornedBee's Avatar
    Join Date
    Aug 2001
    Location
    In a microchip!
    Posts
    11,594
    PHP Code:
    WNDPROC pfnOldProc// stores a pointer to the old window proc
    pfnOldProc SetWindowLong(hwndGWL_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 hwndUINT 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.

  13. #13

    Thread Starter
    Hyperactive Member Amon Ra's Avatar
    Join Date
    Feb 2001
    Location
    In some cave on Uranus...
    Posts
    500
    cornedbee, after this:

    PHP Code:
    LRESULT MyProc(HWND hwndUINT 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 hwndUINT 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.

  14. #14

    Thread Starter
    Hyperactive Member Amon Ra's Avatar
    Join Date
    Feb 2001
    Location
    In some cave on Uranus...
    Posts
    500
    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(hwndDlgID_EDIT); 
     
                
    // Subclass the edit control. 
                
    wpOrigEditProc = (WNDPROCSetWindowLong(hwndEdit
                    
    GWL_WNDPROC, (LONGEditSubclassProc); 
                
    // 
                // Continue the initialization procedure. 
                // 
                
    return TRUE
     
            case 
    WM_DESTROY
                
    // Remove the subclass from the edit control. 
                
    SetWindowLong(hwndEditGWL_WNDPROC
                    (
    LONGwpOrigEditProc); 
                
    // 
                // 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(wpOrigEditProchwnduMsg
            
    wParamlParam); 

    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.

  15. #15

    Thread Starter
    Hyperactive Member Amon Ra's Avatar
    Join Date
    Feb 2001
    Location
    In some cave on Uranus...
    Posts
    500
    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 hwndUINT MessageWPARAM wParamLPARAM lParam);
    WNDPROC wpOrigWinProc;

    LRESULT CALLBACK WndProc(HWND hwndUINT MessageWPARAM 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(hwndGWL_WNDPROC, (LONGwpOrigWinProc);
                
    PostQuitMessage(0);
            }
            break;
        default:
            return 
    DefWindowProc(hwnd,Message,wParam,lParam);
        }

        return 
    0;
    }

    int WINAPI WinMain(HINSTANCE hInstanceHINSTANCE hPrevInstance,
                       
    LPSTR lpCmdLineint 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(NULLIDI_APPLICATION);
        
    WndClass.hCursor LoadCursor(NULLIDC_ARROW);
        
    WndClass.hbrBackground = (HBRUSH)(COLOR_WINDOW);
        
    WndClass.lpszMenuName NULL;
        
    WndClass.lpszClassName g_szClassName;
        
    WndClass.hIconSm LoadIcon(NULLIDI_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_USEDEFAULTCW_USEDEFAULT320135,
            
    NULLNULLg_hInstNULL);

    //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_VISIBLE235617020hwnd,
            
    NULLg_hInstNULL);

        
    //check for error in creation
        
    if(hbtnDone == NULL)
        {
            
    MessageBox(0"Done Creation Failed""Error"
                
    MB_ICONEXCLAMATION MB_OK MB_SYSTEMMODAL);
            return 
    0;
        }

        
    ShowWindow(hwndnShowCmd);
        
    UpdateWindow(hwnd);

        
    wpOrigWinProc = (WNDPROCSetWindowLong(hwndGWL_WNDPROC, (LONG)SubclassWndProc);

        while(
    GetMessage(&msgNULL00))
        {
            
    TranslateMessage(&msg);
            
    DispatchMessage(&msg);
        }

        return 
    FALSE;
    }

    LRESULT CALLBACK SubclassWndProc(HWND hwndUINT MessageWPARAM wParamLPARAM lParam)
    {
        switch(
    Message)
        {
        case 
    WM_LBUTTONDOWN:
            {
                
    MessageBox(hwnd"Message from SubclassWinProc""It works"MB_OK);
            }
        break;
        }
        
        return (::
    CallWindowProcA(wpOrigWinProchwndMessagewParamlParam));

    does it?
    thanks a lot
    Amon Ra
    The Power of Learning.

  16. #16

    Thread Starter
    Hyperactive Member Amon Ra's Avatar
    Join Date
    Feb 2001
    Location
    In some cave on Uranus...
    Posts
    500
    CornedBee, when i do:

    PHP Code:
    wpOldProc SetWindowLong(hwndGWL_WNDPROC, (LONGESWindowProc); 
    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
  •  



Click Here to Expand Forum to Full Width