Depending on the OS, you may be able to create dynamic functions for each callback object. I've done exactly that for callbacks from legacy code which didn't have any facility to pass a value to the callback.
Create a small prototype forwarding function with the type the library expects which then calls the real callback function with an easily seen extra parameter
void Call01020304 () {
CallWithValue(0x01020304);
}
Compile it and look at the hex for the assembly. It should be obvious where the constant is.
You then use VirtualAlloc + PAGE_EXECUTE_READWRITE or mmap + PROT_EXEC to allocate some memory which can be executed. Allocation is usually in 4K blocks, so create a class to manage the functions, as you will be allocating enough for many in one go.
When you need a new callback function with a unique value, copy the bytes of the prototype with appropriately changed value into your executable memory, and return the pointer to it as the callback function.