I have this class that will help me with animated meshes.
class CAllocateHierarchy: public ID3DXAllocateHierarchy
{
public:
STDMETHOD(CreateFrame)(THIS_ LPCTSTR Name, LPD3DXFRAME *ppNewFrame);
STDMETHOD(CreateMeshContainer)(THIS_ LPCTSTR Name, LPD3DXMESHDATA pMeshData,
LPD3DXMATERIAL pMaterials, LPD3DXEFFECTINSTANCE pEffectInstances, DWORD NumMaterials,
DWORD *pAdjacency, LPD3DXSKININFO pSkinInfo,
LPD3DXMESHCONTAINER *ppNewMeshContainer);
STDMETHOD(DestroyFrame)(THIS_ LPD3DXFRAME pFrameToFree);
STDMETHOD(DestroyMeshContainer)(THIS_ LPD3DXMESHCONTAINER pMeshContainerBase);
CAllocateHierarchy(CMyD3DApplication *pApp) :m_pApp(pApp) {}
public:
CMyD3DApplication* m_pApp;
};
but when i try to intallizes a class like CAllocateHierarchy allloc(this); i will get error. 16 IntelliSense: object of abstract class type "CAllocateHierarchy" is not allowed: c:\users\owner\documents\visual studio 2010\projects\monopoly\monopoly\monopoly.cpp 186
The error message indicates that you didn't override all the abstract methods from the interface ID3DXAllocateHierarchy.
Looking through the arguments, I see that you forgot the "const" for several arguments to the CreateMeshContainer() method. As a result, the C++ compiler thinks this is a different method, and complains that the original CreateMeshContainer() is still abstract.
From http://msdn.microsoft.com/en-us/library/bb205621(v=VS.85).aspx
HRESULT CreateMeshContainer(
[in] LPCSTR Name,
[in] const D3DXMESHDATA *pMeshData,
[in] const D3DXMATERIAL *pMaterials,
[in] const D3DXEFFECTINSTANCE *pEffectInstances,
[in] DWORD NumMaterials,
[in] const DWORD *pAdjacency,
[in] LPD3DXSKININFO pSkinInfo,
[out, retval] LPD3DXMESHCONTAINER *ppNewMeshContainer
);
So the solution is: Add 'const' to several arguments (but see update below).
Update: You also are missing some '*' in your arguments. Apparently you have declared the CreateMeshContainer to take arguments by value, while it should be by const pointer. Copy-pasting the declaration from the msdn link and removing the [in] tags might be the fastest way to get a correct declaration.
Suggestion: Using a different compiler might help to generate more insightful error messages, as might setting the warning level as high as possible. Some compilers list the methods that are still abstract. Some compilers might warn that your CreateMeshContainer() is not overriding the virtual CreateMeshContainer() in the interface. Every suggestion what is wrong could be helpful.
Your subclass doesn't implement at least one of the pure virtual methods (marked virtual whatever = 0) of its base class. You must implement all such methods in order to instantiate your subclass.
Related
I am writing some C++ code to get data from a SDR (software defined radio) and analyse it using an FFT library (FFTW3). The software uses an API (SDR_play_API and its DLL). I am trying to include the API functionality into an object. The library comes with a non-object based example program.
The IDE I am using is VS2105.
Three of the functions are callbacks to handle events from the hardware. The address of the callback functions that handle these events are passed to the API through a structure. I include the relevant code snippets from the example program, the header files and my own code after a description of the problem.
Though I have been on some C++ training - and taught others the basics - I am far from an expert and the problem goes beyond my understanding of pointers and objects.
The problem I have is one that has been discussed before on Stack Exchange. It is a problem of pointers to member functions.
The simple solution would seem to be to make the functions STATICs. However that causes problems because of some of the variables used in these functions. Without making them static then the compiler complains and if I make them static the linker complains because there is no matching definition for static variables in the library.
I have looked through Stack Exchange tried the solutions suggested but I can't seem to make any of them work - I get compiler errors.
So I feel ideally I just want to pass the pointers to the member functions to API through the structure ... but I have tried all sorts of variations on syntax without success. Can anyone help?
The API comes with an example program that does not use objects. So before I reveal my attempts to use the functions in an object, here is the code from the example program. First I will show where it assigns the location of the functions to the members of the structure, then I will include the structure definitions etc from the header file.
First then, the assignment:
// Assign callback functions to be passed to sdrplay_api_Init()
cbFns.StreamACbFn = StreamACallback;
cbFns.StreamBCbFn = StreamBCallback;
cbFns.EventCbFn = EventCallback;
Here, from the header file that comes with the API, is the definition of the structure
{
sdrplay_api_StreamCallback_t StreamACbFn;
sdrplay_api_StreamCallback_t StreamBCbFn;
sdrplay_api_EventCallback_t EventCbFn;
} sdrplay_api_CallbackFnsT;
and here, again from the header file that comes with the API is the definition of the data types - you can see the these are function pointers
typedef void (*sdrplay_api_StreamCallback_t)(short *xi, short *xq, sdrplay_api_StreamCbParamsT *params, unsigned int numSamples, unsigned int reset, void *cbContext);
typedef void (*sdrplay_api_EventCallback_t)(sdrplay_api_EventT eventId, sdrplay_api_TunerSelectT tuner, sdrplay_api_EventParamsT *params, void *cbContext);
here is one of the call back function declarations
void StreamACallback(short *xi, short *xq, sdrplay_api_StreamCbParamsT *params, unsigned int numSamples, unsigned int reset, void *cbContext)
{
...
}
So that all works fine and compiles - but it that works in a non-object scenario.
However when I make the functions a member of a class then I get errors. I have tried the following variations without success. Can someone please point me in the right direction - if I had had hair by now I wouldn't have anymore cause it would be on the floor all around me in clumps.
function definition:
void sdr_object::StreamACallback(short *xi, short *xq, sdrplay_api_StreamCbParamsT *params, unsigned int numSamples, unsigned int reset, void *cbContext)
{
...
}
Unsuccessful attempts to assign to structure include (including compiler error)
cbFns.StreamACbFn = this->StreamACallback;//"non standard syntax: use '&' to create a pointer to the member"
//cannot convert from 'void (__cdecl sre_object::*)(...) to sdrplay_api_StreanCallback_t
cbFns.StreamACbFn = &this->StreamACallback;//'&': illegal operation on bound member function experssion
cbFns.StreamACbFn = this->sdr_object::StreamACallback; //"non standard syntax: use '&' to create a pointer to the member"
//cannot convert from 'void (__cdecl sre_object::*)(...) to sdrplay_api_StreanCallback_t
cbFns.StreamACbFn = &this->sdr_object::StreamACallback; //'&': illegal operation on bound member function experssion
Any wisdom will e received most gratefully. (How to do it will be received even more gratefully ...!)
This answer comes with many thanks to Igor Tandetnik who suggested the solution in comments above.
Igor wrote "Make your callbacks static member functions. Pass this pointer for cbContext parameter to sdrplay_api_Init - you get that same pointer back in the callback. Now the callback can do static_cast<MyClass*>(cbContext)->memberFunction(params); . The actual logic can now be implemented in a non-static member function; the static one just serves as a glue between C++ implementation and C API"
My implementation of that is as follows:
Add to the class declaration in the header file an intermediary "glue" function for each event handler e.g.:
static void sdr_object::StreamACallback_static(short *xi, short *xq, sdrplay_api_StreamCbParamsT *params, unsigned int numSamples, unsigned int reset, void *cbContext)
{
static_cast<sdr_object*>(cbContext)->StreamACallback(xi, xq, params, numSamples, reset, cbContext);
};
For the function above, the pointer that is handed to the API then becomes
cbFns.StreamACbFn = this->StreamACallback_static;
In my particular example, I then had to do the same for the other two functions.
I did not have to change any other existing code.
Again, many thanks to Igor for the answer - I hope I have implemented it as he intended ... that said, what I have described works, so I imagine I have!
I'm getting this error and I don't know how to solve it. This is my code (more details below):
CP1626.h
#pragma once
#include <Windows.h>
namespace CP1626{
...
//DLL functions
void setCallbackDataWriteFunc(PNIO_CBF_DATA_WRITE _ptrDataWriteFunc);
...
}
cp1626.cpp
#include "cp1626lib.h"
...
typedef void (* ptr_setCallbackDataWriteFunc)(PNIO_CBF_DATA_WRITE);
ptr_setCallbackDataWriteFunc setCallbackDataWriteFuncFunction;
...
void CP1626::setCallbackDataWriteFunc(PNIO_CBF_DATA_WRITE _ptrDataWriteFunc){
(setCallbackDataWriteFuncFunction)(_ptrDataWriteFunc);
}
And with PNIO_IOXS defined as
typedef PNIO_IOXS (*PNIO_CBF_DATA_WRITE) /* write data to IO stack (local ==> remote) */
(PNIO_UINT32 DevHndl, /* Handle for Multidevice */
PNIO_DEV_ADDR * pAddr, /* geographical address */
PNIO_UINT32 BufLen, /* length of the submodule input data */
PNIO_UINT8 * pBuffer, /* Ptr to data buffer to write to */
PNIO_IOXS Iocs); /* remote (io controller) consumer status */
And then, I've, coded using C++/CLI and .NET, my main user interface class, who does next:
UI_Main.h
#include "cp1626lib.h"
...
public ref class UI_Main : public System::Windows::Forms::Form{
//Local function definition, which is assigned to callback
PNIO_IOXS dataWriteFunc(PNIO_UINT32 DevHndl, PNIO_DEV_ADDR * pAddr, PNIO_UINT32 BufLen, PNIO_UINT8 * pBuffer, PNIO_IOXS Iocs);
...
void InitCP1626(){
...
CP1626::setCallbackDataWriteFunc(dataWriteFunc);
...
}
}
The error is at line CP1626::setCallbackDataWriteFunc(dataWriteFunc);, and it says that a pointer to member is not valid for a managed class. What's the correct form to do this callback assignation when I'm on a managed class? I think that I should find a way to convert delegates into function pointers, but also I'm not sure about this.
Thank you in advance.
EDIT: I've tried to change line CP1626::setCallbackDataWriteFunc(dataWriteFunc); with CP1626::setCallbackDataWriteFunc(Marshal::GetFunctionPointerForDelegate(del));, with dataWriteFunc^ del; a delegate with format delegate PNIO_IOXS dataWriteFunc(PNIO_UINT32 DevHndl, PNIO_DEV_ADDR * pAddr, PNIO_UINT32 BufLen, PNIO_UINT8 * pBuffer, PNIO_IOXS Iocs);
But it also fails. At this time, the error says 'CP1626::setCallbackDataWriteFunc : cannot convert parameter 1 from 'System::IntPtr' to 'PNIO_CBF_DATA_WRITE''
you might think about rereading part of the documentation from Microsoft. Even if it's old (like from 2006) it is not outdated.
Example. Microsoft documented the use of callbacks.
https://msdn.microsoft.com/en-us/library/367eeye0.aspx
In your case, you didn't look, what GetFunctionPointerForDelegate() is returning. It is a IntPtr. This is a structure Microsoft uses to wrap all sort of pointers into one structure for .NET. It has the method void* ToPointer()
PNIO_CBF_DATA_WRITE cb = static_cast<PNIO_CBF_DATA_WRITE>(IntPtr.ToPointer());
CP1626::setCallbackDataWriteFunc(cb);
Be aware that you should use __stdcall for the callback. It is mentioned to be needed for compatibility.
typedef PNIO_IOXS (__stdcall *PNIO_CBF_DATA_WRITE)
If you are not able to recompile the sources to use __stdcall, just reroute it over another function you have defined.
I tried to use your code within a test project but i didn't want to setup to call the callback somewhere independent.
Kind Regards
p.s. I wanted to mark your question with low quality. Because there is documentation to read/google and learn from. You should take your time and be so kind to mark some of the answers for your four questions lately as the right answer.
I was trying to write a C++ program, including a header file, and a cpp file, plus, I am using the SimConnect dll.
Let's say I have a class called MyClass, which contains some functions.
Inside one of my functions, I call this SimConnect function:
SIMCONNECTAPI SimConnect_CallDispatch(HANDLE hSimConnect, DispatchProc pfcnDispatch, void * pContext);
Also, I wrote this function:
void __stdcall MyClass::myDispatchProc(SIMCONNECT_RECV* pData, DWORD cbData, void *pContext)
As far as I understood, I should send this function as the second parameter to the SimConnect function SimConnect_CallDispatch I talked about before.
I read an example which came with the SimConnect SDK which is doing exactly what I am doing, while I get an error, and they don't.
The only thing that's different is that they wrote their whole code in one page, while I tried to split the code into header + body.
When I try to do as I said above, and write
SimConnect_CallDispatch(hSimConnect, myDispatchProc, NULL);
I receive this error (compiler is having trouble in myDispatchProc part):
argument of type "void (__stdcall TransmitData::*)(SIMCONNECT_RECV *pData, DWORD cbData, void *pContext)" is incompatible with parameter of type "DispatchProc"
So clearly, it's a casting-like error.
As I said, this code would've worked if I didn't split my program into two separate files. Why doesn't it work now?
Although this is not a recent question, I'll leave a reference in case anyone else stumbles upon this. Note: This question is specific to the SimConnect SDK used for MS FS2020 (and FSX).
The SimConnect_CallDispatch function requires a reference to a static, callback function with a specific interface, i.e. (SIMCONNECT_RECV* pData, DWORD cbData, void* pContext)
The nature of the static function is that it won't have access to the variables of the instance, so to get around this problem, all of the examples out there don't bother with the complexity of .h and .cpp files and just code everything in one file. This is how I solved this issue,
Define the static callback function in the .h file, e.g.
void static CALLBACK MyDispatchProcRD(SIMCONNECT_RECV *pData, DWORD cbData, void *pContext);
Define a separate instance function to handle the actual processing of the callback in the .h file, e.g.
void DispatchProc(SIMCONNECT_RECV* pData, DWORD cbData);
In the implementation of the static callback (.cpp) cast the context reference to your class and pass it on to the instance method for further processing, e.g.
void CALLBACK MainProcessor::MyDispatchProcRD(SIMCONNECT_RECV* pData, DWORD cbData, void* pContext) {
MainProcessor* procThis = reinterpret_cast<MainProcessor*>(pContext);
procThis->DispatchProc(pData, cbData);
}
Just remember to pass the reference to your instance when calling SimConnect dispatch, i.e.
SimConnect_CallDispatch(hSimConnect, MyDispatchProcRD, this);
I have been struggling for days to figure out the probably obvious reason why i cant get my code to compile.
I have a class (based on wxThread) where the callback is defined:
-- Header file --
class TestClass : public wxThread
{
private:
static void WlanNotification(WLAN_NOTIFICATION_DATA *wlanNotifData, VOID *p);
};
-- Code file --
I call the WlanRegisterNotification function, that needs the above callback function as a parameter:
dwResult = WlanRegisterNotification(hClient, WLAN_NOTIFICATION_SOURCE_ALL, true, (WLAN_NOTIFICATION_CALLBACK) WlanNotification, this, 0, &dwPrevNotif);
This compiles and works fine, but the problem is the function is marked as static, so i cant access my non static stuff from the callback (which i need for other reasons).
I have tried every single combination i can think of to pass in the callback as non static:
-- Header file --
void WINAPI WlanNotification(PWLAN_NOTIFICATION_DATA data, PVOID context);
-- Code file --
dwResult = WlanRegisterNotification(hClient, WLAN_NOTIFICATION_SOURCE_ALL, true, (WLAN_NOTIFICATION_CALLBACK)WlanNotification, this, 0, &dwPrevNotif);
i just get:
error C2660: 'WlanRegisterNotification' : function does not take 6
arguments
error C2440: 'type cast' : cannot convert from 'overloaded-function'
to 'WLAN_NOTIFICATION_CALLBACK'
I'm thinking its related to the typedef somehow:
typedef VOID (WINAPI *WLAN_NOTIFICATION_CALLBACK) (PWLAN_NOTIFICATION_DATA, PVOID);
I have tried googling for examples of using the WlanRegisterNotification function, but none of the examples i could find is calling it from a class, which is what seems to be an issue here, so i'm really lost.
A non-static class method has a hidden this parameter that the callback is not expecting let alone know how to fill in. That is why you cannot use it as a callback unless you either 1) use static to remove that parameter, or 2) create a thunk to use as the actual callback and then have it internally delegate to a non-static class method. Remember that the Windows API is designed for C, not C++. There are no classes or implicit this pointers in C.
In this case, a static callback can access non-static members of your class because you are explicitly passing the object's this pointer as the pCallbackContext of WlanRegisterNotification(), which is then passed as-is to the context of the callback:
class TestClass : public wxThread
{
private:
static VOID WINAPI WlanNotification(PWLAN_NOTIFICATION_DATA wlanNotifData, PVOID context);
};
VOID WINAPI TestClass::WlanNotification(PWLAN_NOTIFICATION_DATA wlanNotifData, PVOID context)
{
TestClass *pThis = (TestClass*) context;
// use pThis-> to access non-static members as needed..
}
// get rid of the typecast when passing the callback. If it does
// not compile, then it is not declared in a compatible manner...
dwResult = WlanRegisterNotification(hClient, WLAN_NOTIFICATION_SOURCE_ALL, TRUE, &WlanNotification, this, 0, &dwPrevNotif);
As previously discussed here, I'm trying to find a workaround for the LNK2019 issue that arises when building a static library which utilizes C++ templates, and separating the source from the header to keep the code private from other projects. I believe I've nearly come to a working conclusion (for my particular situation), but I'm not entirely sure if this is the correct/best way to go about it and was wondering if anyone has any suggestions, improvements/comments to add?
The goal is to do some type checking to see if the template's signature matches the target prototype function's signature, do some private processing, and return whether or not it was sucessful. NOTE that I have removed SdkHookMgr.h and SdkHookMgr.cpp from the prior version of the solution in the above link, and merged everything back into SdkLib.h and SdkLib.cpp, into a static class for a bit of clarity.
SdkLib.h:
#include <typeinfo>
#ifdef MY_EXPORTS
# define MYDECL __declspec(dllexport)
#else
# define MYDECL
#endif
// Prototypes
typedef HMODULE (WINAPI *HookLoadLibraryA)( LPCSTR lpFileName );
//...
class CHook;
class CHookManager;
MYDECL BOOL WINAPI ValidateHook( CHook *hook );
class CHook
{
public:
CHook() : m_type(NULL), m_target(NULL), m_result(FALSE) {};
CHook( const char *type, PVOID target ) : m_type(type), m_target(target) {
m_result = ValidateHook(this);
};
const char *m_type;
PVOID m_target;
BOOL m_result;
};
class CHookManager
{
public:
template <typename HookFunction> static BOOL Hook(HookFunction target)
{
const type_info& type = typeid(HookFunction);
CHook *hook = new CHook( type.name(), target );
return hook->m_result;
}
};
SdkLib.cpp:
#include <SdkLib.h>
IDXDECL BOOL WINAPI ValidateHook( CHook *hook )
{
// Do type checking, private processing, etc here...
return TRUE;
}
DemoDLL.cpp:
#include <SdkLib.h>
HMODULE WINAPI Hooked_LoadLibraryA( LPCSTR lpFileName )
{
DebugBreak();
}
// The function that starts the rollercoaster.
// - Syntax: Hook< prototype >( target )
if!(CHookManager::Hook<HookLoadLibraryA>(Hooked_LoadLibraryA))
cout << "Failed to create hook for LoadLibraryA!" << endl;
You may find that the results of typeid are not consistent between the DLL and the main program. (See, for example, typeid result across different dll's.)
Since your list of possible hooks is limited, it strikes me that overloaded functions would be a better choice than templates. You'd then have no DLL issues, and the validity of each hook would be checked at compile time. Here's an example of the sort of thing I'm thinking of; obviously in practice you'd split this into separate definition and declaration, with the definitions living in the DLL so it's all cleanly separated out.
class CHookManager {
public:
BOOL Hook(HookLoadLibraryA hook) {
assert(sizeof hook<=sizeof(uintptr_t));
return ValidateHook((uintptr_t)hook,"LoadLibraryA");
}
BOOL Hook(HookLoadLibraryW hook) {
assert(sizeof hook<=sizeof(uintptr_t));
return ValidateHook((uintptr_t)hook,"LoadLibraryW");
}
};
(Note that this shows up one disadvantage of this approach - you can only have one hook per function signature. I mention this for completeness' sake, but I'll assume this hasn't proven an issue.)
(You might like to replace the assert with a compile-time assert, if you have one.)
ValidateHook would use strcmp to figure out which hook is being hooked. Once it's figured out which hook it is, it would then cast the uintptr_t to the appropriate function pointer type. It knows the pointer was originally of the correct type for that hook, because you're using the C++ overload mechanism to do it all. (Or you could have an enum, say, for all the hook types, rather than passing in a string - it's up to you. The key part is that you have full control over the values being passed, so that the DLL and the calling code are definitely using matching values.)
This code would be a little tiresome to generate, but if you already have the list of typedef names then you could create the corresponding code using regular expression search and replace, or keyboard macros, in your editor of choice. Or you could use something like the so-called "X-Macro" to automate the generation of the whole thing.