Forum: VirtualDJ Plugins

Questions about plugins development, talks with other developers etc
Topic: Getting instance of IVdjCallbacks8 to use SendCommand
Hello, I'm fairly new to working with plugins so sorry if it is a trivial question.
I'm creating a program in C++ that gets the current played song. I managed to load dll in program and have no problem in executing OnGetPluginInfo(), but when I want to send command to VirtualDJ with SendCommand() method I get exception that IVdjCallbacks8 cb was nullptr.
Now my question is how to get instance of IVdjCallbacks8* cb in order to be able to send commands and get results?
Plugin I want to access is almost the same as basic plugin example and I placed it in Plugins64\AutoStart

Inviato Thu 30 Apr 20 @ 1:45 pm
NicotuxHome userMember since 2014
What kind of plugin ?
Where do you call SendCommand () from ?

cb are not already set before OnGetPluginInfo() returned with S_OK ( plugin not initialized before that)

cb can be called from within OnLoad and following


Inviato Thu 30 Apr 20 @ 2:16 pm
The plugin is almost the same as Basic plugin (with default interface) example in VDJPedia, it inherits after IVdjPlugin8.
I call SendCommand in main in my external program after getting plugin instance from DllGetClassObject.
I called OnGetPluginInfo() only to check if I managed to load dll correctly and it worked.
So in order to use SendCommand() there must be something more in OnLoad() method in plugin?
OnLoad() from example looks like this:

HRESULT VDJ_API CMyPlugin8::OnLoad()
{
// ADD YOUR CODE HERE WHEN THE PLUGIN IS CALLED
m_Reset = 0;
m_Dry = 0.0f;
m_Wet = 0.0f;
bool bMasterFX = isMasterFX();
DeclareParameterButton(&m_Reset,ID_BUTTON_1,"Reset","R");
DeclareParameterSlider(&m_Wet,ID_SLIDER_1,"Dry/Wet","D/W",1.0f);
OnParameter(ID_SLIDER_1);
return S_OK;
}

Inviato Thu 30 Apr 20 @ 2:41 pm
NicotuxHome userMember since 2014

Are you trying to implement a wrapper ?? ( external program going to load vdj plugins) ?

from the "main" of your plugin, the DLL is loaded and the instance is created
but it is not already linked to VDJ Plugin chain (or your app's own one) thus all virtual IVdjCallbacks8 are NULL

There is nothing you can do with that because they will be overitten by VDJ only after DllGetClassObject had returned S_OK
(or if you are creating a wrapper, you need to PROVIDE the callback functions , not trying to use them before that)

Its free to the caller app to implement its own callbacks, they are there for the plugin to send command to the parent app

OnLoad can be call because all DeclareParameter* are not virtual they return NULL not trying to call the callback
but they wont declare anything




Inviato Thu 30 Apr 20 @ 3:29 pm
AdionPRO InfinityCTOMember since 2006
Just use
cb->SendCommand()

Inviato Thu 30 Apr 20 @ 3:38 pm
Yes, I'm trying to implement a wrapper, right now it looks like this:

HRESULT hr;
HMODULE vdjDLL;
CMyPlugin8* pluginInstance;

typedef HRESULT(VDJ_API* dllGetClassObjectType)(IN REFCLSID rclsid, IN REFIID riid, OUT LPVOID FAR* ppv);
vdjDLL = LoadLibrary("C:\\Users\\Cartinese\\Documents\\VirtualDJ\\Plugins64\\AutoStart\\VDJ_DLL.dll");
dllGetClassObjectType dllgetclass = (dllGetClassObjectType)GetProcAddress(vdjDLL, "DllGetClassObject");
hr = dllgetclass(CLSID_VdjPlugin8, IID_IVdjPluginBasic8, (void**)&pluginInstance);
pluginInstance->hInstance = GetModuleHandle(NULL);
pluginInstance->cb->SendCommand("get_automix_song");

And after running this I get exception:
pluginInstance->cb was nullptr.

So what needs to be done in order to use send command successfully in wrapper?

Inviato Thu 30 Apr 20 @ 3:57 pm
NicotuxHome userMember since 2014
@ adion
in DllGetClassObject cb will be null as long as no host have set the callbacks
the cb are set (cb is initialized) only once DllGetClassObject have return

these functions have to be implemented in the host and the host have init the plugin cd before they can be used
they are not sending any command to VDJ, they only pass back parameters to parent host

// Internal structures
struct IVdjCallbacks8
{
virtual HRESULT SendCommand(const char *command)=0;
...}

class IVdjPlugin8
{
...
IVdjCallbacks8 *cb;
};

Inviato Thu 30 Apr 20 @ 4:14 pm
AdionPRO InfinityCTOMember since 2006
Ah yes understood. If you instantiate the plugin, then it is indeed up to you to set cb to the correct value.

So after
hr = dllgetclass(CLSID_VdjPlugin8, IID_IVdjPluginBasic8, (void**)&pluginInstance);

You should do
pluginInstance->cb = myhandler;

And myHandler should implement the IVdjCallbacks8 interface then.

Inviato Thu 30 Apr 20 @ 4:31 pm
First, thank you both very much for your time and help, your advices help me a lot in understanding this subject.
So if I get what you say correctly, then in my wrapper I need to implement class like this:
class Myhandler
{
public:
Myhandler();
IVdjCallbacks8* cb;
};

And in main then:
Myhandler* myhandler = new Myhandler();
...
pluginInstance->cb = myhandler->cb;

I thought it would be good, but ended up with error:(

Inviato Thu 30 Apr 20 @ 5:02 pm
NicotuxHome userMember since 2014
because you NEED to implement every function you will provide to the plugin in your host

something like this (syntax OK but untested )

class MyHandler : IVdjCallbacks8 {
HRESULT MyHandler::SendCommand(const char* command) { /* do something; */ return S_OK; };
HRESULT MyHandler::GetInfo(const char* command,double* result) { /* do something; */ return S_OK; };
HRESULT MyHandler::GetStringInfo(const char* command,void* result,int size) { /* do something; */ return S_OK; };
HRESULT MyHandler::DeclareParameter(void* parameter,int type,int id,const char* name,const char* shortName,float defaultvalue) { /* do something; */ return S_OK; };
HRESULT MyHandler::GetSongBuffer(int pos, int nb, short** buffer) { /* do something; */ return S_OK; };
} myhandler;

and in main() {
...
hr = dllgetclass(CLSID_VdjPlugin8, IID_IVdjPluginBasic8, (void**)&pluginInstance);

/* Provides the cb functions to the plugin */
pluginInstance->cb = reinterpret_cast<IVdjCallbacks8*>(&myhandler);
...
}

Inviato Thu 30 Apr 20 @ 5:53 pm
Ok, so my whole main looks now like this:
class MyHandler : IVdjCallbacks8 {
HRESULT SendCommand(const char* command) { /* do something; */ return S_OK; };
HRESULT GetInfo(const char* command, double* result) { /* do something; */ return S_OK; };
HRESULT GetStringInfo(const char* command, void* result, int size) { /* do something; */ return S_OK; };
HRESULT DeclareParameter(void* parameter, int type, int id, const char* name, const char* shortName, float defaultvalue) { /* do something; */ return S_OK; };
HRESULT GetSongBuffer(int pos, int nb, short** buffer) { /* do something; */ return S_OK; };
} myhandler;

HRESULT hr;
HMODULE vdjDLL;
CMyPlugin8* pluginInstance;

typedef HRESULT(VDJ_API* dllGetClassObjectType)(IN REFCLSID rclsid, IN REFIID riid, OUT LPVOID FAR* ppv);
vdjDLL = LoadLibrary("C:\\Users\\Cartinese\\Documents\\VirtualDJ\\Plugins64\\AutoStart\\VDJ_DLL.dll");
dllGetClassObjectType dllgetclass = (dllGetClassObjectType)GetProcAddress(vdjDLL, "DllGetClassObject");
hr = dllgetclass(CLSID_VdjPlugin8, IID_IVdjPluginBasic8, (void**)&pluginInstance);
pluginInstance->cb = reinterpret_cast<IVdjCallbacks8*>(&myhandler);
pluginInstance->hInstance = GetModuleHandle(NULL);
char const* command = "get_version";
char result[20];
pluginInstance->cb->GetStringInfo(command, result, 20);

After this variable result should be something like "8.0....", but instead it equals: ĚĚĚĚĚĚĚĚĚĚĚĚĚĚĚĚĚĚĚĚ and I can't figure why.
For other commands the result is also the same Ě.


Inviato Thu 30 Apr 20 @ 11:10 pm
AdionPRO InfinityCTOMember since 2006
What is the "do something" in your GetStringInfo implementation?
Currently you didn't write anything there, so it will just leave result untouched.

Inviato Fri 01 May 20 @ 2:54 am
I tried, but have no idea what is needed in it in order to make it work.
Should it be somehow similar to implementation in base plugin?
In vdjPlugin8.h it looks like this:

HRESULT GetStringInfo(const char *command, char *result, int size) {return cb->GetStringInfo(command,result,size);}

Inviato Fri 01 May 20 @ 11:55 am
AdionPRO InfinityCTOMember since 2006
It should check what is passed in command and based on that fill in result.
I'm not sure what you are trying to achieve exactly though. You want to use vdj plugins in your own software?

Inviato Fri 01 May 20 @ 12:25 pm
Yes, I want to use vdj plugin in my software.
What I am trying to create is program (wrapper) in C++, which gets song that is playing now (and other parameters if possible but song is priority) from vdj plugin and saves it to string or txt file.
Plugin that I use is almost same as example Basic plugin (with default interface).
The reason why I'm struggling is because its my first time working with plugins.

Inviato Fri 01 May 20 @ 2:35 pm
AdionPRO InfinityCTOMember since 2006
If your program hosts the plugin, then it is your program that would be playing the songs and replying to the queries of the loaded plugin.

If you want your program to get information from VirtualDJ, then your program should be a plugin itself, not load other plugins.

Inviato Fri 01 May 20 @ 3:11 pm
Oh ok, second option is exactly what I want.
So is it possible to modify basic plugin from example to save song title to txt each time new song is played?
And if I understand correctly this solution doesn't require external program/wrapper (because plugin will do it by itself).

Inviato Fri 01 May 20 @ 3:42 pm