Changeset 1075


Ignore:
Timestamp:
Jan 13, 2010, 3:58:11 PM (12 years ago)
Author:
Arno Wacker
Message:

PluginHowTo:

  • Removed LaTex errors (made it compile)(" -> and
    after figures do lead to compile errors/warnings)
  • Small changes to abstract
    • use new paragraph (insert single empty line) instead of newline
    • Removed surrounding and word "Abstract"
  • Changed title to Plugin Developer Howto (instead of the old two-line version), removed formating from \subtitle - if formatting is needed, this should be done in the template (i.e. frontpage.tex)
Location:
trunk/Documentation/Developer/PluginHowTo
Files:
3 edited

Legend:

Unmodified
Added
Removed
  • trunk/Documentation/Developer/PluginHowTo/HowToDeveloper.tex

    r1060 r1075  
    115115
    116116\title{CrypTool 2.0}
    117 \subtitle{\Huge Developer Manual\\\normalsize How to build your own plugins for CT2?}
     117\subtitle{Plugin Developer Manual}
    118118\author{S.\ Przybylski, A.\ Wacker, M.\ Wander and F.\ Enkler}
    119119\email{\{przybylski$|$wacker$|$wander$|$enkler\}@cryptool.org}
     
    156156
    157157
    158 %\AtBeginDocument{\markboth{\@author}{\@title}} 
     158%\AtBeginDocument{\markboth{\@author}{\@title}}
    159159\begin{document}
    160160        \maketitle
    161161       
    162162        \begin{abstract}
    163     \textbf{''Abstract.} CrypTool 2 is the modern successor of the well known e-learning platform for cryptography and cryptanalysis \htmladdnormallink{CrypTool 1}{http://www.cryptool.org}, which is used world-wide for educational purposes at school and universities and in companies and agencies.\\\\Since the first launch of CrypTool 1 in 1999 the art of software development has changed dramatically. So the CrypTool 2 team started in 2008 to develop a completely new e-learning application, embracing the newest trends in both didactics and software architecture to delight the end-user with an entirely new experience.\\\\CT 2 is build using
    164 \renewcommand{\labelitemi}{-}
     163     CrypTool 2 is the modern successor of the well known e-learning platform for cryptography and cryptanalysis \htmladdnormallink{CrypTool 1}{http://www.cryptool.org}, which is used world-wide for educational purposes at school and universities and in companies and agencies.
     164     
     165     Since the first launch of CrypTool 1 in 1999 the art of software development has changed dramatically. So the CrypTool 2 team started in 2008 to develop a completely new e-learning application, embracing the newest trends in both didactics and software architecture to delight the end-user with an entirely new experience.
     166     
     167     CrypTool 2 is build using
     168
    165169\begin{itemize}
    166         \item .NET (modern software framework with solutions to common programming problems form Microsoft),
    167         \item C\# (modern object-oriented programming language, comparable to Java) and
    168  \item WPF (modern purely vector-based graphical subsystem for rendering user interfaces in Windows-based applications) plus
    169  \item VisualStudio2008 (development environment) and
    170         \item Subversion (source code and documentation version management system).
    171 \end{itemize}\\
    172 This document is intended for plugin developers, who want to contribute new visual or mathematical functionality to CT2.\\Currently (January 2010) the code exists of about 7000 lines of C\# code in the Core system and about 240,641 lines of C\# code in the 115 plugins.\\\\For further news and more screenshots please see the developer page \htmladdnormallink{http://www.cryptool2.vs.uni-due.de}{http://www.cryptool2.vs.uni-due.de}.''
     170        \item .NET (modern software framework with solutions to common programming problems form Microsoft),
     171        \item C\# (modern object-oriented programming language, comparable to Java) and
     172    \item WPF (modern purely vector-based graphical subsystem for rendering user interfaces in Windows-based applications) plus
     173    \item VisualStudio2008 (development environment) and
     174        \item Subversion (source code and documentation version management system).
     175\end{itemize}
     176
     177This document is intended for plugin developers, who want to contribute new visual or mathematical functionality to CT2. Currently (January 2010) the code exists of about 7000 lines of C\# code in the Core system and about 240,641 lines of C\# code in the 115 plugins.
     178
     179
     180For further news and more screenshots please see the developer page \htmladdnormallink{http://www.cryptool2.vs.uni-due.de}{http://www.cryptool2.vs.uni-due.de}.
    173181    \end{abstract}
    174182
    175183        \tableofcontents
    176184
    177    
    178     \AddToShipoutPicture{\WaterMarkPic} 
     185
     186    \AddToShipoutPicture{\WaterMarkPic}
    179187
    180188        \include{part1}
  • trunk/Documentation/Developer/PluginHowTo/part2.tex

    r1072 r1075  
    2626\section{Interface selection}
    2727\label{sec:SelectTheInterfaceYourPluginWantsToServe}
    28 First we have to add a reference to the CrypTool library called ''CrypPluginBase.dll'' where all necessary CrypTool plugin interfaces are declared.\\
     28First we have to add a reference to the CrypTool library called ''CrypPluginBase.dll'' where all necessary CrypTool plugin interfaces are declared.
     29
    2930\begin{figure}[h!]
    3031        \includegraphics{figures/add_reference.jpg}
    3132        \caption{Add new reference}
    3233        \label{fig:add_reference}
    33 \end{figure}\\
     34\end{figure}
     35
    3436Make a right click in the Solution Explorer on the ''Reference'' item and choose ''Add Reference''.\\
     37
    3538\begin{figure}[h!]
    3639        \centering
     
    3841        \caption{Add reference PluginBase source code}
    3942        \label{fig:add_pluginbase_source}
    40 \end{figure}\\
     43\end{figure}
     44
    4145Select the project ''CrypPluginBase''. If you don't have the CrypPluginBase source code, it's also possible to add a reference the the binary DLL. In this case browse to the path where the library file ''CrypPluginBase.dll'' is located e.g. ''C:\textbackslash Documents and Settings \textbackslash $<$Username$>$ \textbackslash My Documents\textbackslash Visual Studio  2008\textbackslash Projects\textbackslash CrypPluginBase\textbackslash bin\textbackslash Debug'') and select the library by double clicking the file or pressing the "OK" button.\\
    4246
     
    4953        \caption{Browse reference}
    5054        \label{fig:browse_reference}
    51 \end{figure}\\
    52 Besides the CrypPluginBase you need to add three assembly references (same way like the ''CrypPluginBase'' before by selectig the ''.NET'' tab) to provide the necessary "Windows" namespace for your \textbf{user control} functions called "Presentation" and "QuickWatchPresentation". Select the following .NET components:\\
     55\end{figure}
     56
     57Besides the CrypPluginBase you need to add three assembly references (same way like the ''CrypPluginBase'' before by selecting the ''.NET'' tab) to provide the necessary ''Windows'' namespace for your \textbf{user control} functions called ''Presentation'' and "QuickWatchPresentation". Select the following .NET components:
     58
    5359\begin{itemize}
    5460    \item PresentationCore
    5561    \item PresentationFramework
    5662    \item WindowsBase
    57 \end{itemize}\clearpage
     63\end{itemize}
     64\clearpage
     65
    5866Afterwards your reference tree view should look like this:
     67
    5968\begin{figure}[h!]
    6069                \includegraphics{figures/reference_tree.jpg}
     
    6271        \label{fig:reference_tree}
    6372\end{figure}
     73
    6474If your plugin will be based on further libraries, you have to add them in the same way.
    6575\section{Create the classes for the algorithm and for its settings}\label{sec:CreateTheClassesForTheAlgorithmAndForItsSettings}
    66 In the next step we have to create two classes. The first class named "Caesar" has to inherit from IEncryption to provide an ecryption plugin. If you want to develop a Hash plugin your class has to inherit from IHash.
    67 The second class named "CaesarSettings" has to inherit from ISettings.
     76In the next step we have to create two classes. The first class named ''Caesar'' has to inherit from IEncryption to provide an ecryption plugin. If you want to develop a Hash plugin your class has to inherit from IHash.
     77The second class named ''CaesarSettings'' has to inherit from ISettings.
    6878\subsection{Create the class for the algorithm (Caesar)}\label{sec:CreateTheClassForTheAlgorithmCaesar}
    69 Visual Studio automatically creates a class which has the name "Class1.cs".  There are two ways to change the name to "Caesar.cs":
     79Visual Studio automatically creates a class which has the name ''Class1.cs''.  There are two ways to change the name to ''Caesar.cs'':
    7080\renewcommand{\labelitemi}{-}
    7181\begin{itemize}
     
    295305    {
    296306        #region Public Caesar specific interface
    297        
     307
    298308        /// <summary>
    299309        /// We use this delegate to send log messages from the settings class to the Caesar plugin
     
    365375        private string alphabet = ''ABCDEFGHIJKLMNOPQRSTUVWXYZ'';
    366376        private char shiftChar = 'C';
    367         private int shiftValue = 2; 
     377        private int shiftValue = 2;
    368378        // private int shiftValue = 2;
    369379        private UnknownSymbolHandlingMode unknownSymbolHandling = UnknownSymbolHandlingMode.Ignore;
     
    402412            HasChanges = true;
    403413
    404             // making sure the shift value lies within the alphabet range     
     414            // making sure the shift value lies within the alphabet range
    405415            offset = offset % alphabet.Length;
    406416
     
    432442                    offset = alphabet.ToUpper().IndexOf(char.ToUpper(value[0]));
    433443                }
    434                
     444
    435445                if (offset >= 0)
    436446                {
     
    451461                LogMessage(''Bad input \'''' + value + ''\''! ('' + e.Message + '') Reverting to '' + shiftChar.ToString() + ''!'', NotificationLevel.Error);
    452462            }
    453         } 
     463        }
    454464
    455465        #endregion
     
    475485            }
    476486        }
    477        
     487
    478488        [PropertySaveOrder(5)]
    479         [TaskPane(''Key as integer'', ''Enter the number of letters to shift. For instance a value of 1 means that the plaintext character a gets mapped to the ciphertext character B, b to C and so on.'', null, 2, true, DisplayLevel.Beginner, ControlType.NumericUpDown, ValidationType.RangeInteger, 0, 100)]       
     489        [TaskPane(''Key as integer'', ''Enter the number of letters to shift. For instance a value of 1 means that the plaintext character a gets mapped to the ciphertext character B, b to C and so on.'', null, 2, true, DisplayLevel.Beginner, ControlType.NumericUpDown, ValidationType.RangeInteger, 0, 100)]
    480490        public int ShiftValue
    481491        {
     
    490500
    491501        [PropertySaveOrder(6)]
    492         [TaskPaneAttribute(''Key as single letter'', ''Enter a single letter as the key. This letter is mapped to an integer stating the position in the alphabet. The values for \''Key as integer\'' and \''Key as single letter” are always synchronized.'', null, 3, true, DisplayLevel.Beginner, ControlType.TextBox, ValidationType.RegEx, ''^([A-Z]|[a-z]){1,1}'')]
     502        [TaskPaneAttribute(''Key as single letter'', ''Enter a single letter as the key. This letter is mapped to an integer stating the position in the alphabet. The values for 'Key as integer' and 'Key as single letter' are always synchronized.'', null, 3, true, DisplayLevel.Beginner, ControlType.TextBox, ValidationType.RegEx, ''^([A-Z]|[a-z]){1,1}'')]
    493503        public string ShiftChar
    494504        {
     
    545555        /// <summary>
    546556        /// Visible setting how to deal with alphabet case. 0 = case insentive, 1 = case sensitive
    547         /// </summary>   
     557        /// </summary>
    548558        //[SettingsFormat(1, ''Normal'')]
    549559        [PropertySaveOrder(8)]
     
    563573                        alphabet = upperAlphabet;
    564574                        LogMessage(''Changing alphabet to: \'''' + alphabet + ''\'' ('' + alphabet.Length.ToString() + '' Symbols)'', NotificationLevel.Info);
    565                         OnPropertyChanged(''AlphabetSymbols'');                       
     575                        OnPropertyChanged(''AlphabetSymbols'');
    566576                        // re-set also the key (shiftvalue/shiftChar to be in the range of the new alphabet
    567577                        setKeyByValue(shiftValue);
     
    574584                        alphabet = upperAlphabet + lowerAlphabet;
    575585                        LogMessage(''Changing alphabet to: \'''' + alphabet + ''\'' ('' + alphabet.Length.ToString() + '' Symbols)'', NotificationLevel.Info);
    576                         OnPropertyChanged(''AlphabetSymbols'');                       
     586                        OnPropertyChanged(''AlphabetSymbols'');
    577587                    }
    578588                }
     
    600610
    601611        protected void OnPropertyChanged(string name)
    602         {         
     612        {
    603613          if (PropertyChanged != null)
    604614          {
     
    622632            sensitivityEnabled = !sensitivityEnabled;
    623633            if (sensitivityEnabled)
    624             {             
     634            {
    625635              TaskPaneAttributeChanged(this, new TaskPaneAttributeChangedEventArgs(new TaskPaneAttribteContainer(''AlphabetCase'', Visibility.Visible)));
    626636            }
     
    640650For testing purposes you may create a simple black and white PNG image with MS Paint or Paint.NET. As image size you can use 40x40 pixels for example, but as the image will be scaled when required, any size should do it. Place the image file in your project directory or in a subdirectory.\clearpage
    641651Then make a right click on the project item "Caesar" or any subdirectory within the Solution Explorer, and select ''Add-$>$Existing Item...'':
     652
    642653\begin{figure}[h!]
    643654        \centering
     
    646657        \label{fig:add_existing_item}
    647658\end{figure}
     659
    648660As you can see, in our solution we create an new folder named ''Images'' (make a right click on the project item ''Caesar'' and select ''Add-$>$New Folder'') and placed there the new icon by clicking right on the folder as mentioned aboved.\clearpage
    649661Then select ''Image Files'' as file type, and choose the icon for your plugin:
     
    669681\end{figure}
    670682\section{Set the attributes for the class Caesar}\label{sec:SetTheAttributesForTheClassCaesar}
    671 Now let's go back to the code of the Caesar class (''Caesar.cs'' file). First we have to set the necessary attributes for our class. This attributes are used to provide additional information for the CrypTool 2.0 environment. If not set, your plugin won't show up in the GUI, even if everything else is implemented correctly.\\\\
    672 Attributes are used for \textbf{declarative} programming and provide meta data, that can be attached to the existing .NET meta data , like classes and properties. CrypTool provides a set of custom attributes, that are used to mark the different parts of your plugin.\\\\
     683Now let's go back to the code of the Caesar class (''Caesar.cs'' file). First we have to set the necessary attributes for our class. This attributes are used to provide additional information for the CrypTool 2.0 environment. If not set, your plugin won't show up in the GUI, even if everything else is implemented correctly.
     684
     685Attributes are used for \textbf{declarative} programming and provide meta data, that can be attached to the existing .NET meta data , like classes and properties. CrypTool provides a set of custom attributes, that are used to mark the different parts of your plugin.
     686
     687
    673688\textit{[Author]}\\
    674689The first attribute called ''Author'' is optional, which means we are not forced to define this attribute. It provides the additional information about the plugin developer. This informations you can see for example in the TaskPane as shown on a screenshot above. We set this attribute to demonstrate how it has to look in case you want to provide this attribute.
     
    678693        \caption{Attribute author}
    679694        \label{fig:attribute_author}
    680 \end{figure}\\
     695\end{figure}
     696
    681697As we can see above the author attribute takes four elements of type string. These elements are:
    682698\begin{itemize}
     
    686702        \item Url = the website or homepage of the developer
    687703\end{itemize}
    688 All this elements are also optional. The developer decides what he wants to publish. Unused elements shall be set to null or a zero-length string ('''').\\
     704All this elements are also optional. The developer decides what he wants to publish. Unused elements shall be set to null or a zero-length string ('''').
     705
    689706Our author attribute should look now as you can see below:
    690707\begin{figure}[h!]
     
    693710        \caption{Filled author auttribute}
    694711        \label{fig:attribute_author_filled}
    695 \end{figure}\\\\
     712\end{figure}
     713
     714
    696715\textit{[PluginInfo]}\\
    697716The second attribute called ''PluginInfo'' provides the necessary information about the plugin like caption and tool tip. This attribute is mandatory. The attribute has the definition as you can see below:
     
    701720        \caption{Attribute PluginInfo}
    702721        \label{fig:attribute_plugininfo}
    703 \end{figure}\\
     722\end{figure}
     723
    704724This attribute expects the following elements:
    705725\begin{itemize}
     
    711731        \item icons = from type string array, which provides all necessary icon paths you want to use in the plugin (e.g. the plugin icon as seen above). This element is mandatory.
    712732\end{itemize}
    713 Unused optional elements shall be set to null or a zero-length string ('''').\\\\
     733Unused optional elements shall be set to null or a zero-length string ('''').
     734
     735
    714736\textit{\small Note 1: It is possible to use the plugin without setting a caption though it is not recommended. This will be changed in future and the plugin will fail to load without a caption.\\\\
    715737\small Note 2: Currently a zero-length toolTip string appears as empty box. This will be changed in future.\\\\
     
    721743        \caption{Attribute PluginInfo element resourceFile}
    722744        \label{fig:attribute_plugininfo_resourceFile}
    723 \end{figure}\\
     745\end{figure}
     746
    724747The second parameter called ''startable'' has to be set to ''false'', because our encryption algorithm is neither an input nor generator plugin.
    725748\begin{figure}[h!]
     
    728751        \caption{Attribute PluginInfo startable}
    729752        \label{fig:attribute_plugininfo_startable}
    730 \end{figure}\\
     753\end{figure}
     754
    731755The next two parameters are needed to define the plugin's name and its description. Now that we decided to provide a resource file we have to place here the both resource field names which contains the description and captions. Otherwise just write here a simple string text:
    732756\begin{figure}[h!]
     
    735759        \caption{Attribute PluginInfo name and description}
    736760        \label{fig:attribute_plugininfo_description}
    737 \end{figure}\\
     761\end{figure}
     762
    738763The next element defines the location path of the description file. The parameter is made up by $<$Assembly name$>$/$<$filename$>$ or $<$Assembly name$>$/$<$Path$>$/$<$file name$>$ if you want to store your description files in a separate folder (as seen on the icon). The description file has to be of type XAML. In our case we create a folder called ''DetailedDescription'' and store our XAML file there with the necessary images if needed. How you manage the files and folders is up to you. This folder could now look as you can see below:
    739764\begin{figure}[h!]
     
    742767        \caption{Attribute PluginInfo icon and description file path}
    743768        \label{fig:attribute_plugininfo_icon_path}
    744 \end{figure}\\
     769\end{figure}
     770
    745771Accordingly the attribute parameter has to be set to:
    746772\begin{figure}[h!]
     
    749775        \caption{Attribute PluginInfo description file}
    750776        \label{fig:attribute_plugininfo_icon}
    751 \end{figure}\\
     777\end{figure}
     778
    752779The detailed description could now look like this in CrypTool (right click plugin icon on workspace and select ''Show description''):\clearpage
    753780\begin{figure}[h!]
     
    756783        \caption{XAML detailed description}
    757784        \label{fig:xaml_description}
    758 \end{figure}\\
     785\end{figure}
     786
    759787The last parameter tells CrypTool the names of the provided icons. This parameter is made up by $<$Assembly name$>$/$<$file name$>$ or $<$Assembly name$>$/$<$Path$>$/$<$file name$>$.\\\\
    760788The most important icon is the plugin icon, which will be shown in CrypTool in the ribbon bar or navigation pane (This is the first icon in list, so you have to provide at least one icon for a plugin). As named above how to add an icon to the solution accordingly we have to tell CrypTool where to find the icon by setting this parameter as you can see below:
     
    764792        \caption{Attribute PluginInfo icons}
    765793        \label{fig:attribute_plugininfo_icons}
    766 \end{figure}\\
     794\end{figure}
     795
    767796You can define further icon paths if needed, by adding the path string separated by a comma. We just add here two further icons (don't forget to add the icons to your solution) to provide them for the context menu in the CrypTool workspace.\\\\
    768797\textit{[EncryptionType]}\\
     
    773802        \caption{Attribute encryption type}
    774803        \label{fig:attribute_encryption_type}
    775 \end{figure}\\
     804\end{figure}
     805
    776806The ''EncryptionType'' attribute can also be set as the following types:
    777807\begin{itemize}
     
    782812        \item SymmetricStream = for all stream cipher algorithms like RC4, Rabbit or SEAL
    783813\end{itemize}
     814
     815
    784816\section{Set the private variables for the settings in the class Caesar}\label{sec:SetThePrivateVariablesForTheSettingsInTheClassCaesar}
    785817The next step is to define some private variables needed for the settings, input and output data which could look like this:
     
    883915{
    884916        get { return this.inputString; }
    885         set 
     917        set
    886918  {
    887919                if (value != inputString)
     
    919951        {
    920952                if (outputString != null)
    921                 {                   
     953                {
    922954                        CryptoolStream cs = new CryptoolStream();
    923955                        listCryptoolStreamsOut.Add(cs);
     
    937969{
    938970        get { return ((CaesarSettings)this.settings).AlphabetSymbols; }
    939         set 
     971        set
    940972        {
    941                 if (value != null && value != settings.AlphabetSymbols) 
    942                 { 
     973                if (value != null && value != settings.AlphabetSymbols)
     974                {
    943975                        ((CaesarSettings)this.settings).AlphabetSymbols = value;
    944976                        OnPropertyChanged(''InputAlphabet'');
    945                 } 
     977                }
    946978        }
    947979}
     
    951983{
    952984        get { return settings.ShiftKey; }
    953         set 
    954         { 
     985        set
     986        {
    955987                if (value != settings.ShiftKey)
    956988                {
     
    10081040\end{lstlisting}
    10091041\section{Complete the actual code for the class Caesar}\label{sec:CompleteTheActualCodeForTheClassCaesar}
    1010 Up to now, the plugin is ready for the CrypTool base application to be accepted and been shown correctly in the CrypTool menu. What we need now, is the implementation of the actual algorithm in the function ''Execute()'' which is up to you as the plugin developer. CrypTool will always call first the Execute() function.If you place the whole algorithm in this function or split in other as needed is also up to you.\\
    1011 We decided to split our algorithm encryption and decryption in two seperate functions, which finally call the function ProcessCaesar.\\
     1042Up to now, the plugin is ready for the CrypTool base application to be accepted and been shown correctly in the CrypTool menu. What we need now, is the implementation of the actual algorithm in the function ''Execute()'' which is up to you as the plugin developer. CrypTool will always call first the Execute() function.If you place the whole algorithm in this function or split in other as needed is also up to you.
     1043
     1044We decided to split our algorithm encryption and decryption in two separate functions, which finally call the function ProcessCaesar.
     1045
    10121046Let us demonstrate the Execute() function, too:
    10131047\begin{lstlisting}
     
    10181052        string alphabet = cfg.AlphabetSymbols;
    10191053
    1020   // in case we want don't consider case in the alphabet, we use only capital letters, hence transform 
     1054  // in case we want don't consider case in the alphabet, we use only capital letters, hence transform
    10211055        // the whole alphabet to uppercase
    10221056        if (!cfg.CaseSensitiveAlphabet)
     
    10241058                alphabet = cfg.AlphabetSymbols.ToUpper(); ;
    10251059        }
    1026            
     1060
    10271061        if (inputString != null)
    10281062        {
     
    11891223\end{lstlisting}
    11901224Your plugin should compile without errors at this point.\clearpage
     1225
    11911226\section{Import the plugin to CrypTool and test it}\label{sec:ImportThePluginToCryptoolAndTestIt}
    11921227After you have built the plugin, you need to move the newly created plugin DLL to a location, where CrypTool can find it. To do this, there are the following ways:
     
    11981233        \caption{Copy plugin to global storage}
    11991234        \label{fig:copy_dll_global_storage}
    1200 \end{figure}\\
     1235\end{figure}
     1236
    12011237This folder is called ''Global storage'' in the CrypTool architecture. Changes in this folder will take effect for all users on a multi user Windows. Finally restart CrypTool.\clearpage
    12021238\begin{figure}[h]
     
    12051241        \caption{Plugins global storage}
    12061242        \label{fig:global_storage}
    1207 \end{figure}\\
     1243\end{figure}
     1244
    12081245        \item Copy your plugin DLL file in the folder ''CrypPlugins'' which is located in your home path in the folder ''ApplicationData'' and restart CrypTool.  This home folder path is called ''Custom storage'' in the CrypTool architecture. Changes in this folder will only take effect for current user.  On a German Windows XP the home folder path could look like:
    12091246''C:\textbackslash Dokumente und Einstellungen\textbackslash $<$User$>$\textbackslash Anwendungsdaten\textbackslash CrypPlugins'' and in Vista/Windows7 the path will look like ''C:\textbackslash Users\textbackslash $<$user$>$\textbackslash Application Data\textbackslash CrypPlugins''.\clearpage
     
    12321269        \caption{Build Events}
    12331270        \label{fig:post_build}
    1234 \end{figure}\\
     1271\end{figure}
     1272
    12351273Enter the following text snippet into ''Post-build event command line'':\\\\
    12361274cd ''\$(ProjectDir)''\\
     
    12411279You need to adapt the yellow marked field to your actual project name.
    12421280\end{itemize}
     1281
     1282
    12431283\section{Source code and source template}\label{sec:SourceCodeAndSourceTemplate}
    12441284Here you can download the whole source code which was presented in this ''Howto'' as a Visual Studio \textbf{solution}:\\\\
     
    12561296        \caption{Plugin sample}
    12571297        \label{fig:sample}
    1258 \end{figure}
     1298\end{figure} 
Note: See TracChangeset for help on using the changeset viewer.