Is it true?

Hi, In win32 programming, what is the correct way to exchange data?  Do we have to use global variables to exchange data?  Say, I have a class member function within which that I create a dialog by using CreateDialog().  Then, in the dialog procedure, I expect to accept some user inputs.  Then, how can save the user input into the data member of my class.  For example:

void MyClass::MemberFunction()
{
  .........
  CreateDialog(x, x, x, DialogProc);
  .........
}

LRESULT DialogProc(x, x, x, x)
{
  // How can I save the user inputs here into the member data of MyClass?
}

Thanks,

Robin
LVL 1
tao_shaobinAsked:
Who is Participating?
 
sofConnect With a Mentor Commented:
The proposed solution sounds a bit complex to me (sorry ;-) - here's what I normally do: use CreateDialogParam().

i.e.,

void MyClass::MemberFunction()
{
  .........
  CreateDialogParam(x, x, x, DialogProc,(LPARAM)this);
  .........
}

LRESULT
CALLBACK
DialogProc
   ( HWND hWnd
   , UINT uMsg
   , WPARAM wParam
   , LPARAM lParam
   )
{
  switch(uMsg) {

  case WM_INITDIALOG:
    SetWindowLong(hWnd,GWL_USERDATA, (LONG)lParam);
    ...
    return TRUE; // handled
  ...
  case WM_COMMAND:
    {
       MyClass* pObj = (MyClass*)GetWindowLong(hWnd, GWL_USERDATA);

     ...

    }
 }
}

No attempt at making this robust, but hopefully you get the main idea:

 * Use CreateDialogParam() to pass a pointer to the object you wish to update in your DialogProc().
 * Handle WM_INITDIALOG in that DialogProc, storing the object
reference off of the dialog box HWND.

 * Fetch the object reference via the HWND using GetWindowLong() whenever you need to get access it from within the DialogProc (cf. WM_COMMAND above.)

Hopefully that should be enough to get you going!
0
 
JMuCommented:
This is a problem if you don't have a "decent" class library or framework.

DialogProc is a global function. A framework hides global procedure and calls your dialog-class's dialog procedure. This procedure may be in base window-class and call hundreds of predefined virtual functions like MFC does.

I don't use MFC. I've created my own framework. It also hides global dialog/window procedure. The hidden procedure finds window object every time it gets a message and calls it's virtual procedure. I override this procedure in a dialog class. Now all dialog data is accessible without global variables.

In your case I'll have to write this:
LRESULT MyClass::DialogProc(x, x, x)
....

Note that the first parameter is missing.

I'll bet you can do this with MFC, if you use it. Just add variables to CDialog-derived class.

If you don't use MFC, you just need to do more work. But, you just have to write it once.

Is this an answer to your question?

JMu
0
 
tao_shaobinAuthor Commented:
Hi, JMu:

Thanks for your explanations.  I am sure you understand this problem.  But, I still don't know how to solve it.  Below is what I tried before(BTW, I am not using MFC also):

class MyClass
{
  bool DlgProc( HWND, UINT, WPARAM, LPARAM );
}

MyClass::AFunction()
{
   CreateDialog(x, x, x, DlgProc);
}

MyClass::DlgProc(x, x, x, x)
{

}

The compiler gave me:
error C2440: 'type cast' : cannot convert from '' to 'int (__stdcall *)(struct HWND__ *,unsigned int,unsigned int,long)'

If you could try an example and teach me how.  I would like to increase the pts.

Thanks,

Robin
0
Cloud Class® Course: Microsoft Exchange Server

The MCTS: Microsoft Exchange Server 2010 certification validates your skills in supporting the maintenance and administration of the Exchange servers in an enterprise environment. Learn everything you need to know with this course.

 
JMuCommented:
You get error because CreateDialog expects a global function. You can write a static DlgProc inside of the MyClass, but that doesn't solve the problem. It's just a beginning.

You need one global pointer to a dialog which you are creating. Create a dialog like this (copy-paste and modified a little bit):

EnterCriticalSection();

ASSERT( ::creatingWindow == 0 );
::creatingWindow = this;

windowHandle = ::CreateDialog(
 instanceHandle,
 templateName,
 parentWindowHandle,
 DialogProc );

ASSERT( ::creatingWindow == 0 );
::creatingWindow = 0;

LeaveCriticalSection();

In static MyClass::DlgProc you should first find an object of MyClass using hwnd. If you don't find it, then it's a first message to your window. Here is the code.

      MWindow* window;

      // find window object of handle
      if ( ! Find( windowHandle, window ) )
      {
            // handle is not in the list yet
            // this is propably because we are creating a new window

            if ( ! creatingWindow )
            {
                  // something odd happened!
                  // window is not in list and could not get new window object
                  ASSERT( false );

                  // do default processing
                  return FALSE;
            }

            window = creatingWindow;
            creatingWindow = 0;

            // this is the first message to the window

            // must attach this window handle to object
            window->AttachWindow( windowHandle );

            // remember both (handle and window object)
            // so we will find window object for the handle in next messages
            Add( windowHandle, window );
      }

      ASSERT( window );

      BOOL result = window->DialogProc( message, wParam, lParam );

      if ( message == WM_NCDESTROY )
      {
            // this is the last message to the window, so remove window from this map
            Remove( windowHandle );

            // and because window does not exists anymore, tell this to the object too
            window->AttachWindow( 0 );
      }

      return result;

I have similar routine for WindowProcedure. I hope you get the idea.

JMu
0
 
JMuCommented:
sof and tao_shaobin,

Yes, I know that my solution is more complex than sof's.

My solution is suitable for framework. Framework should not use and framework cannot use param to pass a pointer to an object. Param is open to the user of the library.

I've used sof's solution myself.

In framework it doesn't work because Windows may send a message before you have set the user data. If you try to trap this message and convert user data to a pointer, it will point to 0-address.

tao_shaobin, please test for not null before using user data.

JMu
0
 
tao_shaobinAuthor Commented:
Hi, JMu:

I have posted another question for you to collect credit.  Thanks.
0
Question has a verified solution.

Are you are experiencing a similar issue? Get a personalized answer when you ask a related question.

Have a better answer? Share it in a comment.

All Courses

From novice to tech pro — start learning today.