[Okta Webinar] Learn how to a build a cloud-first strategyRegister Now

x
?
Solved

GetClassInfo() returned invalid WndProc when putting manifest in my application...

Posted on 2007-10-03
8
Medium Priority
?
1,053 Views
Last Modified: 2013-12-04
I read all you have written about manifest here ... but find no solution to resolve my problem!!!

Here is the situation :

I work on a big application where the main application is written in VB6 ... This VB6 application call method of some home made DLL written in C++ using VC6 ...

I want that my application and all DLL show XP theme GUI ... So I call InitComCtrl method in the Form_Initialize of my VB6 application ... and I add a manifest (MyAppName.exe.manifest) in the same directory of my exe file.

When I start my Application ... All seems to work fine and GUI is XP themed ...

And then the application crash for no reason!! I debug that, and found that a DLL Call the method GetClassInfo and the call succeed (return TRUE) but it return the WNDCLASS lpfnWndProc member set to 0xffff04df... That is an invalid address!!!

So the crash occur because this DLL Subclass a ListBox Window and try to forward message to the original WndProc returned in the WNDCLASS lpfnWndProc ... That is invalid...

I not that the GetClassInfo method only return invalid WinProc address when the manifest is present!!

Somebody understand something in that??
Some body could help me??
0
Comment
Question by:clemex
  • 3
  • 3
  • 2
8 Comments
 
LVL 39

Expert Comment

by:itsmeandnobodyelse
ID: 20012823
The lpfnWndProc is a (static) function pointer. If you call it by a DLL function it will fail in case the function pointer is defined from the app. If you subclass a control by the dll you would need to exchange the WindowsProc by a dll exported function as far as I understand. That is the way active-x controls work. They create their control with functions defined in the dll (ocx) only.

The .manifest is a means to get registry information both from registered app and from registered dll out of the .manifest and not from registry. To make that work both the app and the dll need to have self-register functionality which was up-to-date when creating the .manifest. Moreover, if some other dlls or controls were used by either the app or the dll, these versions of the dlls or ocx' must be available at the target machine as well what may be difficult to guarantee in any case. Moreover, as far as I know neither VB6 nor VC6 were made to use .manifest files. The manifest is a feature that came with .NET and works for XP and Vista only. I never heard that it is possible to let VC6 applications work with .manifest though it may work envertheless. How did you create the .manifest files? Couldn't you upgrade to VC7.1 or  VC8?

Regards, Alex
0
 

Author Comment

by:clemex
ID: 20014428
You are wrong!! You can use manifest with VC6 and VB6 Apps by putting the manifest in resource or in the same directory of the exe file... And this work perfectly ...

About my problem : I read what you write and I don't really understand your point!! A WindowsProc method is a static function ... And the DLL is a part of the process so you can call WinProc from a DLL without problem ... I really don't understand your point ...

More details about my problem:
The Only thing I explained in my question is :  We have a VB6 app, This VB6 app calls an exported function of a DLL I created in VC6... The only thing the exported function, of the DLL, do is calling the GetClassInfo(...) Win32 API function...

So the GetClassInfo(NULL, "LISTBOX", &aWndClass) function fill a WNDCLASS ... And all is ok here!!

After that ... (and not that all is working correctly) the only thing I do is to put a manifest associated to the VB6 App executable... At this point the app is fully XP themed ... But when the app call the same exported function of my DLL the GetClassInfo(NULL, "LISTBOX", &aWndClass) Win32 API function succeeded by returning TRUE but fill the WNDCLASS structure with invalid values... For Example : the lpfnWndProc member of the WNDCLASS struct is equal to somthing like 0xFFFF0DE4 which is an invalid Default LISTBOX WinProc Address...

What do you think??

My Question is Why the Win32 function GetClassInfo(...) does not work correctly when putting manifest  in my app ???

0
 
LVL 10

Expert Comment

by:pjasnos
ID: 20027146
lpfnWndProc is correct - this is because there are two kinds of window procedures: client-side (so called normal one) and server side(which one is executed inside kernel address space). This allows to put some common window procedures within kernel, and hence avoid cost of many context switches when doing some more complex drawing. In case window procedure is kernel-side, GetClassInfo returns a "handle" to server side window procedure. This handle is not a valid address - it is only meaningful to kernel counterpart of CallWindowProc. So, assuming you are subclassing by replacing window proc and then calling directly the original one, the solution is to use CallWindowProc instead. This is the way of subclassing recommended by Microsoft.
0
 [eBook] Windows Nano Server

Download this FREE eBook and learn all you need to get started with Windows Nano Server, including deployment options, remote management
and troubleshooting tips and tricks

 

Author Comment

by:clemex
ID: 20041928
Hmm ... I think you're right ... We should use the CallWindowProc API...

I check the sub classing code we have in our system an after subclassing the WinProc of a ListBox the system generate a Access Violation when calling the macro FORWARD_WM_NCCREATE on the WindowProc ...

Hmmm ....

Their is one think I don't understand about you explanation ... Why Microsoft macros don't use the CallWindowProc API the call WindowProc???

The macro FORWARD_WN_NCCREATE is a macro defined by Microsoft in the WindowsX.h file...

And this macro si define like the following:

FORWARD_WM_NCCREATE(hwnd, lpCreateStruct, fn) \
    (BOOL)(DWORD)(fn)((hwnd), WM_NCCREATE, 0L, (LPARAM)(LPCREATESTRUCT)(lpCreateStruct))

This Microsoft macro call the WindowProc directly??

I change the code by replacing the call to FORWARD_WN_NCCREATE call by a call to CallWindowProc(g_WWSWndProc, hwnd, WM_NCCREATE, (WPARAM)0, (LPARAM)lpCreateStruct);

Which is supposed to be correct but the call do an Access Violation because it try to access the address 0xFFFF0DE4 which is the address that GetClassInfo returned ...

Hmmm ... So it seems that CallWindowProc try to call the addess of the WindowProc directly and Freeze because the 0xFFFF0DE4 is not a valid WindowProc Handle an/or function address...

What do you think??  
0
 
LVL 10

Expert Comment

by:pjasnos
ID: 20044518
You should probably ask MS why they don't use the Callwindowproc (using it is recommended on their website).

You said you are subclassing a ListBox window - why are you using GetClassInfo to get previous address of window proc?
Solution recommended by MS is:

"To subclass an instance of a window, call the SetWindowLong function and specify the handle to the window to subclass the GWL_WNDPROC flag and a pointer to the subclass procedure. SetWindowLong returns a pointer to the original window procedure; use this pointer to pass messages to the original procedure. The subclass window procedure must use the CallWindowProc function to call the original window procedure.

Note  To write code that is compatible with both 32-bit and 64-bit versions of Microsoft Windows, use the SetWindowLongPtr function."

from http://msdn2.microsoft.com/en-us/library/ms633570.aspx

It *could* be possible that the constant returned (I don't believe it to be an address) may be used by the theme api - they may be intentionally causing the exception and look for this value to do their job (with which you are interfering) <-- this are my guesses only. They may for instance intercept window creation in this way and then replace window procedure - that's why you should not use GetClassInfo. Try with SetWindowLong - if it doesn't work, I'll investigate further.

Fingers crossed

Pawel
0
 
LVL 39

Expert Comment

by:itsmeandnobodyelse
ID: 20044735
As the problem arises with the .manifest only, the reasons for the wrong WindowsProc cannot explained by code which runs for both cases. The differences when using a manifest is that you may use different versions of MFC dll or runtime dlls. Also, different active-x controls might be loaded when using a manifest. If a VC6 exe loads a different dll than that it was developed with all kind of thinkable corruption can occur.

To find out whether I am right you should run the depends which was in VC6 tools both when running with manifest and without and check whether the same dlls were loaded. If not, most probably that is the reason for the crash.
0
 

Author Comment

by:clemex
ID: 20050632
Ok ... I check the code and I find that the code does not override a LISTBOX ... The code create a new Window Class based on a the class LISTBOX...

So the code get the LISTBOX class info by calling GetClassInfo(..., "LISTBOX", ...) and use this info to create a new Window  based on the WNDCLASS returned by GetClassInfo...

The code change the WinProc returned by GetClassInfo, by our own WinProc ... And we keep the original WinProc returned by the GetClassInfo to call the default ListBox WinProc in our own WinProc to let the default implementation to work ... Understand?

This code is really strange ... because It create a new Window Class that work like a List box rather than sub classing a list box ... hmmm...

May be this code is not correct but we have to deal with it ... This code is in the old part of our system and probably be written 10 years ago!! so!!

What do you think?
0
 
LVL 10

Accepted Solution

by:
pjasnos earned 1500 total points
ID: 20050993
I think that the best solution would be to change the way your code is hooking Listboxes. :-)

I found this example on the net:

http://www.gipsysoft.com/articles/global_subclass/
The guy is subclassing listbox class as well (well, it modifies the class), but in a slightly different way. I have checked whether it works with xp theming, and it does not crash on my computer. Maybe try this approach as a template for modifying your code.

The crucial part from the above website:

BOOL EnhanceLISTBOX( HINSTANCE hInstance )
//
//  This is the main API. Call it once and that's it!
{
  if( !g_wpOld )
  {
    HWND hwnd = ::CreateWindow( _T("LISTBOX")
        , NULL, 0, 0, 0, 0, 0, 0, 0, hInstance, 0 );
    ASSERT( hwnd );
   
    g_wpOld = reinterpret_cast< WNDPROC >( ::GetClassLongPtr( hwnd, GCLP_WNDPROC ) );
    ::SetClassLongPtr( hwnd, GCLP_WNDPROC, (LONG_PTR)WndProc );

    VERIFY( DestroyWindow( hwnd ) );
    return TRUE;
  }
  return FALSE;
}
0

Featured Post

Upgrade your Question Security!

Add Premium security features to your question to ensure its privacy or anonymity. Learn more about your ability to control Question Security today.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

A theme is a collection of property settings that allow you to define the look of pages and controls, and then apply the look consistently across pages in an application. Themes can be made up of a set of elements: skins, style sheets, images, and o…
Enums (shorthand for ‘enumerations’) are not often used by programmers but they can be quite valuable when they are.  What are they? An Enum is just a type of variable like a string or an Integer, but in this case one that you create that contains…
As developers, we are not limited to the functions provided by the VBA language. In addition, we can call the functions that are part of the Windows operating system. These functions are part of the Windows API (Application Programming Interface). U…
Get people started with the process of using Access VBA to control Outlook using automation, Microsoft Access can control other applications. An example is the ability to programmatically talk to Microsoft Outlook. Using automation, an Access applic…
Suggested Courses

872 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question