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

Posted on 2007-10-03
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??
Question by:clemex
    LVL 39

    Expert Comment

    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

    Author Comment

    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 ???

    LVL 10

    Expert Comment

    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.

    Author Comment

    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??  
    LVL 10

    Expert Comment

    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."


    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

    LVL 39

    Expert Comment

    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.

    Author Comment

    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?
    LVL 10

    Accepted Solution

    I think that the best solution would be to change the way your code is hooking Listboxes. :-)

    I found this example on the net:
    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;

    Featured Post

    IT, Stop Being Called Into Every Meeting

    Highfive is so simple that setting up every meeting room takes just minutes and every employee will be able to start or join a call from any room with ease. Never be called into a meeting just to get it started again. This is how video conferencing should work!

    Join & Write a Comment

    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…
    Background What I'm presenting in this article is the result of 2 conditions in my work area: We have a SQL Server production environment but no development or test environment; andWe have an MS Access front end using tables in SQL Server but we a…
    Get people started with the process of using Access VBA to control Excel using automation, Microsoft Access can control other applications. An example is the ability to programmatically talk to Excel. Using automation, an Access application can laun…
    This lesson covers basic error handling code in Microsoft Excel using VBA. This is the first lesson in a 3-part series that uses code to loop through an Excel spreadsheet in VBA and then fix errors, taking advantage of error handling code. This l…

    745 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

    Need Help in Real-Time?

    Connect with top rated Experts

    16 Experts available now in Live!

    Get 1:1 Help Now