AF 2.x Clients contain an executable named RegPlugIn.exe used for registering plug-in assemblies, typically located in the \PIPC\AF directory. There are currently 4 types of PI AF Plug-Ins: DataReference, DeliveryChannel, TimeRule, and AnalysisRule. In addition, there may be support assemblies that are required for the implementation of the AF Plug-Ins or to provide translated resources for different languages. Starting in AF 2.1, support (or dependent) assemblies can be loaded by RegPlugIn as well.
The goal of this blog is to walk you through a simple example on the caveats of using RegPlugIn to register support assemblies. The following examples are tested with PI AF 2014 R2.
Background on the RegPlugIn Utility
The simplest way to register an AF Plug-In is to run the RegPlugIn utility located in the \PIPC\AF folder:
which uploads the plug-in to the AF server. When an AF client (e.g. PI System Explorer) needs the Plug-In, it will download the Plug-In on to the client computer in the %ProgramData%\OSIsoft\AF\PlugIns directory.
.NET of the Plug-In
version Shipped with AF client
version Shipped with AF client
dll version of the custom plug-In
dll version of the custom plug-In
The above applies for plug-ins targeting “Any CPU”. If the plug-in specifically targets “x86”, it will be placed under the x86 folder under its respective directory; similarly, plug-ins targeting “x64” will be placed under the x64 folder.
After registering the plug-in, you can list the registered assemblies by running:
There are other parameters (e.g. you can specify the PI AF server) available for the RegPlugIn utility. For examples and parameters, I recommend checking out the “Managing plug-ins” section in the PI System Explorer User Guide.
My First Attempt at Registering a Support Plug-In (Do not Follow!)
In this example, I will use a custom delivery channel that I developed to output alerts at specific Twitter handle (TwitterDeliveryChannel.dll). As part of the project, I am referencing a support assembly that serves as a .NET wrapper to the Twitter API (LinqToTwitter.dll).
After compiling the class library, I am ready to register the delivery channel plug-in. I copied both assemblies from my development server to one of my AF client machines, under C:\Users\dng\Documents. After navigating to the \PIPC\AF directory, I first register my main Delivery Channel plug-in (TwitterDeliveryChannel.dll):
I then register the support assembly (LinqToTwitter.dll):
RegPlugIn “C:\Users\dng\Documents\LinqToTwitter.dll” /own:TwitterDeliveryChannel.dll
The /own or /owner parameter is used to specify the name of the owner assembly during support assembly registration. Alternatively, you can register both assemblies at the same time:
RegPlugIn “C:\Users\dng\Documents\TwitterDeliveryChannel.dll” “C:\Users\dng\Documents\LinqToTwitter.dll” /own:TwitterDeliveryChannel.dll
The following message shows that my assembly has been successfully registered. Note that the support assembly is registered at the relative path (“Users\dng\Documents\LinqToTwitter.dll”):
This can be further confirmed by running RegPlugIn /List:
However, when I tried to use my new Twitter Delivery Channel on a client machine, I encountered this error:
On the client machine, the TwitterDeliveryChannel.dll is downloaded to the %ProgramData%\OSIsoft\AF\PlugIns\220.127.116.11 directory (version of the dll). Interestingly, the LinqToTwitter is located at %ProgramData%\OSIsoft\AF\PlugIns\18.104.22.168\Users\dng\Documents.
When I run Process Explorer to look at which directories PI Notifications is trying to find the supporting assembly (LinqToTwitter.dll):
It looks like PI Notifications Manager is only looking for the supporting assembly at the PlugIns (root) and PlugIns\version directories. Since my supporting assembly is located at PlugIns\22.214.171.124\Users\dng\Documents, it cannot be found or loaded.
When (and how) are the assemblies loaded?
When a PI AF SDK client needs the plug-in (e.g. creating a delivery channel end point), it will download the necessary dll (e.g. TwitterDeliveryChannel.dll) from the AF server if the client does not have the plug-in with the same (or higher) version. It then calls loadLibrary to load the dll from the directory path according to the dll specifications (e.g. .NET 3.5 or 4+, x86/x64, and version).
On the other hand, PI AF SDK does not load the supporting dll (e.g. LinqToTwitter.dll) directly. Microsoft runtime (or .NET framework) is responsible to load any referenced dll when it is required. Since my custom delivery channel does not explicitly call loadLibrary to load the required dll by specifying the relative path, the runtime will search in the GAC and through the default search path. Since Users\dng\Documents is not in the search path. The support dll is not loaded.
RegPlugIn uses the same path for both the input and output file location for supporting assemblies
When using RegPlugIn to register an AF plug-in, the file name (defaulted to current directory) or the path name is needed to specify where the dll is that you are trying to register. For the main plugin dll, the location of the plug-in in the client machine is determined strictly by the dll specifications.
However, for support dlls, the file path argument is used for both input and output specification. The file path is used by RegPlugIn to find where the dll is located, as well as to specify the relative path where the supporting assembly will be downloaded on the client machine (in this case, Users\dng\Documents). I was therefore implicitly specifying the relative output path when I was trying to register the supporting assembly!
How to Register Supporting Plug-Ins? (A Better Way)
The easiest way to register support assemblies is to put them in the same directory as the main plug-in dll. This way, they will be downloaded to the same directory onto the AF client machine. Rather than specifying the input path for the dll as the input arguments for RegPlugIn.exe, navigate to the directory containing the dlls and run:
“%pihome%\AF\RegPlugIn.exe” TwitterDeliveryChannel.dll LinqToTwitter.dll /own:TwitterDeliveryChannel.dll
Then, use RegPlugIn /list to verify that the plug-in and its supporting dlls are put in the same directory:
You can also verify on the client machine that the plugin and its supporting dlls are downloaded into the expected directory.
Note that the search path could be modified by the %path% environment variable or through the application config file. The directory where the calling program or dll is loaded is also path of the search path. You can also hardcode the relative directory path to load the supporting dll. However, I find the easiest way to register support assembly is to put them in the same directory as the main plug-in dll.
When invoking RegPlugIn, set the default directory to where the input dlls are located and explicitly specify the path of RegPlugIn.exe. I hope you find this blog post helpful!