Jump to content


Delphi Plugin API


  • Please log in to reply
12 replies to this topic

#1 Pedja

Pedja

    Advanced

  • Member
  • PipPipPip
  • 96 posts

Posted 10 June 2008 - 10:42 PM

Anyone ported API to Delphi?

#2 Crise

Crise

    Developer

  • Management
  • 2,854 posts

Posted 11 June 2008 - 09:52 AM

View PostPedja, on Jun 10 2008, 11:42 PM, said:

Anyone ported API to Delphi?

It's not possible, and I am uncertain if it even will be, though in the long run I am aiming towards that possibility...
Crise
ApexDC++ - Lead Developer

Proud Affiliates of: TechGeeks Online, PeerWeb

#3 burek

burek

    Advanced

  • Member
  • PipPipPip
  • 99 posts

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?

#4 Crise

Crise

    Developer

  • Management
  • 2,854 posts

Posted 11 November 2008 - 03:38 PM

View Postburek, 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?


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 :P)-

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)

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.
Crise
ApexDC++ - Lead Developer

Proud Affiliates of: TechGeeks Online, PeerWeb

#5 burek

burek

    Advanced

  • Member
  • PipPipPip
  • 99 posts

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?

#6 Crise

Crise

    Developer

  • Management
  • 2,854 posts

Posted 12 November 2008 - 02:02 AM

View Postburek, 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?

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...
Crise
ApexDC++ - Lead Developer

Proud Affiliates of: TechGeeks Online, PeerWeb

#7 burek

burek

    Advanced

  • Member
  • PipPipPip
  • 99 posts

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 :P
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 Crise

Crise

    Developer

  • Management
  • 2,854 posts

Posted 12 November 2008 - 03:43 PM

View Postburek, 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 :)

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 :P
Crise
ApexDC++ - Lead Developer

Proud Affiliates of: TechGeeks Online, PeerWeb

#9 Crise

Crise

    Developer

  • Management
  • 2,854 posts

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.
Crise
ApexDC++ - Lead Developer

Proud Affiliates of: TechGeeks Online, PeerWeb

#10 burek

burek

    Advanced

  • Member
  • PipPipPip
  • 99 posts

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? :)

#11 mappy

mappy

  • Member
  • PipPip
  • 43 posts

Posted 07 September 2009 - 02:08 AM

View PostCrise, on 12 November 2008 - 02:02 AM, said:

Well we use cdecl calling convention, and afaik Delphi supports stdcall and cdecl... so no problems there, I think.

stdcall would open you up to VB plugins as well.
My Projects: jmDC | More

#12 Crise

Crise

    Developer

  • Management
  • 2,854 posts

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.
Crise
ApexDC++ - Lead Developer

Proud Affiliates of: TechGeeks Online, PeerWeb

#13 spktbl

spktbl

    Newbie

  • Member
  • Pip
  • 5 posts

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
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