Delphi Plugin API
Started by Pedja, Jun 10 2008 10:42 PM
12 replies to this topic
#1
Posted 10 June 2008 - 10:42 PM
Connect and let the others connect.
http://wireless.uzice.net, dchub://dc.uzice.net, http://www.supurovic.net, http://www.iz.rs
http://wireless.uzice.net, dchub://dc.uzice.net, http://www.supurovic.net, http://www.iz.rs
#2
#3
Posted 11 November 2008 - 01:45 PM
I've done a lot of work with Delphi (15+ years of programming experience) and I've created even dlls (plugins) for Winamp, which, I was told, was also impossible, so, why not give it a try. I can try to make one empty Delphi DLL example plugin. All I need is a current source code or any specification of plugin if such exists right now?
P.S.
I've tried to look into ApexDC source code, folder "plugins/SamplePlugin" and I have analized those files there and it seems to me that it is pretty simple. So, the only thing I need is that someone tells me if that code is the current actual code for a blank plugin or there is some new stuff, and if it is, where is it located, so I can take a look?
P.S.
I've tried to look into ApexDC source code, folder "plugins/SamplePlugin" and I have analized those files there and it seems to me that it is pretty simple. So, the only thing I need is that someone tells me if that code is the current actual code for a blank plugin or there is some new stuff, and if it is, where is it located, so I can take a look?
#4
Posted 11 November 2008 - 03:38 PM
burek, on Nov 11 2008, 02:45 PM, said:
I've done a lot of work with Delphi (15+ years of programming experience) and I've created even dlls (plugins) for Winamp, which, I was told, was also impossible, so, why not give it a try. I can try to make one empty Delphi DLL example plugin. All I need is a current source code or any specification of plugin if such exists right now?
P.S.
I've tried to look into ApexDC source code, folder "plugins/SamplePlugin" and I have analized those files there and it seems to me that it is pretty simple. So, the only thing I need is that someone tells me if that code is the current actual code for a blank plugin or there is some new stuff, and if it is, where is it located, so I can take a look?
P.S.
I've tried to look into ApexDC source code, folder "plugins/SamplePlugin" and I have analized those files there and it seems to me that it is pretty simple. So, the only thing I need is that someone tells me if that code is the current actual code for a blank plugin or there is some new stuff, and if it is, where is it located, so I can take a look?
There is quite a lot of changes... and I really don't know if you will be able to pull it off with these changes, but I hope so... for I too like the simplicity of Delphi as opposed to C++. (meaning I can create more complex plugins faster with delphi
These two are probably the biggest changes structure wise, though there a bunch of others as well...
Quote
Change: Plugins should be typesafe now (StrData, instead of std::string)
Change: Plugins a bit more RSX like now... (uses exported functions, ie. PluginAPI.lib)
Change: Plugins a bit more RSX like now... (uses exported functions, ie. PluginAPI.lib)
I think it's good to mention here that I would have preferred to use plain char pointers had it only worked well... (this is about the first listed change, which might be by far the most problematic).
In any case I have attached some stuff regarding the new way the plugins are done... including the updated sample plugin.
If you can spot any incompatibilities with delphi give a shout and I'll see if there is something to be done about it.
Unfortunately my knowledge regarding the finer points of delphi is inferior to my C++ skills, if it were otherwise I would have made sure to preserve compatibility...
PS: Also if you or others are wondering the big changes... this is because only after these changes can I consider the plugin api usable and truly useful to some. after next version there probably won't be any big changes in regards to plugins.
#5
Posted 11 November 2008 - 06:40 PM
thanx for this. can you please additionaly provide a compiled dll file, so I can check for naming conventions and declarations, to see if they match with dll created with delphi?
P.S.
What exactly was a problem using plain char pointers? Can you describe it a little bit more, please?
P.S.
What exactly was a problem using plain char pointers? Can you describe it a little bit more, please?
#6
Posted 12 November 2008 - 02:02 AM
burek, on Nov 11 2008, 06:40 PM, said:
thanx for this. can you please additionaly provide a compiled dll file, so I can check for naming conventions and declarations, to see if they match with dll created with delphi?
P.S.
What exactly was a problem using plain char pointers? Can you describe it a little bit more, please?
P.S.
What exactly was a problem using plain char pointers? Can you describe it a little bit more, please?
Well we use cdecl calling convention, and afaik Delphi supports stdcall and cdecl... so no problems there, I think.
As for using plain char pointers, when I did that the strings got mangled when passing from exe to dll... or vice versa, even though I was careful to make sure that the contents of those pointers can't be directly edited (ie. const pointer to const object... in this case char), because allowing that would naturally be risky and cause myriad of issues.
Even though I answered the question about naming, here is a compiled dll attached anyhow, if it's of any help...
#7
Posted 12 November 2008 - 11:56 AM
I've created all those exports with cdecl, but I wanted to make sure it's the same thing 
Anyway, I'm looking into the source code, especially PluginManager.cpp, to see if i can see anything odd there.
I would like to see the part of code that was dealing with passing char pointers to and from a plugin dll, so I can take a look in the code to analyze it a bit.. Can you please tell me where to look?
My first guess was it has maybe something to do with mixing unicode and ansii string pointers, but I'd like to first see the code, so I can make sure what am I talking about
Anyway, I'm looking into the source code, especially PluginManager.cpp, to see if i can see anything odd there.
I would like to see the part of code that was dealing with passing char pointers to and from a plugin dll, so I can take a look in the code to analyze it a bit.. Can you please tell me where to look?
My first guess was it has maybe something to do with mixing unicode and ansii string pointers, but I'd like to first see the code, so I can make sure what am I talking about
#8
Posted 12 November 2008 - 03:43 PM
burek, on Nov 12 2008, 12:56 PM, said:
I've created all those exports with cdecl, but I wanted to make sure it's the same thing 
Anyway, I'm looking into the source code, especially PluginManager.cpp, to see if i can see anything odd there.
I would like to see the part of code that was dealing with passing char pointers to and from a plugin dll, so I can take a look in the code to analyze it a bit.. Can you please tell me where to look?
My first guess was it has maybe something to do with mixing unicode and ansii string pointers, but I'd like to first see the code, so I can make sure what am I talking about
Anyway, I'm looking into the source code, especially PluginManager.cpp, to see if i can see anything odd there.
I would like to see the part of code that was dealing with passing char pointers to and from a plugin dll, so I can take a look in the code to analyze it a bit.. Can you please tell me where to look?
My first guess was it has maybe something to do with mixing unicode and ansii string pointers, but I'd like to first see the code, so I can make sure what am I talking about
Well I don't have that version anywhere anymore, unfortunately, but it was pretty much simply replacing std::string with char* in the function declarations (adding const, where not present) and then using .c_str() to get the const char* pointer when calling them... and again if there was need to pass a "result string" from dll back to exe ie. a modified string we would make the function return another const char* and then on exe side make const std::string out of that one (of course here we assume the plugin dll would make these returned chars anew with the PluginAPI::AllocFunc(...), since modifying the passed params would be, not impossible, but foolish).
If you need to look at PluginManager code it might be wise of me to share the new code with you, so you can see the up to date stuff in its entirety (and in full context) rather than just bits and pieces.
PS: Check you PM's
#9
Posted 15 February 2009 - 02:53 PM
I thought I'd bump this since with next version a Delphi compatibility might be possible to accomplish thus opening new doors for this feature.
#10
Posted 08 May 2009 - 10:46 AM
Hi,
I'm back again
I was busy with my work in the past months, so I couldn't afford some free time for this thing :/
Anyway, do you have any specifications about dlls, what exports should they have, which data structures should be used, etc. Do you have any documentations about that, or should I just analyze the SamplePlugin folder and see for myself?
I'm back again
Anyway, do you have any specifications about dlls, what exports should they have, which data structures should be used, etc. Do you have any documentations about that, or should I just analyze the SamplePlugin folder and see for myself?
#12
Posted 07 September 2009 - 11:11 AM
I suppose it can be done... though in that case decorated names come to play, although I suppose def file can resolve that easily enough for us.
#13
Posted 06 September 2010 - 07:26 PM
I hope I can help a bit - actually I'm using Delphi 7, not C++, so I just rewrite header file a bit for my needs.
1) Here is a code for very simple plugin.
2) I want to warn you that I don't test all functions and you may crash ApexDC++ when using it.
3) It is not a complete port for header file - only things what I need.
4) This code may a bit rough for someone, but, as I say, I did that for myself and put it here only to help anyone who don't know how to start.
5) The code below is legal only for version 1.3.6 and may be not compatible with later version of ApexDC++ - don't forget to check PluginDefs.h from latest source code package.
ApexTest.pas
PluginDefs.pas
1) Here is a code for very simple plugin.
2) I want to warn you that I don't test all functions and you may crash ApexDC++ when using it.
3) It is not a complete port for header file - only things what I need.
4) This code may a bit rough for someone, but, as I say, I did that for myself and put it here only to help anyone who don't know how to start.
5) The code below is legal only for version 1.3.6 and may be not compatible with later version of ApexDC++ - don't forget to check PluginDefs.h from latest source code package.
ApexTest.pas
library ApexTest;
uses Windows, PluginDefs;
const
PLUGIN_GUID = '{c0dec0de-c0de-c0de-c0de-c0dec0dec0de}'; // UUID/GUID for this plugin project
PLUGIN_NAME = 'ApexTest'; // Name of the plugin
PLUGIN_AUTHOR = 'Anonymous'; // Author of the plugin
PLUGIN_DESC = 'A simple Delphi test plugin with every minute message.'; // Short description about the plugin
PLUGIN_VERSION = 1.00; // Version of the plugin (note: not api version)
PLUGIN_WEB = 'N/A'; // Plugin website, set to "N/A" if none
var
dcpp: PDCCore = nil;
hook: pointer = nil;
// forward declaration for onLoad function
function pluginProc(eventID: cardinal; pData: pointer): longbool; stdcall; forward;
function onLoad(eventID: cardinal; pData: pointer): longbool;
begin
dcpp:=pData;
// set hook
If hook = nil Then hook:=dcpp^.set_hook(HOOK_TIMER, @pluginProc, nil);
result:=True;
end;
function onUnload(eventID: cardinal): longbool;
begin
// remove hook
if hook <> nil then
begin
dcpp^.un_hook(hook);
hook:=nil;
end;
result:=True;
end;
function TimerHandle: longbool;
begin
result:=True;
MessageBox(0, 'To disable this message boxes - uninstall plugin!', 'ApexTest plugin', MB_ICONINFORMATION);
end;
function pluginProc(eventID: cardinal; pData: pointer): longbool; stdcall;
begin
result:=False;
case eventId of
ON_INSTALL, ON_LOAD:
result:=onLoad(eventId, pData);
ON_UNINSTALL, ON_UNLOAD:
result:=onUnload(eventId);
TIMER_MINUTE:
result:=TimerHandle;
end;
end;
function pluginInit(info: PMetaData): pointer; stdcall;
begin
info^.name := PLUGIN_NAME;
info^.author := PLUGIN_AUTHOR;
info^.description := PLUGIN_DESC;
info^.version := PLUGIN_VERSION;
info^.web := PLUGIN_WEB;
info^.apiVersion := DCAPI_VER;
info^.compatibleVersion := DCAPI_COMPATIBLE_VER;
info^.guid := PLUGIN_GUID;
result:=@pluginProc;
end;
exports
pluginInit;
end.
PluginDefs.pas
unit PluginDefs;
interface
const
// Version of the plugin api (must change every time the API has changed)
DCAPI_VER = 0.50;
// The earliest version of the API that this version is backwards compatible with
DCAPI_COMPATIBLE_VER = 0.50;
// Hook IDs
// Mandatory callback hook
CALLBACK_BASE = 0;
// Common hooks (none manadatory, however, one required)
HOOK_PROTOCOL = 500;
HOOK_CHAT = 501;
HOOK_HUBS = 502;
HOOK_TIMER = 503;
HOOK_QUEUE = 504;
HOOK_UI = 505;
// Plugin created hooks and callbacks (HOOK_USER + n)
HOOK_USER = 1000;
// Main hook events (returned by pluginInit)
ON_INSTALL = 0; // Replaces ON_LOAD for the very first loading of the plugin
ON_UNINSTALL = 1; // Replaces ON_UNLOAD when plugin is being uninstalled
ON_LOAD = 2; // Sent after successful call to pluginInit
ON_UNLOAD = 3; // Sent right before plugin is unloaded (no params)
ON_CONFIGURE = 4; // Sent when user wants to configure the plugin (obj: obj: impl. dependant or NULL)
// Chat hook events (HOOK_CHAT)
CHAT_IN = 500; // Incoming chat from hub (obj: ClientData)
CHAT_OUT = 501; // Outgoing chat (obj: ClientData)
CHAT_PM_IN = 502; // Incoming private message (obj: UserData)
CHAT_PM_OUT = 503; // Outgoing private message (obj: UserData)
// Timer hook events (HOOK_TIMER)
TIMER_SECOND = 1000; // Timer event fired once per second (tick value)
TIMER_MINUTE = 1001; // Timer event fired once per minute (tick value)
// Hubs hook events (HOOK_HUBS)
HUB_OFFLINE = 1500; // Hub has just gone offline (obj: ClientData)
HUB_ONLINE = 1501; // (New) hub has just gone online (obj: ClientData)
// Connections hook events (HOOK_PROTOCOL)
HUB_IN = 2000; // Incoming protocol messages from hub (obj: ClientData)
HUB_OUT = 2001; // Outgoing protocol message to hub (obj: ClientData)
CONN_IN = 2002; // Incoming client<->client protocol message (obj: ConnectionData)
CONN_OUT = 2003; // Outgoing client<->client protocol message (obj: ConnectionData)
// Queue hook events (HOOK_QUEUE)
QUEUE_ADD = 2500; // (New) item has been added to download queue (obj: QueueData)
QUEUE_MOVE = 2501; // Download queue item has been moved to new location (obj: QueueData)
QUEUE_REMOVE = 2502; // Item has just been removed from download queue (obj: QueueData)
QUEUE_FINISHED = 2503; // Item has just finished downloading (obj: QueueData)
// UI hook events (HOOK_UI)
UI_CREATED = 3000; // Host node UI has been created (if any, obj: impl. dependant)
UI_CHAT_DISPLAY = 3001; // Chat messages before displayed to user (obj: StringData)
// Plugin created hook events (EVENT_USER + n)
EVENT_USER = 3500;
type
TMetaData = record
name: pchar; // Name of the plugin
author: pchar; // Name/Nick of the plugin author
description: pchar; // *Short* description of plugin functionality (may be multiple lines)
web: pchar; // Authors website if any
guid: pchar; // Plugins unique GUID
dependencies: ^pchar; // Array of plugin dependencies
numDependencies: cardinal; // Number of plugin GUIDs in dependencies array
version: double; // Plugin version
apiVersion: double; // API version the plugin was compiled against
compatibleVersion: double; // Earliest API version the plugin can be used with
End;
PMetaData = ^TMetaData;
TDCCore = record
// Core API version
apiVersion: double;
// Hook creation
create_hook: function(hookID, hookType: cardinal; defProc: pointer): pointer; stdcall;
destroy_hook: procedure(hHook: cardinal); stdcall;
// Hook interaction
set_hook: function(hookID: cardinal; hookProc, pCommon: pointer): pointer; stdcall;
call_hook: function(hookID, eventID: cardinal; pData: pointer): LongBool; stdcall;
un_hook: function(hHook: pointer): cardinal; stdcall;
// Message regitster
register_message: function(hookType: cardinal; const name: pchar): cardinal; stdcall;
register_range: function(hookType: cardinal; const name: pchar; count: cardinal): cardinal; stdcall;
seek_message: function(const name: pchar): cardinal; stdcall;
// Settings management
set_cfg: procedure(const guid, settings: pchar; cval: pointer); stdcall;
get_cfg: function(const guid, settings: pchar; cval: pointer): LongBool; stdcall;
// General
memalloc: function(P: pointer; bytes: cardinal): pointer; stdcall;
strconv: function(ctype: cardinal; dst, src: pointer; len: cardinal): cardinal; stdcall;
end;
PDCCore = ^TDCCore;
implementation
end.
1 user(s) are reading this topic
0 members, 1 guests, 0 anonymous users












