unit UnitPlugins;

interface

uses SysUtils, Classes, Windows, Messages, Forms, ComCtrls;

type TCodeSnippetClick = function (pTitle, pCategory: PChar; pCode: PChar): Integer; cdecl;
     TFileAction = function (pFilename: PChar): Integer; cdecl;
     TDocChange = function (pIndex: Integer; pFilename: PChar; pHighlighter: PChar; pRestoreCaret: Boolean): Integer; cdecl;
     TProjectsChange = function (pOldIndex, pNewIndex: Integer): Integer; cdecl;
     TCreateNewFile = function (Item: Byte): Integer; cdecl;
     TDisplaySearch = function (pSearchList: PChar; pSelected: PChar): Integer; cdecl;
     TSearch = function (pExpression, pSearchList: PChar; pCaseSensivity, pWholeWords, pSearchFromCaret, pSelectedOnly, pRegEx, pForward: Boolean): Integer; cdecl;
     TSearchReplace = function (pExpression, pReplace, pExpList, pRepList: PChar; pCaseSensivity, pWholeWords, pSearchFromCaret, pSelectedOnly, pRegEx, pForward: Boolean): Integer; cdecl;
     TVisibleControlChange = function (pControl: Integer; pShow: Boolean): Integer; cdecl;
     TCompile = function (pCompileType: Integer; Lang, Filename: PChar): Integer; cdecl;
     TShowHelp = function (pHelpType: Integer): Integer; cdecl;
     TCustomItemClick = function (pCaption: PChar): Integer; cdecl;
     TThemeChanged = function (pTheme: PChar): Integer; cdecl;

     TModified = function (pModifiedText: PChar): Integer; cdecl;
     TKeyPress = function (pKey: PChar): Integer; cdecl;
     TEditorClick = function: Integer; cdecl;
     TUpdateSel = function (pSelStart, pSelLength, pFirstVisibleLine: Integer): Integer; cdecl;
     TCallTipShow = function (pList: PChar): Integer; cdecl;
     TCallTipClick = function (pPosition: Integer): Integer; cdecl;
     TAutoCompleteShow = function (pList: PChar): Integer; cdecl;
     TAutoCompleteSelect = function (pText: PChar): Integer; cdecl;

     TAppMsg = function (pHwnd: HWND; pMessage: Integer; pWParam, pLParam: Integer; pTime: Integer; pPt: TPoint): Integer; cdecl;
     TUpdateCodeTools = function (pLang, pFilename, pCurrProjects: PChar): Integer; cdecl;
     TOutputEvent = function (pItemIndex: Integer): Integer; cdecl;

type TIntegerArray = array of Integer;

type TLoadInfo = record
  { Plugin values }
  sPluginName: PChar;
  sPluginDescription: PChar;
  { Form Handles }
  hAllFilesForm: HWND;
  hAutoIndent: HWND;
  hClose: HWND;
  hConnGen: HWND;
  hGoToLine: HWND;
  hHTMLPreview: HWND;
  hHudMsgGenerator: HWND;
  hInfo: HWND;
  hIRCPaster: HWND;
  hMainForm: HWND;
  hMenuGenerator: HWND;
  hMOTDGen: HWND;
  hPluginsIniEditor: HWND;
  hReplace: HWND;
  hSearch: HWND;
  hSelectColor: HWND;
  hSettings: HWND;
  hSocketsTerminal: HWND;
  hSplashscreen: HWND;
  { Important Control Handles }
  hOutput: HWND;
  hCodeExplorer: HWND;
  hCodeInspector: HWND; // even if it won't be useful
  hNotes: HWND;
  { Other }
  pApplication: Pointer; // this is only useful for Delphi developers
end;

type PLoadInfo = ^TLoadInfo;
     TLoadPlugin = procedure (LoadInfo: PLoadInfo); cdecl;
     TUnloadPlugin = procedure; cdecl;

function SendStudioMsg(eMessage: Integer; eData: String; eIntData: Integer): Integer;

function LoadPlugin(ListItem: TListItem): Boolean;
procedure UnloadPlugin(ListItem: TListItem);

function Plugin_CodeSnippetClick(Title, Category: String; Code: String): Boolean;
function Plugin_FileLoad(Filename: String; Loading: Boolean): Boolean;
function Plugin_FileSave(Filename: String; Saving: Boolean): Boolean;
function Plugin_DocChange(Index: Integer; Filename, Highlighter: String; RestoreCaret, Changing: Boolean): Boolean;
function Plugin_ProjectsChange(OldIndex, NewIndex: Integer; Changing: Boolean): Boolean;
function Plugin_CreateNewFile(Item: Byte; Creating: Boolean): Boolean;
function Plugin_Search(SearchList, Selected: String; Displaying, SearchAgain: Boolean; CaseSensivity, WholeWords, SearchFromCaret, SelectedOnly, RegEx, Forward: Boolean): Boolean;
function Plugin_SearchReplace(Expression, Replace, ExpList, RepList: String; CaseSensivity, WholeWords, SearchFromCaret, SelectedOnly, RegEx, Forward: Boolean): Boolean;
function Plugin_VisibleControlChange(Control: Integer; Show: Boolean): Boolean;
function Plugin_Compile(CompileType: Integer; Lang, Filename: String; Compiling: Boolean): Boolean;
function Plugin_ShowHelp(HelpType: Integer): Boolean;
function Plugin_CustomItemClick(Caption: String): Boolean;
function Plugin_ThemeChange(Theme: String): Boolean;

function Plugin_Modified(ModifiedStr: PAnsiChar): Boolean;
function Plugin_KeyPress(Key: Char): Boolean;
function Plugin_EditorClick(DoubleClick: Boolean): Boolean;
function Plugin_UpdateSel(SelStart, SelLength, FirstVisibleLine: Integer): Boolean;
function Plugin_CallTipShow(List: PChar): Boolean;
function Plugin_CallTipClick(Position: Integer): Boolean;
function Plugin_AutoCompleteShow(List: PChar): Boolean;
function Plugin_AutoCompleteSelect(Text: PChar): Boolean;

function Plugin_AppMsg(hwnd: HWND; Message: Integer; wParam, lParam: Integer; time: Integer; pt: TPoint): Boolean;
function Plugin_UpdateCodeExplorer(Lang, Filename, CurrProjects: String; Updating: Boolean): Boolean;
function Plugin_UpdateCodeInspector(Lang, Filename, CurrProjects: String; Updating: Boolean): Boolean;
function Plugin_OutputDblClick(ItemIndex: Integer): Boolean;
function Plugin_OutputPopup(ItemIndex: Integer): Boolean;

const { Return values for dlls }
      PLUGIN_CONTINUE = 0; // continue...
      PLUGIN_STOP = 1; // stop calling funcs and don't handle the command
      PLUGIN_HANDLED = 2; // don't handle the command
      { Compile values }
      COMP_DEFAULT = 0;
      COMP_STARTHL = 1;
      COMP_UPLOAD = 2;
      { Help values }
      HELP_DEFAULT = 0;
      HELP_SEARCH = 1;
      HELP_FORUMS = 2;
      HELP_ABOUT = 3;
      { Controls for visible state }
      CTRL_OUTPUT = 0; // Output list
      CTRL_CODETOOLS_MAIN = 1; // Code-Tools window
      CTRL_CODETOOLS_ITEM = 2; // Code-Tools tab
      CTRL_NOTES = 3; // Notes tab
      { Languages }
      NEW_PAWN_PLUGIN = 0;
      NEW_PAWN_EMPTYPLUGIN = 1;
      NEW_PAWN_HEADER = 2;
      NEW_CPP_MODULE = 3;
      NEW_CPP_UNIT = 4;
      NEW_CPP_HEADER = 5;
      NEW_OTHER_TEXTFILE = 6;
      NEW_OTHER_HTML = 7;
      NEW_OTHER_SQL = 8;
      NEW_OTHER_XML = 9;

const SCM_SHOWPROGRESS = WM_USER + $100;
      SCM_HIDEPROGRESS = WM_USER + $101;
      SCM_UPDATEPROGRESS = WM_USER + $102;
      SCM_LOADCODESNIPPETS = WM_USER + $103;
      SCM_CODESNIPPETCLICK = WM_USER + $104;
      SCM_MIRC_CMD = 	WM_USER + $105;
      SCM_RELOADINI = WM_USER + $106;
      SCM_SELECTLANGUAGE = WM_USER + $107;
      SCM_LOADFILE = WM_USER + $108;
      SCM_CURRPROJECTS = WM_USER + $109;
      SCM_COMPILE = WM_USER + $110;
      SCM_COMPILE_UPLOAD = WM_USER + $111;
      SCM_COMPILE_STARTHL = WM_USER + $112;
      SCM_MENU_LOADIMAGE = WM_USER + $113;
      SCM_MENU_ADDITEM = WM_USER + $114;
      SCM_MENU_ADDSUBITEM = WM_USER + $115;
      SCM_MENU_FAKECLICK = WM_USER + $116;
      SCM_MENU_SHOWITEM = WM_USER + $117;
      SCM_MENU_HIDEITEM = WM_USER + $118;
      SCM_PLUGIN_LOAD = 	WM_USER + $119;
      SCM_PLUGIN_UNLOAD = WM_USER + $120;
      SCM_SETTINGS_CREATEPAGE = WM_USER + $121;
      SCM_CODEINSPECTOR_CLEAR = WM_USER + $122;
      SCM_CODEINSPECTOR_ADD = WM_USER + $123;
      SCM_CODEINSPECTOR_ADDCOMBO = WM_USER + $124;
      SCM_CODEINSPECTOR_SETVALUE = WM_USER + $125;
      SCM_CODEINSPECTOR_SETNAME = WM_USER + $126;
      SCM_CODEINSPECTOR_GETVALUE = WM_USER + $127;
      SCM_CODEINSPECTOR_GETNAME = WM_USER + $128;
      SCM_CODEINSPECTOR_COUNT = WM_USER + $129;
      SCM_CODEINSPECTOR_BEGINUPDATE	= WM_USER + $130;
      SCM_CODEINSPECTOR_ENDUPDATE = WM_USER + $131;
      SCM_CODEINSPECTOR_DELETE = WM_USER + $132;

      SCM_PAWN_NEWFILE = WM_USER + $133;
      SCM_PAWN_SAVEFILE = WM_USER + $134;
      SCM_PAWN_CLOSEFILE = WM_USER + $135;
      SCM_PAWN_ISUNTITLED = WM_USER + $136;
      SCM_PAWN_ACTIVATE = WM_USER + $137;
      SCM_PAWN_ACTIVATEDOC = WM_USER + $138;
      SCM_PAWN_GETNOTES = WM_USER + $139;
      SCM_PAWN_SETNOTES = WM_USER + $140;
      SCM_PAWN_GETFILENAME = WM_USER + $141;
      SCM_PAWN_SETFILENAME = WM_USER + $142;
      SCM_PAWN_GETTEXT = WM_USER + $143;
      SCM_PAWN_SETTEXT = WM_USER + $144;

      SCM_CPP_NEWFILE = WM_USER + $145;
      SCM_CPP_SAVEFILE = WM_USER + $146;
      SCM_CPP_CLOSEFILE = WM_USER + $147;
      SCM_CPP_ISUNTITLED = WM_USER + $148;
      SCM_CPP_ACTIVATE = WM_USER + $149;
      SCM_CPP_ACTIVATEDOC = WM_USER + $150;
      SCM_CPP_ACTIVATEIDE = WM_USER + $151;
      SCM_CPP_GETNOTES = WM_USER + $152;
      SCM_CPP_SETNOTES = WM_USER + $153;
      SCM_CPP_GETFILENAME = WM_USER + $154;
      SCM_CPP_SETFILENAME = WM_USER + $155;
      SCM_CPP_GETTEXT = 	WM_USER + $156;
      SCM_CPP_SETTEXT = 	WM_USER + $157;

      SCM_OTHER_NEWFILE = WM_USER + $158;
      SCM_OTHER_SAVEFILE = WM_USER + $159;
      SCM_OTHER_CLOSEFILE = WM_USER + $160;
      SCM_OTHER_ISUNTITLED = WM_USER + $161;
      SCM_OTHER_ACTIVATE = WM_USER + $162;
      SCM_OTHER_ACTIVATEDOC = WM_USER + $163;
      SCM_OTHER_GETNOTES = WM_USER + $164;
      SCM_OTHER_SETNOTES = WM_USER + $165;
      SCM_OTHER_GETFILENAME = WM_USER + $166;
      SCM_OTHER_SETFILENAME = WM_USER + $167;
      SCM_OTHER_GETTEXT = WM_USER + $168;
      SCM_OTHER_SETTEXT = WM_USER + $169;

      SCM_OUTPUT_SHOW = WM_USER + $170;
      SCM_OUTPUT_HIDE = WM_USER + $171;
      SCM_OUTPUT_ADD = 	WM_USER + $172;
      SCM_OUTPUT_CLEAR = WM_USER + $173;
      SCM_OUTPUT_DELETE = WM_USER + $174;
      SCM_OUTPUT_GETTEXT = WM_USER + $175;
      SCM_OUTPUT_GETITEM = WM_USER + $176;
      SCM_OUTPUT_INDEXOF = WM_USER + $177;
      SCM_ACTIVE_DOCUMENT = WM_USER + $178;
      SCM_ACTIVE_PROJECTS = WM_USER + $179;
      SCM_EDITOR_SETTEXT = WM_USER + $180;
      SCM_EDITOR_GETTEXT = WM_USER + $181;
      SCM_EDTIOR_SETCALLTIPS = WM_USER + $182;
      SCM_EDITOR_SHOWCALLTIP = WM_USER + $183;
      SCM_EDITOR_SETAUTOCOMPLETE = WM_USER + $184;
      SCM_EDITOR_SHOWAUTOCOMPLETE = WM_USER + $185;
      SCM_EDITOR_GETSELSTART = WM_USER + $186;
      SCM_EDTIOR_GETSELLENGTH = WM_USER + $187;
      SCM_EDITOR_SETSELSTART = WM_USER + $188;
      SCM_EDITOR_SETSELLENGH = WM_USER + $189;

      SCM_REMOVE_MENUITEM = WM_USER + $190;
      SCM_REMOVE_IMAGE = WM_USER + $191;
      SCM_SETTHEME = WM_USER + $192;
      SCM_GETTHEME = WM_USER + $193;

implementation

uses UnitfrmSettings, UnitMainTools, UnitfrmAllFilesForm,
  UnitfrmAutoIndent, UnitfrmClose, UnitfrmConnGen, UnitfrmGoToLine,
  UnitfrmHTMLPreview, UnitfrmHudMsgGenerator, UnitfrmInfo, UnitfrmMain,
  UnitfrmMenuGenerator, UnitfrmMOTDGen, UnitfrmPluginsIniEditor,
  UnitfrmReplace, UnitfrmSearch, UnitfrmSelectColor,
  UnitfrmSocketsTerminal, UnitfrmSplashscreen, UnitLanguages,
  UnitCodeExplorerUpdater, UnitCodeInspector, UnitCodeSnippets,
  UnitCodeUtils, UnitCompile, UnitfrmIRCPaster, UnitMenuGenerators,
  UnitReadThread, UnitTextAnalyze;

function LoadPlugin(ListItem: TListItem): Boolean;
var eLoadInfo: TLoadInfo;
    LoadInfo: PLoadInfo;
    eHandle: Cardinal;
    eFunc, eFunc2: TLoadPlugin;
begin
  Result := False;

  with eLoadInfo do begin
    sPluginName := 'Untitled';
    sPluginDescription := 'No description';
    { Handles }
    hAllFilesForm := frmAllFilesForm.Handle;
    hAutoIndent := frmAutoIndent.Handle;
    hClose := frmClose.Handle;
    hConnGen := frmConnGen.Handle;
    hGoToLine := frmGoToLine.Handle;
    hHTMLPreview := frmHTMLPreview.Handle;
    hHudMsgGenerator := frmHudMsgGenerator.Handle;
    hInfo := frmInfo.Handle;
    hIRCPaster := frmIRCPaster.Handle;
    hMainForm := frmMain.Handle;
    hMenuGenerator := frmMenuGenerator.Handle;
    hMOTDGen := frmMOTDGen.Handle;
    hPluginsIniEditor := frmPluginsIniEditor.Handle;
    hReplace := frmReplace.Handle;
    hSearch := frmSearch.Handle;
    hSelectColor := frmSelectColor.Handle;
    hSettings := frmSettings.Handle;
    hSocketsTerminal := frmSocketsTerminal.Handle;
    hSplashscreen := frmSplashscreen.Handle;
    { Important Control Handles }
    hOutput := frmMain.lstOutput.Handle;
    hCodeExplorer := frmMain.trvExplorer.Handle;
    hCodeInspector := frmMain.jviCode.Handle; // even if it won't be useful
    hNotes := frmMain.rtfNotes.Handle;
    { Other }
    pApplication := @Application; // this is only useful for Delphi developers
  end;

  eHandle := LoadLibrary(PChar(ExtractFilePath(ParamStr(0)) + 'plugins\' + ListItem.SubItems[0]));
  if eHandle = 0 then exit;
  @eFunc := GetProcAddress(eHandle, 'PluginLoad');
  @eFunc2 := GetProcAddress(eHandle, 'PluginUnload');
  
  if @eFunc2 <> nil then begin
    if @eFunc <> nil then begin
      try
        LoadInfo := @eLoadInfo;
        eFunc(LoadInfo);
        ListItem.Data := Pointer(eHandle);
        ListItem.Caption := eLoadInfo.sPluginName;
        ListItem.SubItems[1] := eLoadInfo.sPluginDescription;
        ListItem.SubItems[2] := 'Loaded';
      except
        on E: Exception do
          Application.MessageBox(PChar(E.Message), PChar(Application.Title), MB_ICONERROR);
      end;
    end
    else
      MessageBox(Application.Handle, PChar('Error loading plugin:' + #13 + 'PluginLoad function not found.'), PChar(ExtractFileName(ExtractFilePath(ParamStr(0)) + 'plugins\' + ListItem.SubItems[0])), MB_ICONERROR);
  end
  else
    MessageBox(Application.Handle, PChar('Error loading plugin:' + #13 + 'PluginUnload function not found.'), PChar(ExtractFileName(ExtractFilePath(ParamStr(0)) + 'plugins\' + ListItem.SubItems[0])), MB_ICONERROR);
end;

procedure UnloadPlugin(ListItem: TListItem);
var eFunc: TUnloadPlugin;
begin
  @eFunc := GetProcAddress(Cardinal(ListItem.Data), 'PluginUnload');
  if @eFunc <> nil then
    eFunc;
  FreeLibrary(Cardinal(ListItem.Data));
  
  ListItem.Data := nil;
  ListItem.Caption := '-';
  ListItem.SubItems[1] := '-';
  ListItem.SubItems[2] := 'Unloaded';
end;

function SendStudioMsg(eMessage: Integer; eData: String; eIntData: Integer): Integer;
var eStudioHandle: HWND;
    eCopyDataStruct: TCopyDataStruct;
begin
  with eCopyDataStruct do begin
    dwData := eIntData;  
    cbData := Length(eData) + 1;
    lpData := PChar(eData);  
  end;  

  eStudioHandle := FindWindow('TfrmMain', 'AMXX-Studio');
  if eStudioHandle <> 0 then
    Result := SendMessage(eStudioHandle, WM_COPYDATA, eMessage, LongInt(@eCopyDataStruct))
  else
    Result := 0;
end;


function GetDLLHandles: TIntegerArray;
var i, eCount: integer;
begin
  SetLength(Result, 0);
  eCount := 0;

  if not Started then exit;

  for i := 0 to frmSettings.lvPlugins.Items.Count -1 do begin
    if frmSettings.lvPlugins.Items[i].Data <> nil then begin
      SetLength(Result, eCount +1);
      Result[eCount] := Cardinal(frmSettings.lvPlugins.Items[i].Data);
      Inc(eCount, 1);
    end;
  end;
end;

function Plugin_CodeSnippetClick(Title, Category: String; Code: String): Boolean;
var Func: TCodeSnippetClick;
    i: integer;
    Handles: TIntegerArray;
begin
  Result := True;

  Handles := GetDLLHandles;
  for i := 0 to High(Handles) do begin
    @Func := GetProcAddress(Handles[i], 'CodeSnippetClick');

    if @Func <> nil then begin
      case Func(PChar(Title), PChar(Category), PChar(Code)) of
        PLUGIN_HANDLED: Result := False;
        PLUGIN_STOP: begin
          Result := False;
          exit;
        end;
      end;
    end;
  end;
  SetLength(Handles, 0);
  Handles := nil;
end;

function Plugin_FileLoad(Filename: String; Loading: Boolean): Boolean;
var Func: TFileAction;
    i: integer;
    Handles: TIntegerArray;
begin
  Result := True;

  Handles := GetDLLHandles;
  for i := 0 to High(Handles) do begin
    if Loading then
      @Func := GetProcAddress(Handles[i], 'Loading')
    else
      @Func := GetProcAddress(Handles[i], 'Loaded');

    if @Func <> nil then begin
      case Func(PChar(Filename)) of
        PLUGIN_HANDLED: Result := False;
        PLUGIN_STOP: begin
          Result := False;
          exit;
        end;
      end;
    end;
  end;
  SetLength(Handles, 0);
  Handles := nil;
end;

function Plugin_FileSave(Filename: String; Saving: Boolean): Boolean;
var Func: TFileAction;
    i: integer;
    Handles: TIntegerArray;
begin
  Result := True;

  Handles := GetDLLHandles;
  for i := 0 to High(Handles) do begin
    if Saving then
      @Func := GetProcAddress(Handles[i], 'Saving')
    else
      @Func := GetProcAddress(Handles[i], 'Saved');

    if @Func <> nil then begin
      case Func(PChar(Filename)) of
        PLUGIN_HANDLED: Result := False;
        PLUGIN_STOP: begin
          Result := False;
          exit;
        end;
      end;
    end;
  end;
  SetLength(Handles, 0);
  Handles := nil;
end;

function Plugin_DocChange(Index: Integer; Filename, Highlighter: String; RestoreCaret, Changing: Boolean): Boolean;
var Func: TDocChange;
    i: integer;
    Handles: TIntegerArray;
begin
  Result := True;

  Handles := GetDLLHandles;
  for i := 0 to High(Handles) do begin
    if Changing then
      @Func := GetProcAddress(Handles[i], 'DocChanging')
    else
      @Func := GetProcAddress(Handles[i], 'DocChanged');

    if @Func <> nil then begin
      case Func(Index, PChar(Filename), PChar(Highlighter), RestoreCaret) of
        PLUGIN_HANDLED: Result := False;
        PLUGIN_STOP: begin
          Result := False;
          exit;
        end;
      end;
    end;
  end;
  SetLength(Handles, 0);
  Handles := nil;
end;

function Plugin_ProjectsChange(OldIndex, NewIndex: Integer; Changing: Boolean): Boolean;
var Func: TProjectsChange;
    i: integer;
    Handles: TIntegerArray;
begin
  Result := True;

  Handles := GetDLLHandles;
  for i := 0 to High(Handles) do begin
    if Changing then
      @Func := GetProcAddress(Handles[i], 'ProjectsChanging')
    else
      @Func := GetProcAddress(Handles[i], 'ProjectsChanged');

    if @Func <> nil then begin
      case Func(OldIndex, NewIndex) of
        PLUGIN_HANDLED: Result := False;
        PLUGIN_STOP: begin
          Result := False;
          exit;
        end;
      end;
    end;
  end;
  SetLength(Handles, 0);
  Handles := nil;
end;

function Plugin_CreateNewFile(Item: Byte; Creating: Boolean): Boolean;
var Func: TCreateNewFile;
    i: integer;
    Handles: TIntegerArray;
begin
  Result := True;

  Handles := GetDLLHandles;
  for i := 0 to High(Handles) do begin
    if Creating then
      @Func := GetProcAddress(Handles[i], 'CreatingNewFile')
    else
      @Func := GetProcAddress(Handles[i], 'CreatedNewFile');

    if @Func <> nil then begin
      case Func(Item) of
        PLUGIN_HANDLED: Result := False;
        PLUGIN_STOP: begin
          Result := False;
          exit;
        end;
      end;
    end;
  end;
  SetLength(Handles, 0);
  Handles := nil;
end;

function Plugin_Search(SearchList, Selected: String; Displaying, SearchAgain: Boolean; CaseSensivity, WholeWords, SearchFromCaret, SelectedOnly, RegEx, Forward: Boolean): Boolean;
var Func: TSearch;
    i: integer;
    Handles: TIntegerArray;
begin
  Result := True;

  Handles := GetDLLHandles;
  for i := 0 to High(Handles) do begin
    if Displaying then
      @Func := GetProcAddress(Handles[i], 'DisplayingSearch')
    else if SearchAgain then
      @Func := GetProcAddress(Handles[i], 'SearchAgain')
    else
      @Func := GetProcAddress(Handles[i], 'Search');

    if @Func <> nil then begin
      case Func(PChar(Selected), PChar(SearchList), CaseSensivity, WholeWords, SearchFromCaret, SelectedOnly, RegEx, Forward) of
        PLUGIN_HANDLED: Result := False;
        PLUGIN_STOP: begin
          Result := False;
          exit;
        end;
      end;
    end;
  end;
  SetLength(Handles, 0);
  Handles := nil;
end;

function Plugin_SearchReplace(Expression, Replace, ExpList, RepList: String; CaseSensivity, WholeWords, SearchFromCaret, SelectedOnly, RegEx, Forward: Boolean): Boolean;
var Func: TSearchReplace;
    i: integer;
    Handles: TIntegerArray;
begin
  Result := True;

  Handles := GetDLLHandles;
  for i := 0 to High(Handles) do begin
    @Func := GetProcAddress(Handles[i], 'SearchReplace');

    if @Func <> nil then begin
      case Func(PChar(Expression), PChar(Replace), PChar(ExpList), PChar(RepList), CaseSensivity, WholeWords, SearchFromCaret, SelectedOnly, RegEx, Forward)  of
        PLUGIN_HANDLED: Result := False;
        PLUGIN_STOP: begin
          Result := False;
          exit;
        end;
      end;
    end;
  end;
  SetLength(Handles, 0);
  Handles := nil;
end;

function Plugin_VisibleControlChange(Control: Integer; Show: Boolean): Boolean;
var Func: TVisibleControlChange;
    i: integer;
    Handles: TIntegerArray;
begin
  Result := True;

  Handles := GetDLLHandles;
  for i := 0 to High(Handles) do begin
    @Func := GetProcAddress(Handles[i], 'VisibleControlChange');

    if @Func <> nil then begin
      case Func(Control, Show)  of
        PLUGIN_HANDLED: Result := False;
        PLUGIN_STOP: begin
          Result := False;
          exit;
        end;
      end;
    end;
  end;
  SetLength(Handles, 0);
  Handles := nil;
end;

function Plugin_Compile(CompileType: Integer; Lang, Filename: String; Compiling: Boolean): Boolean;
var Func: TCompile;
    i: integer;
    Handles: TIntegerArray;
begin
  Result := True;

  Handles := GetDLLHandles;
  for i := 0 to High(Handles) do begin
    if Compiling then
      @Func := GetProcAddress(Handles[i], 'Compiling')
    else
      @Func := GetProcAddress(Handles[i], 'Compile');

    if @Func <> nil then begin
      case Func(CompileType, PChar(Lang), PChar(Filename))  of
        PLUGIN_HANDLED: Result := False;
        PLUGIN_STOP: begin
          Result := False;
          exit;
        end;
      end;
    end;
  end;
  SetLength(Handles, 0);
  Handles := nil;
end;

function Plugin_ShowHelp(HelpType: Integer): Boolean;
var Func: TShowHelp;
    i: integer;
    Handles: TIntegerArray;
begin
  Result := True;

  Handles := GetDLLHandles;
  for i := 0 to High(Handles) do begin
    @Func := GetProcAddress(Handles[i], 'ShowHelp');

    if @Func <> nil then begin
      case Func(HelpType)  of
        PLUGIN_HANDLED: Result := False;
        PLUGIN_STOP: begin
          Result := False;
          exit;
        end;
      end;
    end;
  end;
  SetLength(Handles, 0);
  Handles := nil;
end;

function Plugin_CustomItemClick(Caption: String): Boolean;
var Func: TCustomItemClick;
    i: integer;
    Handles: TIntegerArray;
begin
  Result := True;

  Handles := GetDLLHandles;
  for i := 0 to High(Handles) do begin
    @Func := GetProcAddress(Handles[i], 'CustomItemClick');

    if @Func <> nil then begin
      case Func(PChar(Caption))  of
        PLUGIN_HANDLED: Result := False;
        PLUGIN_STOP: begin
          Result := False;
          exit;
        end;
      end;
    end;
  end;
  SetLength(Handles, 0);
  Handles := nil;
end;

function Plugin_ThemeChange(Theme: String): Boolean;
var Func: TThemeChanged;
    i: integer;
    Handles: TIntegerArray;
begin
  Result := True;

  Handles := GetDLLHandles;
  for i := 0 to High(Handles) do begin
    @Func := GetProcAddress(Handles[i], 'ThemeChanged');

    if @Func <> nil then begin
      case Func(PChar(Theme))  of
        PLUGIN_HANDLED: Result := False;
        PLUGIN_STOP: begin
          Result := False;
          exit;
        end;
      end;
    end;
  end;
  SetLength(Handles, 0);
  Handles := nil;
end;

function Plugin_Modified(ModifiedStr: PAnsiChar): Boolean;
var Func: TModified;
    i: integer;
    Handles: TIntegerArray;
begin
  Result := True;

  Handles := GetDLLHandles;
  for i := 0 to High(Handles) do begin
    @Func := GetProcAddress(Handles[i], 'Modified');

    if @Func <> nil then begin
      case Func(ModifiedStr)  of
        PLUGIN_HANDLED: Result := False;
        PLUGIN_STOP: begin
          Result := False;
          exit;
        end;
      end;
    end;
  end;
  SetLength(Handles, 0);
  Handles := nil;
end;

function Plugin_KeyPress(Key: Char): Boolean;
var Func: TKeyPress;
    i: integer;
    Handles: TIntegerArray;
begin
  Result := True;

  Handles := GetDLLHandles;
  for i := 0 to High(Handles) do begin
    @Func := GetProcAddress(Handles[i], 'KeyPress');

    if @Func <> nil then begin
      case Func(PChar(String(Key)))  of
        PLUGIN_HANDLED: Result := False;
        PLUGIN_STOP: begin
          Result := False;
          exit;
        end;
      end;
    end;
  end;
  SetLength(Handles, 0);
  Handles := nil;
end;

function Plugin_EditorClick(DoubleClick: Boolean): Boolean;
var Func: TEditorClick;
    i: integer;
    Handles: TIntegerArray;
begin
  Result := True;

  Handles := GetDLLHandles;
  for i := 0 to High(Handles) do begin
    if DoubleClick then
      @Func := GetProcAddress(Handles[i], 'DoubleClick')
    else
      @Func := GetProcAddress(Handles[i], 'Click');

    if @Func <> nil then begin
      case Func of
        PLUGIN_HANDLED: Result := False;
        PLUGIN_STOP: begin
          Result := False;
          exit;
        end;
      end;
    end;
  end;
  SetLength(Handles, 0);
  Handles := nil;
end;

function Plugin_UpdateSel(SelStart, SelLength, FirstVisibleLine: Integer): Boolean;
var Func: TUpdateSel;
    i: integer;
    Handles: TIntegerArray;
begin
  Result := True;

  Handles := GetDLLHandles;
  for i := 0 to High(Handles) do begin
    @Func := GetProcAddress(Handles[i], 'UpdateSel');

    if @Func <> nil then begin
      case Func(SelStart, SelLength, FirstVisibleLine)  of
        PLUGIN_HANDLED: Result := False;
        PLUGIN_STOP: begin
          Result := False;
          exit;
        end;
      end;
    end;
  end;
  SetLength(Handles, 0);
  Handles := nil;
end;

function Plugin_CallTipShow(List: PChar): Boolean;
var Func: TCallTipShow;
    i: integer;
    Handles: TIntegerArray;
begin
  Result := True;

  Handles := GetDLLHandles;
  for i := 0 to High(Handles) do begin
    @Func := GetProcAddress(Handles[i], 'CallTipShow');

    if @Func <> nil then begin
      case Func(List)  of
        PLUGIN_HANDLED: Result := False;
        PLUGIN_STOP: begin
          Result := False;
          exit;
        end;
      end;
    end;
  end;
  SetLength(Handles, 0);
  Handles := nil;
end;

function Plugin_CallTipClick(Position: Integer): Boolean;
var Func: TCallTipClick;
    i: integer;
    Handles: TIntegerArray;
begin
  Result := True;

  Handles := GetDLLHandles;
  for i := 0 to High(Handles) do begin
    @Func := GetProcAddress(Handles[i], 'CallTipClick');

    if @Func <> nil then begin
      case Func(Position)  of
        PLUGIN_HANDLED: Result := False;
        PLUGIN_STOP: begin
          Result := False;
          exit;
        end;
      end;
    end;
  end;
  SetLength(Handles, 0);
  Handles := nil;
end;

function Plugin_AutoCompleteShow(List: PChar): Boolean;
var Func: TAutoCompleteShow;
    i: integer;
    Handles: TIntegerArray;
begin
  Result := True;

  Handles := GetDLLHandles;
  for i := 0 to High(Handles) do begin
    @Func := GetProcAddress(Handles[i], 'AutoCompleteShow');

    if @Func <> nil then begin
      case Func(List)  of
        PLUGIN_HANDLED: Result := False;
        PLUGIN_STOP: begin
          Result := False;
          exit;
        end;
      end;
    end;
  end;
  SetLength(Handles, 0);
  Handles := nil;
end;

function Plugin_AutoCompleteSelect(Text: PChar): Boolean;
var Func: TAutoCompleteSelect;
    i: integer;
    Handles: TIntegerArray;
begin
  Result := True;

  Handles := GetDLLHandles;
  for i := 0 to High(Handles) do begin
    @Func := GetProcAddress(Handles[i], 'AutoCompleteSelect');

    if @Func <> nil then begin
      case Func(Text)  of
        PLUGIN_HANDLED: Result := False;
        PLUGIN_STOP: begin
          Result := False;
          exit;
        end;
      end;
    end;
  end;
  SetLength(Handles, 0);
  Handles := nil;
end;

function Plugin_AppMsg(hwnd: HWND; Message: Integer; wParam, lParam: Integer; time: Integer; pt: TPoint): Boolean;
var Func: TAppMsg;
    i: integer;
    Handles: TIntegerArray;
begin
  Result := True;

  Handles := GetDLLHandles;
  for i := 0 to High(Handles) do begin
    @Func := GetProcAddress(Handles[i], 'AppMessage');

    if @Func <> nil then begin
      case Func(hwnd, Message, wParam, lParam, time, pt)  of
        PLUGIN_HANDLED: Result := False;
        PLUGIN_STOP: begin
          Result := False;
          exit;
        end;
      end;
    end;
  end;
  SetLength(Handles, 0);
  Handles := nil;
end;

function Plugin_UpdateCodeExplorer(Lang, Filename, CurrProjects: String; Updating: Boolean): Boolean;
var Func: TUpdateCodeTools;
    i: integer;
    Handles: TIntegerArray;
begin
  Result := True;

  Handles := GetDLLHandles;
  for i := 0 to High(Handles) do begin
    if Updating then
      @Func := GetProcAddress(Handles[i], 'UpdatingCodeExplorer')
    else
      @Func := GetProcAddress(Handles[i], 'UpdatedCodeExplorer');

    if @Func <> nil then begin
      case Func(PChar(Lang), PChar(Filename), PChar(CurrProjects))  of
        PLUGIN_HANDLED: Result := False;
        PLUGIN_STOP: begin
          Result := False;
          exit;
        end;
      end;
    end;
  end;
  SetLength(Handles, 0);
  Handles := nil;
end;

function Plugin_UpdateCodeInspector(Lang, Filename, CurrProjects: String; Updating: Boolean): Boolean;
var Func: TUpdateCodeTools;
    i: integer;
    Handles: TIntegerArray;
begin
  Result := True;

  Handles := GetDLLHandles;
  for i := 0 to High(Handles) do begin
    if Updating then
      @Func := GetProcAddress(Handles[i], 'UpdatingCodeInspector')
    else
      @Func := GetProcAddress(Handles[i], 'UpdatedCodeInspector');

    if @Func <> nil then begin
      case Func(PChar(Lang), PChar(Filename), PChar(CurrProjects))  of
        PLUGIN_HANDLED: Result := False;
        PLUGIN_STOP: begin
          Result := False;
          exit;
        end;
      end;
    end;
  end;
  SetLength(Handles, 0);
  Handles := nil;
end;

function Plugin_OutputDblClick(ItemIndex: Integer): Boolean;
var Func: TOutputEvent;
    i: integer;
    Handles: TIntegerArray;
begin
  Result := True;

  Handles := GetDLLHandles;
  for i := 0 to High(Handles) do begin
    @Func := GetProcAddress(Handles[i], 'OutputDoubleClick');

    if @Func <> nil then begin
      case Func(ItemIndex)  of
        PLUGIN_HANDLED: Result := False;
        PLUGIN_STOP: begin
          Result := False;
          exit;
        end;
      end;
    end;
  end;
  SetLength(Handles, 0);
  Handles := nil;
end;

function Plugin_OutputPopup(ItemIndex: Integer): Boolean;
var Func: TOutputEvent;
    i: integer;
    Handles: TIntegerArray;
begin
  Result := True;

  Handles := GetDLLHandles;
  for i := 0 to High(Handles) do begin
    @Func := GetProcAddress(Handles[i], 'OutputPopup');

    if @Func <> nil then begin
      case Func(ItemIndex)  of
        PLUGIN_HANDLED: Result := False;
        PLUGIN_STOP: begin
          Result := False;
          exit;
        end;
      end;
    end;
  end;
  SetLength(Handles, 0);
  Handles := nil;
end;

end.