Link to home
Start Free TrialLog in
Avatar of bod_1
bod_1

asked on

callback not getting right params?

Hi,
I've got a common Open dialog with a callback function for it.  The callback looks like this:

UINT CALLBACK CFind_Replace::ofnHook(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)

There is a lCustData member in the OPENFILENAME struct that I've read, is supposed to be passed to your callback function in the lParam of the WM_INITDIALOG message.  I've checked the parameter that I get and it's not the same as the value that I put in lCustData.

One more question is that HWND parameter in the callback.
What window is it a handle to?  I've gotten a valid window pointer from it and done all sorts of things to the window that the pointer points to and it doesn't seem to be the dialog (or any other window).

Thanks
Avatar of WxW
WxW

The HWND is the windows handle to the dialog , NOT the MFC handle . You cannot use it with MFC functions directly , because when a MFC function wants a handle to a window , it asks for a MFC handle , and not a HWND . You can use this value with the Windows API . For example , you can manually set the window title bar by calling ::SetWindowText(HWND,char*) . In the API form of SetWindowText, you must provide the HWND . IN the MFC form of that function ( if it has any ) , the HWND is got internally by the MFC object , and you give only the title .
>>There is a lCustData member in the OPENFILENAME struct that I've read, is
>> supposed to be passed to your callback function in the lParam of the
>> WM_INITDIALOG message

Nope.  You are in good company.  9 out of 10 programmers make that mistake and one like it with WM_CREATE.

The lParam is not a pointer to the custom data.  It is a pointer to the OPENFILENAME structure.  Inside that structure there is a pointer to the data in the lCustData member.  So you can get to the custom data, but not directly.
>> What window is it a handle to?  I've gotten a valid window pointer from it
How did you get a window pointer from it?  Not by casting right?
Avatar of bod_1

ASKER

I just thought about the MFC vs. API HWNDs and that would kind of make sense.  If I called CWnd::FromHandle() on a non-MFC object, the FromHandle() would probably just use the handle as a reference address, count back a certain number of bytes (to where the beginning of the CWnd class data structure should be) and return that address.
If that's right, then I was just getting a pointer to some data around the HWND.

Thanks Nietod for clearing that up for me about the custom parameter.
Yes, I was trying to CWnd::FromHandle() it.
Does what I wrote above sound right?

What I'm trying to do is to get the edit control in the open dialog.  This is if the user selects more than one file, I want to allocate OPENFILENAME.lpstrFile to hold the filenames before the dialog returns.

I just ran Spy++ and the HWND passed doesn't match any of the open dialog's window's or button's handle.
?

>>Yes, I was trying to CWnd::FromHandle() it.
>> Does what I wrote above sound right?
Yes.  I thought you might have done a cast like (CWnd *) on the handle.  That won't work.

>> If I called CWnd::FromHandle() on a non-MFC object, the FromHandle()
>> would probably just use the handle as a reference address, count back a
>> certain number of bytes (to where the beginning of the CWnd class data
>> structure should be) and return that  address.
>>  If that's right, then I was just getting a pointer to some data around the HWND.

The HWND to CWnd * conversion is not done with pointer math of any sort.  The CWnd's are not positioned in memory in any relation to the HWND pointers.  (In fact they are in differnet memory spaces).  MFC maintains  a look-up table of every HWND it has a CWnd for.  When you specify a HWND to FromHandle() it looks for it in the table.  If it find a CWnd * it returns it.  Otherwise it creates a temporary CWnd for the handle and returns a pointer to it.  The temproary CWnd goes in a second look-up table so it can be disposed of when it is not needed.  That is why the MFC docs say you shouldn't save the pointer returned as the CWnd might be destroyed soon.  It is these temporary ones that are getting destroyed.  The CWnd that are to windows that were created by MFC and more permenant and won't be destroyed unexpectedly.
>> What I'm trying to do is to get the edit control in the open dialog.  This is if the
>> user selects more than one file, I want to allocate OPENFILENAME.lpstrFile
>> to hold the filenames before the dialog returns.
Can you elaborate on this?  Are you specifying the OFN_ALLOWMULTISELECTFLAG?  This isn't soem sort of kludge to allow that type of behavour is it?  Do you mean you are trying to expand the size of the buffer depending on what the user selects?  Bad idea.  If so,  just make the buffer big enough to hold a reasonably large selection.

>> HWND passed doesn't match any of the open dialog's window's or button's handle
It should be the dialog's handle! ???
Avatar of bod_1

ASKER

That's one thing that I don't really understand about not being able to get a pointer to the dialog from the handle as WxW said.
If the CWnd::FromHandle() creates a temporary wrapper class for the handle, than why can't I call it on the open dialog handle to obtain a wrapper CWnd for the open dialog?
I don't really care whether I access the dialog using MFC or API's, I just need to get the edit control inside the dialog.
Regardless of my approach, I can't seem to access the dialog.
I've tried
CWnd::FromHandle(hOpenDlg)->GetWindowText(), DestroyWindow(), ShowWindow(SW_HIDE),
but none of these functions act on the dialog.
Same with ::GetWindowText(), ::ShowWindow().

The reason that I wanted to allocate the buffer to hold the path names dynamically is that it would be the proper way to handle a multiselect open dialog.  If it were not able to handle an infinite number of files (memory allowing), it would not be good code.
I've noticed that when I download MSDN articles with their images and links to other pages, the paths are referencing paths in the Microsoft server's directory structure so I wrote a little program to set all of the paths to the current directory (DOS's .).  The program works fine, but at times I would like to be able to correct paths on MANY html files.

>>The reason that I wanted to allocate the buffer to hold the path names
>> dynamically is that it would be the proper way to handle a multiselect
>> open dialog.  If it were not able to handle an infinite number of files
>> (memory allowing), it would not be good code.
Agreed, but there is no indication that MS wrote the dialog box code with that in mind.  You specify that information when you call the GetOpenFileName() procedure.  They do not say you can alter it during the execution of the procedure.  Thus you could be causing problems.  The changes you make might be ignored or might cause a crash.  They might work under one OS and not under another.  I wouldn't recommend that approach.

Note in the docs for the OFNHookProc() it says that the handle is for a window that is a child of the dialog window (one that fills the client area, I would guess).  If you need to access the actual dialog window, you need to get this window's parent.   If that doesn't help, post your code for this hook procedure and your code for opening the dialog.
I just wanted to note to bod that you can wrap a HWND around a CWnd by using CWnd::Attach(); this can make your life easier rather than suddenly finding you have a second-class window handle that you have to use the old Windows API with.  For example:

void Myfunction(HWND hwnd)
{
   CWnd wnd;
   if(wnd.Attach(hwnd)) {
      // ... now you can use wnd as a stand-in for hwnd
   }
}
Avatar of bod_1

ASKER

Thanks Warmcat.  Yes, I prefer the classes to their equivalent API's.  They make the code more organized.
Nietod, I didn't read anywhere that the handle passed to the callback was a child of the dialog.  I assumed that it would be the dialog.  
That must have been what was going on.  I was enumerating and walking the list of child windows.
About dynamically allocating that buffer, I guess I shouldn't assume that windows code would dynamically allocate their buffer either.  
I am still very confused about the difference between MFC HWNDs and API ones.  I was trying on the Rebar control all night, and I can't seem to get it to stop drawing over top of my toolbar, like it doesn't recognize it as it's child(an MFC toolbar).  I suspect that HWND thing (please explain?).  Thats another question.
I go months programming where everything's just happy, you know, no worries, and then BAM!  I always get nailed with these framework things.
I don't know what the points will do.  Nietod and Warmcat, your boxes are blue and WxW's is green.

Anyways,
Thanks All

>> i am still very confused about the difference between MFC HWNDs and API ones.
HWNDS are the same thing in both cases.  An HWND is a unique number that identifies a particular window to the windows OS.  If MFC or a windows API procedure takes an HWND as a parameter or returns it as a return value, they are the same type of thing.  somethign that uniquely identifies a window to the Windows OS.  

MFC CWnds are something else.  They are C++ objects.  They encapsulate most of the properties an procedures that the windows OS provides for its windows.  an MFC CWnd can be attached to a window.  That means it stores the window's handle (HWND) That way when you manipulate the CWnd (move it, for example) it can have Windows move the corresponding window.

But note you cannot use them interchangbley.  If you have a CWnd, you can move the window like
CWnd SomeWind;
 . . .
SomeWind.MoveWindow(....);

If you had a pointer to a CWnd, it would be like.

CWnd *SomeWindPtr;
 . . .
SomeWindPtr->MoveWindow(....);

But if you tried either of those things with an HWND you will get a compiler error.  An HWND is not a C++ object or a pointer to a C++ object.
>>I don't know what the points will do.  Nietod and Warmcat,
>> your boxes are blue and WxW's is green

WxW has the proposed answer.  He will get the points if you grade the question.  If you don't feel he should, you should reject his answer and ask for a "dummy" answer from the export you think deserves the points.
Avatar of bod_1

ASKER

Well I don't know where WxW's been this whole time.  WxW's answer about API HWNDs vs. MFC HWNDs doesn't seem right to me.
If I understatnd what WxW was trying to say, it was something like I can't do something like this:

CWnd Wind;
Wind.Create(...);
::ShowWindow(Wind.m_hWnd, SW_HIDE);
or
::ShowWindow(Wind.GetSafeHwnd(), SW_HIDE);

or something like this:

HWND hwnd = CreateWindow(...);
CWnd::FromHandle(hwnd)->ShowWindow(SW_HIDE);

than WxW is wrong.
A handle to a window, is a handle to a window whether it's created by MFC or API's (right?).

Anyways, Nietod, you are the one that actually answered my question.  
I was assuming that the handle passed to the callback was that of the dialog but you said that it was a handle to one of it's sub windows.  This would explain why my code could never find the edit control in the dialog.  
I was walking the children of the window whose handle was passed which would be none if it was a child.  I will have to walk the siblings to get the one I want.

Nietod, I think that you should get the points.
I select Reopen question to other experts?
then you answer reopened question?

>> A handle to a window, is a handle to a window whether it's
>> created by MFC or API's (right?).
Yes.  

The question didn't get reopened?
Avatar of bod_1

ASKER

Just now
ASKER CERTIFIED SOLUTION
Avatar of nietod
nietod

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Avatar of bod_1

ASKER

Thanks.
Sorry I have not replied yet  (far away from my pc....)
No prob , nietod has given a good answer .