3 This folders holds the WinMerge runtime plugins, source code and binaries both.
5 These filters are distributed in the `MergePlugins` subdirectory beneath the WinMerge executables.
9 Plugins use an ActiveX interface. Plugins may be written in any format that supports this interface.
11 Examples are available in :
15 * Scriptlets (VBS, JS)
18 Limitation : Scriptlets only work for `EDITOR_SCRIPT` plugins.
20 **Properties** are used to present information concerning the plugin.
21 **Methods** are used to process the data. Method names and syntax depends on events and **API** (see below).
27 In editor view, apply a function to the current selection.
31 Preprocess file before diffing : the plugin is not apply to the text displayed in the editor.
32 It is applied only to a copy of the left and right texts, and this copy are then scanned to create the difference list.
35 * you may delete one column, change the names of variables...
36 * you may not add/delete/move lines.
40 Transform a file in a viewable format (for example, decompress a file...)
42 * The editor displays the unpacked data.
43 * Sometimes files may be packed again (zipped files...). An additional function is of course necessary.
44 * If the author of the plugin created this function, file may be saved again in the compressed format.
45 * 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.
49 Some events have two API. One to exchange the data through a `BSTR` (memory) and one through input/ouput files.
51 | Event | Data exchange |
52 |:---------------------|:---------------------------------------------------------------------------------------------------------|
53 | `FILE_PREDIFF` | data are exchanged through an input and an output file |
54 | `BUFFER_PREDIFF` | data are exchanged through a `BSTR` |
55 | `FILE_PACK_UNPACK` | data are exchanged through an input and an output file |
56 | `BUFFER_PACK_UNPACK` | data are exchanged through a `SafeArray` (`BSTR` not available as the packed data are possibly not text) |
57 | `EDITOR_SCRIPT` | data are exchanged through a `BSTR` |
59 You need to define only one API to handle an event. Define the one you prefer.
63 | Name | Mandatory | Events |
64 |:--------------------|:----------------------------------|:-------------------------|
65 | `PluginEvent` | yes | all |
66 | `PluginDescription` | no | all |
67 | `PluginFileFilters` | no | `PACK_UNPACK`, `PREDIFF` |
68 | `PluginIsAutomatic` | if `PluginFileFilters` is defined | `PACK_UNPACK`, `PREDIFF` |
70 `PluginIsAutomatic` and `PluginFileFilters` are for automatic mode :
72 * When `PluginIsAutomatic` is `false`, the plugin is never used in automatic mode.
73 * When `PluginIsAutomatic` is `true`, `PluginFileFilters` is compared to the filename of both files. If one file matches the filter, the plugin is applied.
78 |:---------------------|:-----------------------------------------------------------------------------------------------|
79 | `EDITOR_SCRIPT` | function name is free **Note**: several functions may be defined in one `EDITOR_SCRIPT` plugin |
80 | `BUFFER_PREDIFF` | `PrediffBufferW` |
81 | `FILE_PREDIFF` | `PrediffFile` |
82 | `BUFFER_PACK_UNPACK` | `UnpackBufferA`, `PackBufferA` |
83 | `FILE_PACK_UNPACK` | `UnpackFile`, `PackFile` |
85 **Note**: `PACK_UNPACK` functions use an additional parameter. The value may be set during `UnpackBuffer`.
86 When file is changed, the value is forwarded to `PackBuffer`. The goal is to pass a parameter from `UnpackBuffer` to `PackBuffer`.
88 For example, the plugin may handle several compressed formats, and use this value to recompress a file in the format of the original.
89 This parameter is mandatory for the function's syntax. But you don't have to set its value when you don't use it.
98 |:--------:|:-------------------------------------------------------------|
99 | C++ | `STDMETHODIMP CWinMergeScript::get_PluginEvent(BSTR * pVal)` |
100 | VB | `Public Property Get PluginEvent() As String` |
101 | VBS | `Function get_PluginEvent()` |
103 #### `PluginDescription`
105 | Language | Syntax |
106 |:--------:|:-------------------------------------------------------------------|
107 | C++ | `STDMETHODIMP CWinMergeScript::get_PluginDescription(BSTR * pVal)` |
108 | VB | `Public Property Get PluginDescription() As String` |
109 | VBS | `Function get_PluginDescription()` |
111 #### `PluginFileFilters`
113 String formed of fileFilters, separated with `;`
115 | Language | Syntax |
116 |:--------:|:-------------------------------------------------------------------|
117 | C++ | `STDMETHODIMP CWinMergeScript::get_PluginFileFilters(BSTR * pVal)` |
118 | VB | `Public Property Get PluginFileFilters() As String` |
120 #### `PluginIsAutomatic`
122 | Language | Syntax |
123 |:--------:|:---------------------------------------------------------------------------|
124 | C++ | `STDMETHODIMP CWinMergeScript::get_PluginIsAutomatic(VARIANT_BOOL * pVal)` |
125 | VB | `Public Property Get PluginIsAutomatic() As Boolean` |
131 | Language | Functions parameters (function names are free) |
132 |:--------:|:--------------------------------------------------------------------------------|
133 | C++ | `STDMETHOD(MakeUpperVB)([in] BSTR inputText, [out, retval] BSTR * outputText);` |
134 | VB | `Public Function MakeUpperVB(text As String)` |
135 | VBS | `Function MakeUpperVBS(Text)` |
139 | Language | Functions names | Functions parameters |
140 |:--------:|:------------------------------|:---------------------------------------------------------------------------------------------------------------------------|
141 | VC++ | `STDMETHOD(PrediffFile)` | `([in] BSTR fileSrc, [in] BSTR fileDst, VARIANT_BOOL * pbChanged, INT * pSubcode, [out, retval] VARIANT_BOOL * pbSuccess)` |
142 | VB | `Public Function PrediffFile` | `(BSTR fileSrc, BSTR fileDst, ByRef bChanged As Boolean, ByRef subcode As Long) As Boolean` |
144 #### `BUFFER_PREDIFF`
146 | Language | Functions names | Functions parameters |
147 |:--------:|:---------------------------------|:----------------------------------------------------------------------------------------------------------------|
148 | C++ | `STDMETHOD(PrediffBufferW)` | `([in] BSTR * pText, [in] INT * pSize, [in] VARIANT_BOOL * pbChanged, [out, retval] VARIANT_BOOL * pbHandled);` |
149 | VB | `Public Function PrediffBufferW` | `(ByRef text As String, ByRef size As Long, ByRef bChanged As Boolean) As Boolean` |
151 #### `FILE_PACK_UNPACK`
153 | Language | Functions names | Functions parameters |
154 |:--------:|:-----------------------------|:---------------------------------------------------------------------------------------------------------------------------|
155 | VC++ | `STDMETHOD(UnpackFile)` | `([in] BSTR fileSrc, [in] BSTR fileDst, VARIANT_BOOL * pbChanged, INT * pSubcode, [out, retval] VARIANT_BOOL * pbSuccess)` |
156 | VC++ | `STDMETHOD(PackFile)` | `([in] BSTR fileSrc, [in] BSTR fileDst, VARIANT_BOOL * pbChanged, INT pSubcode, [out, retval] VARIANT_BOOL * pbSuccess)` |
157 | VB | `Public Function UnpackFile` | `(BSTR fileSrc, BSTR fileDst, ByRef bChanged As Boolean, ByRef subcode As Long) As Boolean` |
158 | VB | `Public Function PackFile` | `(BSTR fileSrc, BSTR fileDst, ByRef bChanged As Boolean, subcode As Long) As Boolean` |
160 #### `BUFFER_PACK_UNPACK`
162 | Language | Functions names | Functions parameters |
163 |:--------:|:--------------------------------|:--------------------------------------------------------------------------------------------------------------------------------------------|
164 | VC++ | `STDMETHOD(UnpackBufferA)` | `([in] SAFEARRAY ** pBuffer, [in] INT * pSize, [in] VARIANT_BOOL * pbChanged, [in] INT * pSubcode, [out, retval] VARIANT_BOOL * pbSuccess)` |
165 | VC++ | `STDMETHOD(PackBufferA)` | `([in] SAFEARRAY ** pBuffer, [in] INT * pSize, [in] VARIANT_BOOL * pbChanged, [in] INT subcode, [out, retval] VARIANT_BOOL * pbSuccess)` |
166 | VB | `Public Function UnpackBufferA` | `(ByRef buffer() As Byte, ByRef size As Long, ByRef bChanged As Boolean, ByRef subcode As Long) As Boolean` |
167 | VB | `Public Function PackBufferA` | `(ByRef buffer() As Byte, ByRef size As Long, ByRef bChanged As Boolean, subcode As Long) As Boolean` |
169 ## How to write plugins quickly ?
171 Easiest plugins are scriptlets.
173 Just VBscript (or JavaScript probably) with an additional section `<implement>`. See examples.
174 But they are difficult to debug. And valid only for `EDITOR_SCRIPT` events.
178 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.
180 But easy to write from an existing plugin.
182 1. Select a C++ plugin with the same API
183 2. Rename the files `cpp,def,dsp,idl,rc` : replace \[_name of old plugin_\] with \[_name of your plugin_\]
184 3. In all the files, replace all instances of \[_name of old plugin_\] with \[_name of your plugin_\]
185 4. Write your custom code : `WinMergeScript.cpp` holds all the important functions.
186 5. Generate new GUIDs and add to the `.idl` file.
188 ### Additional steps to write a plugin in C++
190 * do not register the dll : delete everything in 'settings'->'custom build'
191 * do not register the dll : delete the file `.rgs`, and the registry section in the file `.rc`
192 * do not register the dll : add `typeinfoex.h` + and make 3 changes in `WinMergeScript.h` (see commented lines)
193 * `SAFEARRAY` : replace the interface in `.idl` :
194 * `SAFEARRAY *` `SAFEARRAY(unsigned char)`
195 * `SAFEARRAY **` `SAFEARRAY(unsigned char) *`
197 ## How to debug VC++ plugins ?
199 Easy with Visual Studio after you installed WinMerge source.
203 1. Set a breakpoint at the beginning of `safeInvokeA` in `Plugins.cpp`.
205 3. Do all you need (open file, menu...) to call the plugin.
206 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.
207 5. Set a breakpoint in this file at the beginning of your function.
208 6. `F5`. The breakpoint in your function is triggered.
210 ### `PREDIFF`, `PACK_UNPACK`
212 Same steps, point #1 only differs:
214 1. Set a breakpoint at the beginning of `safeInvokeW` in `Plugins.cpp`.
216 **Note**: `safeInvokeW` instead of `safeInvokeA`.