Back to Winmerge

WinMerge Plugins

Plugins/README.md

2.16.5614.6 KB
Original Source

WinMerge Plugins

This folders holds the WinMerge runtime plugins, source code and binaries both.

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 (VBScript, JScript)
  • 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.

EventData exchange
FILE_PREDIFFdata are exchanged through an input and an output file
BUFFER_PREDIFFdata are exchanged through a BSTR
FILE_PACK_UNPACKdata are exchanged through an input and an output file
BUFFER_PACK_UNPACKdata are exchanged through a SafeArray (BSTR not available as the packed data are possibly not text)
EDITOR_SCRIPTdata are exchanged through a BSTR

You need to define only one API to handle an event. Define the one you prefer.

Properties

NameMandatoryEvents
PluginEventyesall
PluginDescriptionnoall
PluginFileFiltersnoPACK_UNPACK, PREDIFF
PluginIsAutomaticif PluginFileFilters is definedPACK_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

APIMethod name
EDITOR_SCRIPTfunction name is free Note: several functions may be defined in one EDITOR_SCRIPT plugin
BUFFER_PREDIFFPrediffBufferW
FILE_PREDIFFPrediffFile
BUFFER_PACK_UNPACKUnpackBufferA, PackBufferA
FILE_PACK_UNPACKUnpackFile, 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

LanguageSyntax
C++STDMETHODIMP CWinMergeScript::get_PluginEvent(BSTR * pVal)
VBPublic Property Get PluginEvent() As String
VBScriptFunction get_PluginEvent()
JScriptfunction get_PluginEvent()

PluginDescription

LanguageSyntax
C++STDMETHODIMP CWinMergeScript::get_PluginDescription(BSTR * pVal)
VBPublic Property Get PluginDescription() As String
VBScript`Function get_PluginDescription()
JScriptfunction get_PluginDescription()

PluginFileFilters

String formed of fileFilters, separated with ;

LanguageSyntax
C++STDMETHODIMP CWinMergeScript::get_PluginFileFilters(BSTR * pVal)
VBPublic Property Get PluginFileFilters() As String
VBScript`Function get_PluginFileFilters()
JScriptfunction get_PluginFileFilters()

PluginIsAutomatic

LanguageSyntax
C++STDMETHODIMP CWinMergeScript::get_PluginIsAutomatic(VARIANT_BOOL * pVal)
VBPublic Property Get PluginIsAutomatic() As Boolean
VBScriptFunction get_PluginIsAutomatic()
JScriptfunction get_PluginIsAutomatic()

Methods syntax

EDITOR_SCRIPT

LanguageFunctions parameters (function names are free)
C++STDMETHOD(MakeUpper)([in] BSTR inputText, [out, retval] BSTR * outputText);
VBPublic Function MakeUpper(text As String)
VBScriptFunction MakeUpper(Text)
JScriptfunction MakeUpper(Text)

FILE_PREDIFF

LanguageFunctions namesFunctions parameters
VC++STDMETHOD(PrediffFile)([in] BSTR fileSrc, [in] BSTR fileDst, VARIANT_BOOL * pbChanged, INT * pSubcode, [out, retval] VARIANT_BOOL * pbSuccess)
VBPublic Function PrediffFile(BSTR fileSrc, BSTR fileDst, ByRef bChanged As Boolean, ByRef subcode As Long) As Boolean
VBScriptFunction PrediffFile(fileSrc, fileDst, bChanged, subcode)
JScriptfunction PrediffFile(fileSrc, fileDst, bChanged, subcode) { ...; var r = new ActiveXObject("Scripting.Dictionary"); r.Add(0, retval); r.Add(1, bChanged); r.Add(2, subcode); return r.Items(); }

BUFFER_PREDIFF

LanguageFunctions namesFunctions parameters
C++STDMETHOD(PrediffBufferW)([in] BSTR * pText, [in] INT * pSize, [in] VARIANT_BOOL * pbChanged, [out, retval] VARIANT_BOOL * pbHandled);
VBPublic Function PrediffBufferW(ByRef text As String, ByRef size As Long, ByRef bChanged As Boolean) As Boolean
VBScriptFunction PrediffBufferW(text, size, bChanged)
JScriptfunction PrediffBufferW(text, size, bChanged) { ...; var r = new ActiveXObject("Scripting.Dictionary"); r.Add(0, retval); r.Add(1, text); r.Add(2, size); r.Add(3, bChanged); return r.Items(); }

FILE_PACK_UNPACK

LanguageFunctions namesFunctions 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)
VBPublic Function UnpackFile(BSTR fileSrc, BSTR fileDst, ByRef bChanged As Boolean, ByRef subcode As Long) As Boolean
VBPublic Function PackFile(BSTR fileSrc, BSTR fileDst, ByRef bChanged As Boolean, subcode As Long) As Boolean
VBScriptFunction UnpackFile(fileSrc, fileDst, bChanged, subcode)
VBScriptFunction PackFile(fileSrc, fileDst, bChanged, subcode)
JScriptfunction UnpackFile(fileSrc, fileDst, bChanged, subcode) { ...; var r = new ActiveXObject("Scripting.Dictionary"); r.Add(0, retval); r.Add(1, bChanged); r.Add(2, subcode); return r.Items(); }
JScriptfunction PackFile(fileSrc, fileDst, bChanged, subcode) { ...; var r = new ActiveXObject("Scripting.Dictionary"); r.Add(0, retval); r.Add(1, bChanged); return r.Items(); }

BUFFER_PACK_UNPACK

LanguageFunctions namesFunctions 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)
VBPublic Function UnpackBufferA(ByRef buffer() As Byte, ByRef size As Long, ByRef bChanged As Boolean, ByRef subcode As Long) As Boolean
VBPublic 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.