OSDN Git Service

Move Plugins.html developer doc to README.md
authorTim Gerundt <tim@gerundt.de>
Thu, 12 Mar 2020 22:40:26 +0000 (23:40 +0100)
committerTim Gerundt <tim@gerundt.de>
Thu, 12 Mar 2020 22:40:26 +0000 (23:40 +0100)
Docs/Developers/Plugins.html [deleted file]
Docs/Developers/README.md
Plugins/README.md

diff --git a/Docs/Developers/Plugins.html b/Docs/Developers/Plugins.html
deleted file mode 100644 (file)
index 949015f..0000000
+++ /dev/null
@@ -1,429 +0,0 @@
-<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
-  "http://www.w3.org/TR/html4/loose.dtd">
-<html>
-<head>
-  <title>Plugins</title>
-  <meta http-equiv="content-type" content="text/html; charset=ISO-8859-1">
-  <style type="text/css">
-  <!--
-    body {
-      font-family: Verdana,Helvetica,Arial,sans-serif;
-      font-size: small;
-    }
-    code,pre {
-      font-family: "Courier New",Courier,monospace;
-      font-size: 1em;
-    }
-    h3 {
-      padding: 2px;
-      border-left: 4px solid #FFCC00;
-      border-bottom: 1px solid #FFCC00;
-    }
-    h4 {
-      padding: 2px;
-      border-left: 8px solid #FF9933;
-      border-bottom: 1px solid #FF9933;
-    }
-    table {
-      border-collapse: collapse;
-      border: 1px solid black;
-    }
-    th {
-      text-align: left;
-      padding: 3px;
-      background-color: #EEEEEE;
-      border: 1px solid black;
-    }
-    td {
-      padding: 3px;
-      border: 1px solid black;
-    }
-    dt {
-      font-weight: bold;
-    }
-  -->
-  </style>
-</head>
-<body>
-<h2>Plugins</h2>
-
-<h3>Table of Contents</h3>
-<ul>
-  <li><a href="#description">Quick description</a></li>
-  <li><a href="#events">Events</a></li>
-  <li><a href="#api">API</a></li>
-  <li><a href="#properties">Properties</a></li>
-  <li><a href="#methods">Methods</a></li>
-  <li><a href="#syntax">Syntax</a>
-    <ul>
-      <li><a href="#syntax_properties">Properties syntax</a></li>
-      <li><a href="#syntax_methods">Methods syntax</a></li>
-    </ul>
-  </li>
-  <li><a href="#write">How to write plugins quickly ?</a></li>
-  <li><a href="#debug">How to debug VC++ plugins ?</a></li>
-</ul>
-
-<h3><a name="description">Quick description</a></h3>
-<p>Plugins use an ActiveX interface. Plugins may be written in any format that supports this interface.</p>
-<p>Examples are available in :</p>
-<ul>
-  <li>C++ COM component</li>
-  <li>VB ActiveX dll</li>
-  <li>Scriptlets (VBS, JS)</li>
-  <li>Delphi</li>
-</ul>
-<p>Limitation : Scriptlets only work for <code>EDITOR_SCRIPT</code> plugins.</p>
-<p><a href="#properties">Properties</a> are used to present information concerning the plugin.<br />
-<a href="#methods">Methods</a> are used to process the data. Method names and syntax depends on events and <a href="#api">API</a> (see below).</p>
-
-<h3><a name="events">Events</a></h3>
-<dl>
-  <dt><code>EDITOR_SCRIPT</code></dt>
-  <dd><p>In editor view, apply a function to the current selection.</p></dd>
-
-  <dt><code>PREDIFF</code></dt>
-  <dd>
-    <p>Preprocess file before diffing : the plugin is not apply to the text displayed in the editor. It is applied only to a copy of the left and right texts, and this copy are then scanned to create the difference list. As now :</p>
-    <ul>
-      <li>you may delete one column, change the names of variables...</li>
-      <li>you may not add/delete/move lines.</li>
-    </ul>
-  </dd>
-
-  <dt><code>PACK_UNPACK</code></dt>
-  <dd>
-    <p>Transform a file in a viewable format (for example, decompress a file...)</p>
-    <ul>
-      <li>The editor displays the unpacked data.</li>
-      <li>Sometimes files may be packed again (zipped files...). An additional function is of course necessary.</li>
-      <li>If the author of the plugin created this function, file may be saved again in the compressed format.</li>
-      <li>Else the file can only be saved in a text format. To avoid problems, you are proposed to change the filename when saving a changed file.</li>
-    </ul>
-  </dd>
-</dl>
-
-<h3><a name="api">API</a></h3>
-<p>Some events have two API. One to exchange the data through a <code>BSTR</code> (memory) and one through input/ouput files.</p>
-
-<table border="1">
-  <tr>
-    <td><code>FILE_PREDIFF</code></td>
-    <td>data are exchanged through an input and an output file</td>
-  </tr>
-  <tr>
-    <td><code>BUFFER_PREDIFF</code></td>
-    <td>data are exchanged through a <code>BSTR</code></td>
-  </tr>
-  <tr>
-    <td><code>FILE_PACK_UNPACK</code></td>
-    <td>data are exchanged through an input and an output file</td>
-  </tr>
-  <tr>
-    <td><code>BUFFER_PACK_UNPACK</code></td>
-    <td>data are exchanged through a <code>SafeArray</code> (<code>BSTR</code> not available as the packed data are possibly not text)</td>
-  </tr>
-  <tr>
-    <td><code>EDITOR_SCRIPT</code></td>
-    <td>data are exchanged through a <code>BSTR</code></td>
-  </tr>
-</table>
-<p>You need to define only one API to handle an event. Define the one you prefer.</p>
-
-<h3><a name="properties">Properties</a></h3>
-<table border="1">
-  <tr>
-    <th>Name</th>
-    <th>Mandatory</th>
-    <th>Events</th>
-  </tr>
-  <tr>
-    <td><code>PluginEvent</code></td>
-    <td>yes</td>
-    <td>all</td>
-  </tr>
-  <tr>
-    <td><code>PluginDescription</code></td>
-    <td>no</td>
-    <td>all</td>
-  </tr>
-  <tr>
-    <td><code>PluginFileFilters</code></td>
-    <td>no</td>
-    <td><code>PACK_UNPACK</code>, <code>PREDIFF</code></td>
-  </tr>
-  <tr>
-    <td><code>PluginIsAutomatic</code></td>
-    <td>if <code>PluginFileFilters</code> is defined</td>
-    <td><code>PACK_UNPACK</code>, <code>PREDIFF</code></td>
-  </tr>
-</table>
-
-<p><code>PluginIsAutomatic</code> and <code>PluginFileFilters</code> are for automatic mode :</p>
-<ul>
-  <li>When <code>PluginIsAutomatic</code> is <code>false</code>, the plugin is never used in automatic mode.</li>
-  <li>When <code>PluginIsAutomatic</code> is <code>true</code>, <code>PluginFileFilters</code> is compared to the filename of both files. If one file
-      matches the filter, the plugin is applied.</li>
-</ul>
-
-<h3><a name="methods">Methods</a></h3>
-<table border="1">
-  <tr>
-    <th>API</th>
-    <th>Method name</th>
-  </tr>
-  <tr>
-    <td><code>EDITOR_SCRIPT</code></td>
-    <td>function name is free<br /><br /><b>Note</b> : several functions may be defined in one <code>EDITOR_SCRIPT</code> plugin</td>
-  </tr>
-  <tr>
-    <td><code>BUFFER_PREDIFF</code></td>
-    <td><code>PrediffBufferW</code></td>
-  </tr>
-  <tr>
-    <td><code>FILE_PREDIFF</code></td>
-    <td><code>PrediffFile</code></td>
-  </tr>
-  <tr>
-    <td><code>BUFFER_PACK_UNPACK</code></td>
-    <td><code>UnpackBufferA</code><br /><code>PackBufferA</code></td>
-  </tr>
-  <tr>
-    <td><code>FILE_PACK_UNPACK</code></td>
-    <td><code>UnpackFile</code><br /><code>PackFile</code></td>
-  </tr>
-</table>
-
-<p><b>Note</b> : <code>PACK_UNPACK</code> functions use an additional parameter. The value may be set during <code>UnpackBuffer</code>.
-When file is changed, the value is forwarded to <code>PackBuffer</code>.
-The goal is to pass a parameter from <code>UnpackBuffer</code> to <code>PackBuffer</code>.<br />
-For example, the plugin may handle several compressed formats, and use this value to recompress a file in
-the format of the original.
-This parameter is mandatory for the function's syntax. But you don't have to set its value when you don't use it.</p>
-
-<h3><a name="syntax">Syntax</a></h3>
-
-<h3><a name="syntax_properties">Properties syntax</a></h3>
-
-<h4><code>PluginEvent</code></h4>
-<table border="1">
-  <tr>
-    <th>C++</th>
-    <td><code>STDMETHODIMP CWinMergeScript::get_PluginEvent(BSTR * pVal)</code></td>
-  </tr>
-  <tr>
-    <th>VB</th>
-    <td><code>Public Property Get PluginEvent() As String</code></td>
-  </tr>
-  <tr>
-    <th>VBS</th>
-    <td><code>Function get_PluginEvent()</code></td>
-  </tr>
-</table>
-
-<h4><code>PluginDescription</code></h4>
-<table border="1">
-  <tr>
-    <th>C++</th>
-    <td><code>STDMETHODIMP CWinMergeScript::get_PluginDescription(BSTR * pVal)</code></td>
-  </tr>
-  <tr>
-    <th>VB</th>
-    <td><code>Public Property Get PluginDescription() As String</code></td>
-  </tr>
-  <tr>
-    <th>VBS</th>
-    <td><code>Function get_PluginDescription()</code></td>
-  </tr>
-</table>
-
-<h4><code>PluginFileFilters</code></h4>
-<p>String formed of fileFilters, separated with "<code>;</code>"</p>
-<table border="1">
-  <tr>
-    <th>C++</th>
-    <td><code>STDMETHODIMP CWinMergeScript::get_PluginFileFilters(BSTR * pVal)</code></td>
-  </tr>
-  <tr>
-    <th>VB</th>
-    <td><code>Public Property Get PluginFileFilters() As String</code></td>
-  </tr>
-</table>
-
-<h4><code>PluginIsAutomatic</code></h4>
-<table border="1">
-  <tr>
-    <th>C++</th>
-    <td><code>STDMETHODIMP CWinMergeScript::get_PluginIsAutomatic(VARIANT_BOOL * pVal)</code></td>
-  </tr>
-  <tr>
-    <th>VB</th>
-    <td><code>Public Property Get PluginIsAutomatic() As Boolean</code></td>
-  </tr>
-</table>
-
-<h3><a name="syntax_methods">Methods syntax</a></h3>
-
-<h4><code>EDITOR_SCRIPT</code></h4>
-<table border="1">
-  <tr>
-    <th></th>
-    <th>Functions parameters (function names are free)</th>
-  </tr>
-  <tr>
-    <th>C++</th>
-    <td><code>STDMETHOD(MakeUpperVB)([in] BSTR inputText, [out, retval] BSTR * outputText);</code></td>
-  </tr>
-  <tr>
-    <th>VB</th>
-    <td><code>Public Function MakeUpperVB(text As String)</code></td>
-  </tr>
-  <tr>
-    <th>VBS</th>
-    <td><code>Function MakeUpperVBS(Text)</code></td>
-  </tr>
-</table>
-
-<h4><code>FILE_PREDIFF</code></h4>
-<table border="1">
-  <tr>
-    <th></th>
-    <th>Functions names</th>
-    <th>Functions parameters</th>
-  </tr>
-  <tr>
-    <th>VC++</th>
-    <td><code>STDMETHOD(PrediffFile)</code></td>
-    <td><code>([in] BSTR fileSrc, [in] BSTR fileDst, VARIANT_BOOL * pbChanged, INT * pSubcode, [out, retval] VARIANT_BOOL * pbSuccess)</code></td>
-  </tr>
-  <tr>
-    <th>VB</th>
-    <td><code>Public Function PrediffFile</code></td>
-    <td><code>(BSTR fileSrc, BSTR fileDst, ByRef bChanged As Boolean, ByRef subcode As Long) As Boolean</code></td>
-  </tr>
-</table>
-
-<h4><code>BUFFER_PREDIFF</code></h4>
-<table border="1">
-  <tr>
-    <th></th>
-    <th>Functions names</th>
-    <th>Functions parameters</th>
-  </tr>
-  <tr>
-    <th>C++</th>
-    <td><code>STDMETHOD(PrediffBufferW)</code></td>
-    <td><code>([in] BSTR * pText, [in] INT * pSize, [in] VARIANT_BOOL * pbChanged, [out, retval] VARIANT_BOOL * pbHandled);</code></td>
-  </tr>
-  <tr>
-    <th>VB</th>
-    <td><code>Public Function PrediffBufferW</code></td>
-    <td><code>(ByRef text As String, ByRef size As Long, ByRef bChanged As Boolean) As Boolean</code></td>
-  </tr>
-</table>
-
-<h4><code>FILE_PACK_UNPACK</code></h4>
-<table border="1">
-  <tr>
-    <th></th>
-    <th>Functions names</th>
-    <th>Functions parameters</th>
-  </tr>
-  <tr>
-    <th rowspan="2">VC++</th>
-    <td><code>STDMETHOD(UnpackFile)</code></td>
-    <td><code>([in] BSTR fileSrc, [in] BSTR fileDst, VARIANT_BOOL * pbChanged, INT * pSubcode, [out, retval] VARIANT_BOOL * pbSuccess)</code></td>
-  </tr>
-  <tr>
-    <td><code>STDMETHOD(PackFile)</code></td>
-    <td><code>([in] BSTR fileSrc, [in] BSTR fileDst, VARIANT_BOOL * pbChanged, INT pSubcode, [out, retval] VARIANT_BOOL * pbSuccess)</code></td>
-  </tr>
-  <tr>
-    <th rowspan="2">VB</th>
-    <td><code>Public Function UnpackFile</code></td>
-    <td><code>(BSTR fileSrc, BSTR fileDst, ByRef bChanged As Boolean, ByRef subcode As Long) As Boolean</code></td>
-  </tr>
-  <tr>
-    <td><code>Public Function PackFile</code></td>
-    <td><code>(BSTR fileSrc, BSTR fileDst, ByRef bChanged As Boolean, subcode As Long) As Boolean</code></td>
-  </tr>
-</table>
-
-<h4><code>BUFFER_PACK_UNPACK</code></h4>
-<table border="1">
-  <tr>
-    <th></th>
-    <th>Functions names</th>
-    <th>Functions parameters</th>
-  </tr>
-  <tr>
-    <th rowspan="2">VC++</th>
-    <td><code>STDMETHOD(UnpackBufferA)</code></td>
-    <td><code>([in] SAFEARRAY ** pBuffer, [in] INT * pSize, [in] VARIANT_BOOL * pbChanged, [in] INT * pSubcode, [out, retval] VARIANT_BOOL * pbSuccess)</code></td>
-  </tr>
-  <tr>
-    <td><code>STDMETHOD(PackBufferA)</code></td>
-    <td><code>([in] SAFEARRAY ** pBuffer, [in] INT * pSize, [in] VARIANT_BOOL * pbChanged, [in] INT subcode, [out, retval] VARIANT_BOOL * pbSuccess)</code></td>
-  </tr>
-  <tr>
-    <th rowspan="2">VB</th>
-    <td><code>Public Function UnpackBufferA</code></td>
-    <td><code>(ByRef buffer() As Byte, ByRef size As Long, ByRef bChanged As Boolean, ByRef subcode As Long) As Boolean</code></td>
-  </tr>
-  <tr>
-    <td><code>Public Function PackBufferA</code></td>
-    <td><code>(ByRef buffer() As Byte, ByRef size As Long, ByRef bChanged As Boolean, subcode As Long) As Boolean</code></td>
-  </tr>
-</table>
-
-<h3><a name="write">How to write plugins quickly ?</a></h3>
-<p>Easiest plugins are scriptlets.</p>
-<p>Just VBscript (or JavaScript probably) with an additional section <code>&lt;implement&gt;</code>. See examples.<br />
-But they are difficult to debug. And valid only for <code>EDITOR_SCRIPT</code> events.</p>
-
-<h4>VC++ plugins :</h4>
-<p>The most difficult to write when you do it from scratch. See in <code>Plugins/syntax.txt</code>, there are three additional steps from normal COM dll.</p>
-<p>But easy to write from an existing plugin.</p>
-<ol>
-  <li>Select a C++ plugin with the same API</li>
-  <li>Rename the files <code>cpp,def,dsp,idl,rc</code> : replace [<em>name of old plugin</em>] with [<em>name of your plugin</em>]</li>
-  <li>In all the files, replace all instances of [<em>name of old plugin</em>] with [<em>name of your plugin</em>]</li>
-  <li>Write your custom code : <code>WinMergeScript.cpp</code> holds all the important functions.</li>
-  <li>Generate new GUIDs and add to the <code>.idl</code> file.</li>
-</ol>
-
-<h4>Additional steps to write a plugin in C++</h4>
-<ul>
-  <li>do not register the dll : delete everything in 'settings'->'custom build'</li>
-  <li>do not register the dll : delete the file <code>.rgs</code>, and the registry section in the file <code>.rc</code></li>
-  <li>do not register the dll : add <code>typeinfoex.h</code> + and make 3 changes in <code>WinMergeScript.h</code> (see commented lines)</li>
-  <li><code>SAFEARRAY</code> : replace the interface in <code>.idl</code> :
-    <ul>
-      <li><code>SAFEARRAY *</code>             <code>SAFEARRAY(unsigned char)</code></li>
-      <li><code>SAFEARRAY **</code>            <code>SAFEARRAY(unsigned char) *</code></li>
-    </ul>
-  </li>
-</ul>
-
-<h3><a name="debug">How to debug VC++ plugins ?</a></h3>
-<p>Easy with Visual Studio after you installed WinMerge source.</p>
-
-<h4><code>EDITOR_SCRIPT</code> :</h4>
-<ol>
-  <li>Set a breakpoint at the beginning of <code>safeInvokeA</code> in <code>Plugins.cpp</code>.</li>
-  <li>Run WinMerge</li>
-  <li>Do all you need (open file, menu...) to call the plugin.</li>
-  <li>The breakpoint is triggered. The plugin interface is loaded at this moment.
-      Open the file <code>WinMergeScript.cpp</code> source of your plugin in the debugging session.</li>
-  <li>Set a breakpoint in this file at the beginning of your function.</li>
-  <li><code>F5</code>. The breakpoint in your function is triggered.</li>
-</ol>
-
-<h4><code>PREDIFF</code>, <code>PACK_UNPACK</code> :</h4>
-<p>Same steps, point #1 only differs:</p>
-<ol>
-  <li>Set a breakpoint at the beginning of <code>safeInvokeW</code> in <code>Plugins.cpp</code>.<br /><br />
-      <b>Note</b> : <code>safeInvokeW</code> instead of <code>safeInvokeA</code>.</li>
-</ol>
-</body>
-</html>
\ No newline at end of file
index 9536d9a..40692b2 100644 (file)
@@ -12,7 +12,7 @@ Developer documentation is in meant for people who want to compile WinMerge them
  * [Translation instructions](../../Translations/README.md)
  * [User manual information](../Users/Manual/README.md) tells how to convert manual from DocBook to HTML and HTML help.
  * [Options](Options.html) explains WinMerge's options handling.
- * [Plugins](Plugins.html) contains documentation about plugins-system.
+ * [Plugins](../../Plugins/README.md) contains documentation about plugins-system.
  * [ShellExtension](../../ShellExtension/README.md) contains tipps for the Windows Explorer shell integration.
  * [InnoSetup](../../Installer/InnoSetup/README.md) contains documentation about WinMerge's installer.
  * [Unit testing](UnitTesting.html) instructions for unit testing in WinMerge development.
\ No newline at end of file
index 49ffd1a..67b3e4f 100644 (file)
@@ -1,9 +1,216 @@
 # WinMerge Plugins
 
-Plugins holds the WinMerge runtime plugins, source code and binaries both.
+This folders holds the WinMerge runtime plugins, source code and binaries both.
 
-These plugins allow transformations to files before diffing, or during
-editing. See the manual for more information.
+These filters are distributed in the `MergePlugins` subdirectory beneath the WinMerge executables.
 
-These filters are distributed in the MergePlugins
-subdirectory beneath the WinMerge executables.
+## Quick description
+
+Plugins use an ActiveX interface. Plugins may be written in any format that supports this interface.
+
+Examples are available in :
+
+ * C++ COM component
+ * VB ActiveX dll
+ * Scriptlets (VBS, JS)
+ * Delphi
+
+Limitation : Scriptlets only work for `EDITOR_SCRIPT` plugins.
+
+**Properties** are used to present information concerning the plugin.  
+**Methods** are used to process the data. Method names and syntax depends on events and **API** (see below).
+
+## Events
+
+### `EDITOR_SCRIPT`
+
+In editor view, apply a function to the current selection.
+
+### `PREDIFF`
+
+Preprocess file before diffing : the plugin is not apply to the text displayed in the editor.
+It is applied only to a copy of the left and right texts, and this copy are then scanned to create the difference list.
+As now:
+
+ * you may delete one column, change the names of variables...
+ * you may not add/delete/move lines.
+
+### `PACK_UNPACK`
+
+Transform a file in a viewable format (for example, decompress a file...)
+
+ * The editor displays the unpacked data.
+ * Sometimes files may be packed again (zipped files...). An additional function is of course necessary.
+ * If the author of the plugin created this function, file may be saved again in the compressed format.
+ * Else the file can only be saved in a text format. To avoid problems, you are proposed to change the filename when saving a changed file.
+
+## API
+
+Some events have two API. One to exchange the data through a `BSTR` (memory) and one through input/ouput files.
+
+| Event                | Data exchange                                                                                            |
+|:---------------------|:---------------------------------------------------------------------------------------------------------|
+| `FILE_PREDIFF`       | data are exchanged through an input and an output file                                                   |
+| `BUFFER_PREDIFF`     | data are exchanged through a `BSTR`                                                                      |
+| `FILE_PACK_UNPACK`   | data are exchanged through an input and an output file                                                   |
+| `BUFFER_PACK_UNPACK` | data are exchanged through a `SafeArray` (`BSTR` not available as the packed data are possibly not text) |
+| `EDITOR_SCRIPT`      | data are exchanged through a `BSTR`                                                                      |
+
+You need to define only one API to handle an event. Define the one you prefer.
+
+## Properties
+
+| Name                | Mandatory                         | Events                   |
+|:--------------------|:----------------------------------|:-------------------------|
+| `PluginEvent`       | yes                               | all                      |
+| `PluginDescription` | no                                | all                      |
+| `PluginFileFilters` | no                                | `PACK_UNPACK`, `PREDIFF` |
+| `PluginIsAutomatic` | if `PluginFileFilters` is defined | `PACK_UNPACK`, `PREDIFF` |
+
+`PluginIsAutomatic` and `PluginFileFilters` are for automatic mode :
+
+ * When `PluginIsAutomatic` is `false`, the plugin is never used in automatic mode.
+ * When `PluginIsAutomatic` is `true`, `PluginFileFilters` is compared to the filename of both files. If one file matches the filter, the plugin is applied.
+
+## Methods
+
+| API                  | Method name                                                                                    |
+|:---------------------|:-----------------------------------------------------------------------------------------------|
+| `EDITOR_SCRIPT`      | function name is free **Note**: several functions may be defined in one `EDITOR_SCRIPT` plugin |
+| `BUFFER_PREDIFF`     | `PrediffBufferW`                                                                               |
+| `FILE_PREDIFF`       | `PrediffFile`                                                                                  |
+| `BUFFER_PACK_UNPACK` | `UnpackBufferA`, `PackBufferA`                                                                 |
+| `FILE_PACK_UNPACK`   | `UnpackFile`, `PackFile`                                                                       |
+
+**Note**: `PACK_UNPACK` functions use an additional parameter. The value may be set during `UnpackBuffer`.  
+When file is changed, the value is forwarded to `PackBuffer`. The goal is to pass a parameter from `UnpackBuffer` to `PackBuffer`.  
+
+For example, the plugin may handle several compressed formats, and use this value to recompress a file in the format of the original.  
+This parameter is mandatory for the function's syntax. But you don't have to set its value when you don't use it.
+
+## Syntax
+
+### Properties syntax
+
+#### `PluginEvent`
+
+| Language | Syntax                                                       |
+|:--------:|:-------------------------------------------------------------|
+| C++      | `STDMETHODIMP CWinMergeScript::get_PluginEvent(BSTR * pVal)` |
+| VB       | `Public Property Get PluginEvent() As String`                |
+| VBS      | `Function get_PluginEvent()`                                 |
+
+#### `PluginDescription`
+
+| Language | Syntax                                                             |
+|:--------:|:-------------------------------------------------------------------|
+| C++      | `STDMETHODIMP CWinMergeScript::get_PluginDescription(BSTR * pVal)` |
+| VB       | `Public Property Get PluginDescription() As String`                |
+| VBS      | `Function get_PluginDescription()`                                 |
+
+#### `PluginFileFilters`
+
+String formed of fileFilters, separated with `;`
+
+| Language | Syntax                                                             |
+|:--------:|:-------------------------------------------------------------------|
+| C++      | `STDMETHODIMP CWinMergeScript::get_PluginFileFilters(BSTR * pVal)` |
+| VB       | `Public Property Get PluginFileFilters() As String`                |
+
+#### `PluginIsAutomatic`
+
+| Language | Syntax                                                                     |
+|:--------:|:---------------------------------------------------------------------------|
+| C++      | `STDMETHODIMP CWinMergeScript::get_PluginIsAutomatic(VARIANT_BOOL * pVal)` |
+| VB       | `Public Property Get PluginIsAutomatic() As Boolean`                       |
+
+### Methods syntax
+
+#### `EDITOR_SCRIPT`
+
+| Language | Functions parameters (function names are free)                                  |
+|:--------:|:--------------------------------------------------------------------------------|
+| C++      | `STDMETHOD(MakeUpperVB)([in] BSTR inputText, [out, retval] BSTR * outputText);` |
+| VB       | `Public Function MakeUpperVB(text As String)`                                   |
+| VBS      | `Function MakeUpperVBS(Text)`                                                   |
+
+#### `FILE_PREDIFF`
+
+| Language | Functions names               | Functions parameters                                                                                                       |
+|:--------:|:------------------------------|:---------------------------------------------------------------------------------------------------------------------------|
+| VC++     | `STDMETHOD(PrediffFile)`      | `([in] BSTR fileSrc, [in] BSTR fileDst, VARIANT_BOOL * pbChanged, INT * pSubcode, [out, retval] VARIANT_BOOL * pbSuccess)` |
+| VB       | `Public Function PrediffFile` | `(BSTR fileSrc, BSTR fileDst, ByRef bChanged As Boolean, ByRef subcode As Long) As Boolean`                                |
+
+#### `BUFFER_PREDIFF`
+
+| Language | Functions names                  | Functions parameters                                                                                            |
+|:--------:|:---------------------------------|:----------------------------------------------------------------------------------------------------------------|
+| C++      | `STDMETHOD(PrediffBufferW)`      | `([in] BSTR * pText, [in] INT * pSize, [in] VARIANT_BOOL * pbChanged, [out, retval] VARIANT_BOOL * pbHandled);` |
+| VB       | `Public Function PrediffBufferW` | `(ByRef text As String, ByRef size As Long, ByRef bChanged As Boolean) As Boolean`                              |
+
+#### `FILE_PACK_UNPACK`
+
+| Language | Functions names              | Functions parameters                                                                                                       |
+|:--------:|:-----------------------------|:---------------------------------------------------------------------------------------------------------------------------|
+| VC++     | `STDMETHOD(UnpackFile)`      | `([in] BSTR fileSrc, [in] BSTR fileDst, VARIANT_BOOL * pbChanged, INT * pSubcode, [out, retval] VARIANT_BOOL * pbSuccess)` |
+| VC++     | `STDMETHOD(PackFile)`        | `([in] BSTR fileSrc, [in] BSTR fileDst, VARIANT_BOOL * pbChanged, INT pSubcode, [out, retval] VARIANT_BOOL * pbSuccess)`   |
+| VB       | `Public Function UnpackFile` | `(BSTR fileSrc, BSTR fileDst, ByRef bChanged As Boolean, ByRef subcode As Long) As Boolean`                                |
+| VB       | `Public Function PackFile`   | `(BSTR fileSrc, BSTR fileDst, ByRef bChanged As Boolean, subcode As Long) As Boolean`                                      |
+
+#### `BUFFER_PACK_UNPACK`
+
+| Language | Functions names                 | Functions parameters                                                                                                                        |
+|:--------:|:--------------------------------|:--------------------------------------------------------------------------------------------------------------------------------------------|
+| VC++     | `STDMETHOD(UnpackBufferA)`      | `([in] SAFEARRAY ** pBuffer, [in] INT * pSize, [in] VARIANT_BOOL * pbChanged, [in] INT * pSubcode, [out, retval] VARIANT_BOOL * pbSuccess)` |
+| VC++     | `STDMETHOD(PackBufferA)`        | `([in] SAFEARRAY ** pBuffer, [in] INT * pSize, [in] VARIANT_BOOL * pbChanged, [in] INT subcode, [out, retval] VARIANT_BOOL * pbSuccess)`    |
+| VB       | `Public Function UnpackBufferA` | `(ByRef buffer() As Byte, ByRef size As Long, ByRef bChanged As Boolean, ByRef subcode As Long) As Boolean`                                 |
+| VB       | `Public Function PackBufferA`   | `(ByRef buffer() As Byte, ByRef size As Long, ByRef bChanged As Boolean, subcode As Long) As Boolean`                                       |
+
+## How to write plugins quickly ?
+
+Easiest plugins are scriptlets.
+
+Just VBscript (or JavaScript probably) with an additional section `<implement>`. See examples.  
+But they are difficult to debug. And valid only for `EDITOR_SCRIPT` events.
+
+### VC++ plugins
+
+The most difficult to write when you do it from scratch. See in `Plugins/syntax.txt`, there are three additional steps from normal COM dll.
+
+But easy to write from an existing plugin.
+
+ 1. Select a C++ plugin with the same API
+ 2. Rename the files `cpp,def,dsp,idl,rc` : replace \[_name of old plugin_\] with \[_name of your plugin_\]
+ 3. In all the files, replace all instances of \[_name of old plugin_\] with \[_name of your plugin_\]
+ 4. Write your custom code : `WinMergeScript.cpp` holds all the important functions.
+ 5. Generate new GUIDs and add to the `.idl` file.
+
+### Additional steps to write a plugin in C++
+
+ * do not register the dll : delete everything in 'settings'->'custom build'
+ * do not register the dll : delete the file `.rgs`, and the registry section in the file `.rc`
+ * do not register the dll : add `typeinfoex.h` + and make 3 changes in `WinMergeScript.h` (see commented lines)
+ * `SAFEARRAY` : replace the interface in `.idl` :
+   * `SAFEARRAY *` `SAFEARRAY(unsigned char)`
+   * `SAFEARRAY **` `SAFEARRAY(unsigned char) *`
+
+## How to debug VC++ plugins ?
+
+Easy with Visual Studio after you installed WinMerge source.
+
+### `EDITOR_SCRIPT`
+
+ 1. Set a breakpoint at the beginning of `safeInvokeA` in `Plugins.cpp`.
+ 2. Run WinMerge
+ 3. Do all you need (open file, menu...) to call the plugin.
+ 4. The breakpoint is triggered. The plugin interface is loaded at this moment. Open the file `WinMergeScript.cpp` source of your plugin in the debugging session.
+ 5. Set a breakpoint in this file at the beginning of your function.
+ 6. `F5`. The breakpoint in your function is triggered.
+
+### `PREDIFF`, `PACK_UNPACK`
+
+Same steps, point #1 only differs:
+
+ 1. Set a breakpoint at the beginning of `safeInvokeW` in `Plugins.cpp`.  
+    
+    **Note**: `safeInvokeW` instead of `safeInvokeA`.