I have a Visual Studio 2008 C++ project where I’m creating a DLL with a C interface. I defines two types of callback functions: a regular and an extended that provides additional data.
struct Foo {
char a[ MAX_A ];
char b[ MAX_B ];
char c[ MAX_C ];
};
struct FooEx {
char a[ MAX_A ];
char b[ MAX_B ];
char c[ MAX_C ];
char d[ MAX_D ];
};
typedef void ( CALLBACK *USERCALLBACK )( const Foo&, DWORD );
typedef void ( CALLBACK *USERCALLBACK_EX )( const FooEx&, DWORD );
I maintain state with a UserData structure. Because I have two types of callbacks, I end up with two structures:
struct UserData {
DWORD user;
int zoo;
std::string bar;
USERCALLBACK callback;
};
struct UserDataEx {
DWORD user;
int zoo;
std::string bar;
USERCALLBACK_EX callback;
};
How do I reconcile my API with having two different UserData structures without creating separate EX versions of every function? Is there a way to templatize the callback? Or create a base-class of user data?
DECLARE_HANDLE( HMYAPI );
// this function is agnostic of the callback type
MY_API HMYAPI MyAPI_Create()
{
return (HMYAPI)new UserData();
}
// This function does not directly use the callback type, but may need to know it to properly deallocate the UserData structure.
MY_API void MyAPI_Close( HMYAPI handle )
{
delete reinterpret_cast< UserData* >( handle );
}
// this function needs to know about the different callback types
MY_API void MyAPI_Register( HMYAPI handle, USERCALLBACK cb, DWORD user )
{
UserData* ud = reinterpret_cast< UserData* >( handle );
ud->cb = cb;
ud->user = user
}
// this function needs to know about the different callback types
MY_API void MyAPI_RegisterEX( HMYAPI handle, USERCALLBACK_EX cb, DWORD user )
{
UserData* ud = reinterpret_cast< UserData* >( handle );
ud->cb = cb;
ud->user = user
}
// this function is agnostic of the callback type
MY_API void Foo( HMYAPI handle, int x )
{
UserData* ud = reinterpret_cast< UserData* >( handle );
ud->bar = "Foo";
ud->zoo = x;
}
Not elegant, but it would work:
UserDataandUserDataExstructures are identical other than the pointer types. Combine those two structures into one and replace the callback pointer type withFARPROC. You’d have to cast back and forth when setting and retrieving those function pointers.flagsfield and set aUSES_EXTENDED_CALLBACKflag.