473,508 Members | 2,006 Online
Bytes | Software Development & Data Engineering Community
+ Post

Home Posts Topics Members FAQ

Using CallWindowProc To Call 'Non-WndProc' Functions

I've seen examples of using the CallWindowProc Windows API function to
call functions through their addresses in VB6 -- a clever workaround to
emulate C-like function pointer semantics. A well-known example is the
use of CallWindowProc to call a function gotten via
LoadLibrary/GetProcAddress. For example, I've seen code similar to the
following which can register/unregister a COM DLL where the path to the
DLL is known only at runtime -- in this case, you can't declare the
register/unregister functions in the normal fashion since you can't use
a variable in the Lib clause:

Option Explicit

Public Declare Function LoadLibrary Lib "kernel32" Alias "LoadLibraryA"
_
(ByVal lpszLibraryPath As String) As Long

Public Declare Function FreeLibrary Lib "kernel32" _
(ByVal hLib As Long) As Long

Public Declare Function GetProcAddress Lib "kernel32" _
(ByVal hLib As Long, ByVal lpszProcName As String) As Long

Public Declare Function CallWindowProc Lib "user32" Alias
"CallWindowProcA" _
(ByVal lpWndProc As Long, ByVal hWnd As Long, _
ByVal uMsg As Long, ByVal wParam As Long, ByVal lParam As Long) As
Long
Public Function RegisterComDll(ByVal sDllPath As String) As Boolean

Dim hLib As Long
Dim pRegFunc As Long

' Dynamically load the requested DLL
hLib = LoadLibrary(sDllPath)

If hLib = ERROR_FAILURE Then
' Indicate failure
RegisterComDll = False
Else
' Get the address of this DLL's DllRegisterServer entry point
pRegFunc = GetProcAddress(hLib, "DllRegisterServer")
' Use CallWindowProc as a proxy. We need it to call function
' for us since VB6 doesn't support calling through a function
' pointer directly.
CallWindowProc pRegFunc, 0&, 0&, 0&, 0&
' Done with the DLL, free it
FreeLibrary hLib
' Indicate success
RegisterComDll = True
End If

End Function

I have seen other posters claim that you can only do this if the called
function has the same signature as a window procedure, since
CallWindowProc naturally expects to be given a pointer to a window
procedure. A window procedure takes 4 Longs and is returns a Long. In
the above example, the DllRegisterServer function takes no parameters
and returns a Long.

I can understand the reason why people think the signatures need to
match. The Windows API and VB6 both using the STDCALL calling
convention, where the called function is responsible for cleaning
parameters off the stack (as opposed to the standard C calling
convention, where the caller cleans the parameters off the stack). The
function that CallWindowProc calls is also expected to be STDCALL.
Since a STDCALL function is responsible for cleaning up its own
parameters, it can only clean up the the number of parameters it
expects, i.e. if you pass 5 parameters to a STDCALL function which only
expects 1 parameter, the called function will clean up only 1 parameter
(the number it was expecting), which leaves 4 parameters on the stack.
VB6 can detect when the stack has become unbalanced in this manner by
comparing where the stack pointer was before calling the function with
where it is after the function returns. If the values don't match, then
too few or too many parameters must have been passed to the called
function, and VB6 will generate a 'Run-time error 49: Bad DLL Calling
Convention.' However, the above code works fine. To verify that the
stack is in fact correctly maintained, I repeatedly called the
RegisterComDll in an infinite while loop and let it run for a while.
After 60 million calls, it was safe to assume that the stack was never
going to overflow (i.e. the stack was still balanced after each call to
CallWindowProc, even it invoked DllRegisterServer with the wrong number
of arguments).

This behavior is counterintuitive, because with STDCALL you would
actually expect the code produce a stack overflow after a number of
iterations because the extraneous parameters passed to
DllRegisterServer will be orphaned on the stack. Actually, I would
expect the program to crash and burn on the first call, since an
unbalanced stack can screw up the return addresses.

Does anyone know why this *doesn't* happen? My guess is that
CallWindowProc is storing away the current stack pointer before it
calls the function passed to it, and then restores the stack pointer to
the previosly-stored value, to guarantee that the stack is always in
the right place and that CallWindowProc can always return correctly,
regardless of whether or not the function it calls was given the right
number of params. That's the only logical way I can figure that the
above code would work -- in any event, if it is true that
CallWindowProc is ensuring that the stack is balanced (and it certainly
seems to be the case, at least as far as observable behavior is
concerned), it should then be perfectly safe to use CallWindowProc to
call a function with a different parameter count/parameter types than a
proper window procedure.

--

Mike S

Dec 16 '06 #1
0 5372

This thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

5
2110
by: Roger Leigh | last post by:
I've written a simple container template class to contain a single value. This emits a signal when the value is changed (it's used as a notifier of changes), and listeners can connect to its...
6
1701
by: Marc Mutz | last post by:
Hi, I'm in discussion with a lib vendor who uses placement new to forward construction to another ctor, like this: MyClass( ... ) { new (this) MyClass( ... ); } I asked them to use a private...
3
2299
by: ThunderMusic | last post by:
Hi, I'm trying to have a MSN Messenger like form/app closing behavior. When I click on the X button, I only want the form to disappear and when I double-click on the notify icon or right-click...
11
6551
by: Grasshopper | last post by:
Hi, I am automating Access reports to PDF using PDF Writer 6.0. I've created a DTS package to run the reports and schedule a job to run this DTS package. If I PC Anywhere into the server on...
6
1379
by: Amitava Sengupta | last post by:
Is there any issue in using COM component in web applications. The problem I'm facing are 1. Though the dll is using non-static member variables which are being instantiated on each call,...
43
2680
by: markryde | last post by:
Hello, I saw in some open source projects a use of "!!" in "C" code; for example: in some header file #define event_pending(v) \ (!!(v)->vcpu_info->evtchn_upcall_pending & \...
5
2910
by: removeps-generic | last post by:
Hi. I'm using placement new to re-initialize part of an object. Is this OK? struct BaseImp { All& r_all; BaseImp(All& all) : r_all(all) }; struct Calc::Imp : public BaseImp
89
5948
by: Cuthbert | last post by:
After compiling the source code with gcc v.4.1.1, I got a warning message: "/tmp/ccixzSIL.o: In function 'main';ex.c: (.text+0x9a): warning: the 'gets' function is dangerous and should not be...
4
1921
by: archimed7592 | last post by:
Hi. for example i have base class A and dirved class B: struct A { virtual void f() { std::cout << "A::f()" << std::endl; } }; struct B : public A {
0
4003
by: David | last post by:
- Are there any peculiarities with using curs.executemany(...) vs. multiple How many times are you calling execute vs a single executemany? The python call overhead will add up for thousands of...
0
7226
marktang
by: marktang | last post by:
ONU (Optical Network Unit) is one of the key components for providing high-speed Internet services. Its primary function is to act as an endpoint device located at the user's premises. However,...
0
7125
by: Hystou | last post by:
Most computers default to English, but sometimes we require a different language, especially when relocating. Forgot to request a specific language before your computer shipped? No problem! You can...
0
7328
Oralloy
by: Oralloy | last post by:
Hello folks, I am unable to find appropriate documentation on the type promotion of bit-fields when using the generalised comparison operator "<=>". The problem is that using the GNU compilers,...
0
7388
jinu1996
by: jinu1996 | last post by:
In today's digital age, having a compelling online presence is paramount for businesses aiming to thrive in a competitive landscape. At the heart of this digital strategy lies an intricately woven...
0
5631
agi2029
by: agi2029 | last post by:
Let's talk about the concept of autonomous AI software engineers and no-code agents. These AIs are designed to manage the entire lifecycle of a software development project—planning, coding, testing,...
1
5055
isladogs
by: isladogs | last post by:
The next Access Europe User Group meeting will be on Wednesday 1 May 2024 starting at 18:00 UK time (6PM UTC+1) and finishing by 19:30 (7.30PM). In this session, we are pleased to welcome a new...
0
3199
by: TSSRALBI | last post by:
Hello I'm a network technician in training and I need your help. I am currently learning how to create and manage the different types of VPNs and I have a question about LAN-to-LAN VPNs. The...
0
3186
by: adsilva | last post by:
A Windows Forms form does not have the event Unload, like VB6. What one acts like?
0
422
bsmnconsultancy
by: bsmnconsultancy | last post by:
In today's digital era, a well-designed website is crucial for businesses looking to succeed. Whether you're a small business owner or a large corporation in Toronto, having a strong online presence...

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.