long^ to LONG* conversion in C++/CLI - c++

I have a DLL which I need to write a wrapper for. The goal is to use it in a C# .NET application so I need to use C++/CLI (never had read about it before, so I'm new to that).
The function header in the dll is the following:
extern "C" __declspec(dllexport) BOOL __stdcall PlayM4_GetPort(LONG* nPort);
The header I've defined in my wrapper is this:
bool PlayM4Wrapper::GetPort(long^ nPort);
From what I've understood, the circunflex sign (^) means that is a pointer to the argument (nPort). So what I'm trying to write is the following code but I'm getting a conversion error Error C2664 'BOOL (LONG *)': el argumento 1 no puede convertirse de 'System::Int32 ^' a 'LONG *' .
bool PlayM4Wrapper::GetPort(long^ nPort)
{
BOOL ret =_mLoader->m_PlayM4GetPort(nPort);
return static_cast<BOOL>(ret);
}
Can anyone please help me with this? How should I write this wrapper function?
Thanks.

From what I've understood, the circunflex sign (^) means that is a pointer to the argument
Not in the C++ understanding of a pointer. Yes, it is a reference to an instance of an object. But this reference is nothing you can use in C++. It's not a pointer and you cannot use it as a pointer. First, a long in .NET is not a reference type, so you don't need that. But from your method signature I guess that it is used as a hidden return value, so you need to write to it and therefor indeed need a reference. Since it's not a reference type in .NET, you will need another modifier to make it possible to pass the value back:
// equivalent C# signature:
// bool GetPort(ref long nPort)
bool PlayM4Wrapper::GetPort(long% nPort)
{
LONG local = nPort;
if(_mLoader->m_PlayM4GetPort(&local))
{
nPort = local;
return true;
}
return false;
}
Aparently, the % is called a tracking reference.

Related

C++ make::shared wrapping on existing raw pointer

I am working on a small wrapper for an FMOD library. Below is a snippet of the code that I have, and there are other libraries that manage the SoundData class:
class SoundData
{
public:
...
std::string mSoundName;
std::shared_ptr<FMOD::Sound> mFmodSoundHandle;
...
}
void SoundLib::CreateSound(SoundData& data)
{
FMOD::Sound *sound = nullptr;
system->createSound(data.mSoundName.data(), FMOD_DEFAULT, nullptr, &sound);
data.mFmodSoundHandle = std::make_shared<FMOD::Sound>(sound);
}
Trying to compile this snippet of the code, I get this error:
Error C2664 'FMOD::Sound::Sound(const FMOD::Sound &)': cannot convert argument 1 from 'FMOD::Sound *' to 'const FMOD::Sound &' SoundLib ...\MSVC\14.29.30133\include\xutility 158
I cannot quite understand if I am using std::make_shared() in the wrong way here? The goal here is to save the output from createSound() that is passed as a sound variable into the structure SoundData. Variable data will be managed afterwards.
You're passing a pointer where you should pass a reference. Try *sound.
Notice that you're not wrapping a pointer, you're creating a new instance of Sound and copying the value of *sound into it.
To wrap it consider:
data.mFmodSoundHandle.reset(sound);

creating a callback struct to pass into the LuaJIT FFI

So first I load in a DLL I need
local ffi = require("ffi")
local theDLL = ffi.load("thisDLL")
in the ffi cdef I have two different kinds of structs
ffi.cdef [[
typedef struct StructSession StructSession;
typedef struct {
/*
* begin_proj callback
*/
bool (__cdecl *begin_proj)(char *proj);
/*
* save_proj_state
*/
bool (__cdecl *save_proj_state)(unsigned char **buffer, int *len);
} StructCallbacks;
I also have this function in the cdef
__declspec(dllexport) int __cdecl start_session(StructSession **session,
StructCallbacks *cb);
Now I would like to call this function
print(theDLL.start_session(a,b))
vars a and b are obviously placeholders, the question is how can I pass the structs the function needs? And say we get StructSession working, is making a callback to a function WITHIN LuaJIT even going to be possible for StructCallbacks?
Creating the StructCallbacks is easy; you can create it with ffi.new and create FFI callbacks for the fields (see the FFI semantics for information on callbacks).
Creating the StructSession is trickier since it's an opaque type, but it's not much different from how you would do it in C.
Here is how you would create one in C:
StructSession* S = NULL;
start_session(*S, foo);
Notice how you are not directly allocating a StructSession. Instead, you allocate a pointer to one, and let start_session allocate the actual struct.
So we now translate this to LuaJIT code:
local S = ffi.new("StructSession*")
lib.start_session(getPointer(S), foo) -- getPointer should take the pointer of S, but...
...the FFI doesn't provide any way to take the pointer of an object (This is intentional; it allows for optimizations).
So how do we get a pointer to a StructSession? Well, recall that arrays are convertible to pointers, and we can access those through the FFI. So we instead create a single-slot array of pointers and pass that to start_session:
local S_slot = ffi.new("StructSession*[1]")
lib.start_session(S_slot, foo)
local S = S_slot[0]
And now you have a StructSession object.

callback functions and static_cast for wrapping class methods

I'm having some trouble making a callback wrapper class method that needs to be used by a third party library; the JackAudio library.
I have been able to make a wrapper for a JackAudio callback function that needs two arguments.
I'm just having trouble creating a callback function for a particular function that needs a const char * as an argument.
So far I have been able to make the JackAudio library jack_set_sample_rate_callback function use a custom class and can be executed like so:
SoundClass Sound;
SoundClass * SoundPointer = &Sound;
jack_set_sample_rate_callback(
client,
SoundClass::SampleRateCallbackWrapper,
SoundPointer
);
And the class looks something like this:
SoundClass
{
int SampleRateCallback( jack_nframes_t nframes )
{
//executes some code when called.
}
static int SampleRateCallbackWrapper( jack_nframes_t nframes, void * arg )
{
return static_cast < SoundClass* > ( arg )->SampleRateCallback( nframes );
}
};
All of the above works well, with no issues.
The problem I'm having now is with the JackAudio callback function jack_set_error_function
This is what I tried:
static void ErrorCallbackWrapper( const char * arg )
{
return static_cast < SoundClass*>( arg )->SomeErrorFunction();
}
But I get error: invalid static_cast from type ‘const char*’ to type ‘SoundClass*’
I get the gist why this is happening, I just have no idea what to do for a solution.
Thanks in advance for any help guys.
Assuming the Jack API is written for the C language, there is a formal problem already with the working callback that you have. Namely that it then needs to be extern "C", and that as a static member function it cannot be. So formally it needs to be a free-standing function.
The documentation that you link to for the jack_set_error_function gives this signature, presumably expressed in C:
void jack_set_error_function( void(*)(const char *) func);
For C++ the callback must be assumed to be extern "C", so,
extern "C" void MyErrorFunction( char const* errorMessage )
{
// Whatever, e.g. post a message to the GUI event queue, or terminate.
}
If you want this function to in turn call a method on an object, then unless the library provides some special mechanism to help you, you will just have to use one of the following techniques:
a namespace scope variable accessed by the callback, or
a dynamically generated callback.
C++ does not as of yet support the second approach, at all, so the first one is strongly indicated – if you want a callback on a method of an object.
EDIT: Sorry, I forgot to mention,
the function declarations in the API documentation are syntactically invalid.
E.g. the documentation’s signature
void jack_set_info_function( void(*)(const char *) func );
simply won’t compile with a standard-conforming compiler. Not as C, and not as C++. It’s syntactically invalid in both languages.
Instead it should be
void jack_set_info_function( void(*func)(const char *) );
Since the documentation apparently is generated by DOxygen, it stands to reason that it's been generated from source code that compiles. If so then this is a bug in DOxygen, and a problem with the quality assurance of the library provider. However it might be a problem that lies solely with the library provider, or, I might be mistaken in the assumption that this is a C library?

issue returning CArray

I am trying to return a CArray from a function and trying to call the function from another class
short ListMaker::RetArray(CString szName, CArray<CString, CString&> &szarr_Names) {
szarr_Names.Add(szName);
return 0;
}
int main() {
//..
CArray<CString, CString&> myArray;
ListMaker LM;
short nCode = LM.RetArray(L"Name", myArray);
//..
}
I am getting following errors:
Error 1 error C2664: 'RetArray' : cannot convert parameter 2 from 'CArray<TYPE,ARG_TYPE>' to 'CArray<TYPE,ARG_TYPE>'
Error 2 error C2511: 'short RetArray(CString,CArray<TYPE,ARG_TYPE> &)' : overloaded member function not found in 'ListMaker'
Please tell me the correct way to define and access the return value of the CArray.
Erm, frist of all if RetArray is a member of ListMaker class and you call it from main(), you cannot call it like this: short nCode = RetArray(L"Name", myArray);
If RetArray is a static member, use short nCode = ListMaker::RetArray(L"Name", myArray);. It it's non-static, use instance, short nCode = listMakerInstance.RetArray(L"Name", myArray);.
Check your header file for RetArray declaration in ListMaker class. It might differ from the implementation in your cpp file, hence you get the C2511 error.
You cannot store a reference in an array type, and CArray is to be absolutely avoided at all costs as it uses memcpy to resize and not copy construction, breaking your code the instant you need something with a useful constructor.
I think the problem is in CString&, try using CArray<CString, LPCTSTR> instead.

A reference that is not to 'const' cannot be bound to a non-lvalue

Am struggling a bit with this.
Am declaring:
BYTE *pImage = NULL;
Used in call:
m_pMyInterface->GetImage(i, &imageSize, &pImage);
Visual C++ 2003 compiler error:
error C2664: 'CJrvdInterface::GetImage' : cannot convert parameter 3 from 'BYTE **__w64 ' to 'BYTE **& '
A reference that is not to 'const' cannot be bound to a non-lvalue
The method called is defined as:
void CMyInterface::GetImage(const int &a_iTileId, ULONG *a_pulImageSize,
BYTE** &a_ppbImage)
Any help much appreciated,
Bert
Because GetImage can modify it's third parameter, you need to give it something to modify:
BYTE **ppImage = &pImage;
m_pMyInterface->GetImage(i, &imageSize, ppImage);
It is possible that after your function returns, that &pImage and ppImage may no longer be the same (which also means that pImage and *ppImage may be different). If you add this:
if (ppImage)
pImage = *ppImage;
after the call, you should be good.
If CMyInterface::GetImage is your own function, depending on what you do, you may be able to change it. In your function, do you ever do:
a_ppbImage = ...;
or do you only write:
*a_ppbImage = ...;
If you only do that latter and not the former, passing a reference to a double pointer is overkill. You can either pass a reference to a single pointer (BYTE *&image) or you can pass a double pointer (BYTE **image)
If you are trying to modify the variable 'pImage' inside the method 'GetImage()' you should either be passing a pointer or a reference to it (not doing both).
What you probably want is:
BYTE *pImage = NULL;
x.GetImage(iTileId, pulImageSize, a_pImage );
With the method defined as:
void CMyInterface::GetImage(int const& a_iTileId, ULONG* a_pulImageSize, BYTE*& a_ppbImage)
{
}
PS. Be consistent where you put your & and * in type declarations.
ULONG *a_pulImageSize // Star on the right
BYTE** &a_ppbImage // Star on the left (not consistent)
Personally (and this is just my style others are different) I put everything on the left (with the type) just the variable name goes on the right.
You declared GetImage() to expect a reference to a Byte**.
void CMyInterface::GetImage(const int &a_iTileId,
ULONG *a_pulImageSize,
BYTE** &a_ppbImage);
You passed it a reference to a Byte*.
BYTE *pImage = NULL;
m_pMyInterface->GetImage(i, &imageSize, &pImage);
To make your method call work as written, you need to change your definition of GetImage() to
void CMyInterface::GetImage(const int &a_iTileId, ULONG *a_pulImageSize,
BYTE* &a_ppbImage)