I want to create a Kofax Export Connector and register it in the Administration module. I created a Class Library (.NET Framework) with the following code for the setup and release
KfxReleaseSetupScript.cs
namespace Kofax_CoBRA_Export
{
[Guid("b826cc5a-ed80-4fe1-a80f-86a08cca2851")]
public interface IKfxReleaseSetupScript
{
ReleaseSetupData SetupData { get; set; }
KfxReturnValue OpenScript();
KfxReturnValue CloseScript();
KfxReturnValue RunUI();
KfxReturnValue ActionEvent(KfxActionValue action, string dataStringOne, string dataStringTwo);
}
[Guid("39a4f6f6-0de1-40b2-8934-d9a7c2c79468")]
[ClassInterface(ClassInterfaceType.None)]
[ProgId("Kofax_CoBRA_Export.KfxReleaseSetupScript")]
internal class KfxReleaseSetupScript : IKfxReleaseSetupScript
{
// Interface Implementation
}
}
KfxReleaseScript.cs
namespace Kofax_CoBRA_Export
{
[Guid("091d8f6c-b4c4-42d4-81aa-3b86b31ce46d")]
public interface IKfxReleaseScript
{
ReleaseData DocumentData { get; set; }
KfxReturnValue OpenScript();
KfxReturnValue CloseScript();
KfxReturnValue ReleaseDoc();
}
[Guid("e034c243-ae35-4823-9f2f-10bb6a6fe5c0")]
[ClassInterface(ClassInterfaceType.None)]
[ProgId("Kofax_CoBRA_Export.ReleaseScript")]
internal class KfxReleaseScript : IKfxReleaseScript
{
// Interface Implementation
}
}
My .inf registration file contains this code
[Scripts]
Kofax_CoBRA_Export
[Kofax_CoBRA_Export]
SetupModule=.\bin\Debug\Kofax_CoBRA_Export.dll
SetupProgID=Kofax_CoBRA_Export.KfxReleaseSetupScript
SetupVersion=1.0
ReleaseModule=.\bin\Debug\Kofax_CoBRA_Export.dll
ReleaseProgID=Kofax_CoBRA_Export.KfxReleaseScript
ReleaseVersion=1.0
SupportsNonImageFiles=True
RemainLoaded=True
SupportsKofaxPDF=True
SupportsOriginalFileName=True
SupportsMultipleInstances=False
DisplayName=Kofax_CoBRA_Export
When I select the .inf file in the adminstration module I just get an empty box so there is nothing to install.
I took the information from
Kofax Capture Developer's Guide 10.0.0
KCEC-Text Exporter Sample
Kofax Capture API Reference Guide
Kofax Capture Export Type Library
but I really don't get why I get anything to install in the administration module. Any help would be appreciated.
When providing a relative path, Kofax expects the binaries in its own directory (usually C:\Program Files (x86)\Kofax\CaptureSS\ServLib\Bin on a server, as admin.exe runs using this working path). In your case that would translate to C:\Program Files (x86)\Kofax\CaptureSS\ServLib\Bin\bin\Debug\Kofax_CoBRA_Export.dll.
Note that Kofax recommends copying all custom binaries including your inf file to the server directory, however I prefer creating a sub folders for my code, putting all files there. Then, my inf file would look as follows:
[Scripts]
SmartCAP.KEC.EnergieAG.SAP
[SmartCAP.KEC.EnergieAG.SAP]
SetupModule=SmartCAP.KEC.EnergieAG.SAP.dll
SetupProgID=SmartCAP.KEC.EnergieAG.SAP.Setup
SetupVersion=11.0
ReleaseModule=SmartCAP.KEC.EnergieAG.SAP.dll
ReleaseProgID=SmartCAP.KEC.EnergieAG.SAP
ReleaseVersion=11.0
SupportsNonImageFiles=True
SupportsKofaxPDF=True
Note that Kofax still needs to be able to resolve all dependencies you used in your solution - most definitely internal ones such as the Kofax.ReleaseLib.Interop.DLL - so, you could either copy them there, or - that's what I'd prefer, use a custom assembly resolver in your code, pointing to the server directory.
Related
I'm new to using class libraries. I've started a rather large project for work which needs the ability to be a self-contained file (essentially just drop a .exe on a desktop and run it without prereqs). This means the current class libraries build inside the .exe and I'm unsure how to directly reference them - but the application knows of them and uses them.
I've so far coded the project with the separate class libraries, and it all works great, but I'm now at the part where I need to add the ability for this to load the contents of a file dynamically if the file is available and of a greater file version.
For example:
File.dll v1 is self-contained
File.dll v2 is added to C:\ProgramData\FileVersions (dynamicdLLPath)
Assembly fileDll;
private void LoadDynamicDLLs()
{
if (Directory.Exists(dynamicDLLPath))
{
string filePath = dynamicDLLPath + "File.dll";
if (File.Exists(filePath))
{
FileVersionInfo curfvi = FileVersionInfo.GetVersionInfo(myassembly.Location);
FileVersionInfo newfvi = FileVersionInfo.GetVersionInfo(filePath);
if (Convert.ToInt64(newfvi.FileVersion) > Convert.ToInt64(curfvi.FileVersion))
{
fileDll = Assembly.LoadFrom(filePath);
}
} else
{
fileDll = Assembly.GetAssembly(typeof(FileDLL));
}
}
}
(FileDLL in this instance is the namespace of the self-contained dll)
If this loads correctly, can I then just call all my methods/functions from the file assembly as;
fileDll.myMethod();
This is as far as I've gotten based on not changing any of the existing code base that works. I'd rather not go through 20,000 lines if there's a solution to simply integrate what I've already got using a local .dll class library.
I have some generic interface
namespace SimpleLibrary
{
public interface IImported<T>
{
T Value { get; set; }
}
}
and its implementation in another .dll
namespace ImportedLibrary
{
[Export(typeof(IImported<>))]
public class ExportedEntry<T> : IImported<T>
{
public T Value { get; set; }
}
}
Then I make import into another class
namespace SimpleLibrary
{
public class MainEntry
{
[Import]
public IImported<string> Imported { get; set; }
public MainEntry()
{
try
{
var catalog = new DirectoryCatalog(Dir);
var container = new CompositionContainer(catalog);
container.ComposeParts(this);
Imported.Value = "Gomo Sapiens";
}
catch (CompositionException ex)
{
System.Diagnostics.Debugger.Launch();
}
catch (Exception ex)
{
System.Diagnostics.Debugger.Launch();
}
}
private string Dir
{
get
{
var dir = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ProgramFiles), "SimpleLibrary");
if (!Directory.Exists(dir))
{
dir = AppDomain.CurrentDomain.BaseDirectory;
}
return dir;
}
}
}
}
Then I create console application, put .dll with class marked [Export] inside bin\Debug folder and run
static void Main(string[] args)
{
MainEntry me = new MainEntry();
Console.WriteLine(me.Imported.Value);
Console.ReadLine();
}
Everything works fine, console displays line "Gomo Sapiens".
However, when I create Wix Installer with some custom action that uses the same MainEntry class and runs after InstallFinalize, import doesn't work:
<Binary Id="ServerActions" SourceFile="path to CA.dll" />
<CustomAction Id="RunMainEntry" BinaryKey="ServerActions" DllEntry="RunMainEntry" Execute="immediate" Return="check" />
<InstallExecuteSequence>
<Custom Action='RunMainEntry' After='InstallFinalize'>NOT Installed AND NOT WIX_UPGRADE_DETECTED</Custom>
</InstallExecuteSequence>
and custom action code
public class CustomActions
{
[CustomAction]
public static ActionResult RunMainEntry(Session session)
{
MainEntry me = new MainEntry();
session.Log(me.Imported.Value);
return ActionResult.Success;
}
}
Custom action throws CompositionException. Notice that my installer initially copies all files (.dll and .exe) inside Program Files(x86)\SimpleLibrary, then calls custom action with MEF composition. I want to highlight that at the moment of calling MainEntry constructor all .dlls do lie inside Program Files folder and MEF sees them but can't find what to import. And problem appears only with generics types, simple interfaces do import.
.NET Framework version is 4.5, C# 6.0. CustomAction.config:
<configuration>
<startup useLegacyV2RuntimeActivationPolicy="true">
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5" />
</startup>
</configuration>
Also tried to use MefContrib, situation is the same.
Important thing is that when I run console app manually from Program Files(x86) after installation complete everything again works fine.
So the question is how can I use MEF from Wix's custom actions and if I can't - why?
I'm fairly certain that when running a custom action the installer will unpack the CA.dll binary into a temporary directory and run it from there. If you added anything to the PATH it will not be reflected within the installer's environment so you won't detect any of the new files.
You can verify with running with msi logging (/l*v log.txt) and/or running with procmon also capturing at the same time.
You will probably need to package the dependent DLLs within the self-extracting CA.dll itself.
You can do this by defining <CustomActionContents> in your custom action project and setting the value of this MSBuild property to a ;-separated list of paths to the dependent DLLs. Then when you build, these DLLs along with your custom action dll will be packaged into the CA.dll which will get extracted to a temporary directory for use at runtime for the custom action.
I actually have another answer with better details about what CustomActionContents is and what it does here. It says "space-delimited" in the comment but I've verified it is ;-delimited. This also gives you the location of the file where the MSBuild target and property is defined if you want to read that code as well.
I know this seems like a simple thing but I can't find any help online.
I want to include a file (.html) along with my Azure function when I publish it using Visual Studio. Then I want to be able to access this file in my Azure function.
Why? It seems like only the .dll gets sent to the server when I publish.
This file will be an .html file that will be an email template. I want to read it in my function and then send emails out.
Any help is much appreciated.
I see I can use [send grid in Azure functions][1], but it looks like I can only send out one email and not multiple emails, which is what I want.
First, you need to add the html file to your project, and in the properties, set Copy to Output Directory to "Copy if newer".
Then in your function code, take in an additional ExecutionContext context parameter (note that this is Microsoft.Azure.WebJobs.ExecutionContext and not System.Threading.ExecutionContext). And when you need to access your html file, you can then write:
string htmlFilePath = Path.Combine(context.FunctionAppDirectory, "test.html");
That's assuming you added the file at the root of your VS project. If you instead added it in some Data folder (better practice), you'd write:
string htmlFilePath = Path.Combine(context.FunctionAppDirectory, "Data", "test.html");
See here for full working sample.
I have the same scenario as you have. However, I cannot access ExecutionContext because it is only available in requests. My scenario needs to get the template included in AzFunc project but not in the context of AzFunc's functions. I got it null when I go with the interface - implementation class approach.
Thanks to this guy, I use IOptions<ExecutionContextOptions> in my class to get the root directory of the Azure Func.
My Azure Func project (NET 6, Azure Function v4)
using Microsoft.Extensions.Options;
using Microsoft.Azure.WebJobs.Host.Bindings;
namespace AzureFuncApi
{
public class TemplateHelper : ITemplateHelper
{
private readonly IOptions<ExecutionContextOptions> _executionContext;
public TemplateHelper (IOptions<ExecutionContextOptions> executionContext)
{
_executionContext = executionContext;
}
public string GetTemplate()
{
var context = _executionContext.Value;
var rootDir = context.AppDirectory; // <-- rootDir of AzFunc
var template = Path.Combine(rootDir, "test.html"); // <-- browse for your template. Here's an example if you place test.html right in the root of your project
// return your template here, raw, or after you do whatever you want with it...
}
}
}
My different project defines the interface and uses it there, independently of the real implementation
namespace DifferentProject
{
public interface ITemplateHelper
{
string GetTemplate(); // Use this to get the template
}
}
I am trying to write a plug-in for an application. The only thing I am provided with is a dll resource file which defines an interface; here's the code:
using System;
using System.Drawing;
namespace App.Plugin.Resources.Interface
{
public interface IAppPlugin
{
string Name { get; set; }
string Description { get; set; }
string Author { get; set; }
string Version { get; set; }
Icon MenuIcon { get; set; }
EventHandler PluginEventHandler { get; set; }
}
}
I then created a class that implemented this interface, made it display a message box, compiled the dll, placed it in the Plugins folder of the application and when the application executed and launched the plugin, it did display the message.
It seems to me that the software offers the means to execute external code (through the plugin system), but doesn't actually give access to any of the application's properties or methods.
Considering the above, my question is: Am I able to interact with the host process in any other way (e.g. get informed when a menu item is selected or even add a menu item myself to the main GUI) with the given resources or does this plugin system just act as an application launcher (by executing the code in the dll I'm providing)?
This seems just an application launcher, not a real plugin, unless there is some strategy implemented by convention: maybe the app looks at the plugin constructor with reflection, and pass some interfaces to the host system, or it looks for some properties marked with some custom attributes to pass some entry points.Another possible vehichle to pass the main application entry points is the PluginEventHandler, try to see in debug what you receive when the plugin is invoked. In addition, try to look with some tools as ILspy to see if there is something more in the plugin instantiation.
I have created a simple class library project in visual studio 2008 that has one class as shown below. I am trying to get this class to register for COM interop so that I can use in via unmanaged scripts like vbscript or jscript.
In my project build properties I have checked the box that says "Register for COM Interop".
In the Assembly Settings I have checked "Make this assembly COM Visible" and I have confirmed that the [assembly: ComVisible(true)] attribute is present in the assembly.cs file.
Every time I build this project I get an error that reads "projectname.dll does not contain any types that can be registered for COM Interop. Also, I have not been able to successfully create an instance of class 1 using a vbscript. Does anyone know that this is not registering properly?
My vbscript fails to create activex object at this line... Set F = CreateObject("64BitCLTest.Class1").
Finally, how do I get VS to register this in the 64bit area of the registry instead of the 32 bit area so that 64bit processes can use it?
-- The Test Class--
namespace _64BitCLTest
{
[Guid("BBAA06EF-CA4C-4fe2-97CD-9B1D85ADA656")]
[ClassInterface(ClassInterfaceType.AutoDual)]
[ComVisible(true)]
[ProgId("64BitCLTest.Class1")]
public class Class1
{
Class1()
{
// do nothing
}
public string Method1()
{
return "This is a return string from method 1";
}
public int Property1
{
get {return 777;}
}
}
}
you need to mark the constructor public:
-- The Test Class--
namespace _64BitCLTest
{
[Guid("BBAA06EF-CA4C-4fe2-97CD-9B1D85ADA656")]
[ClassInterface(ClassInterfaceType.AutoDual)]
[ComVisible(true)]
[ProgId("64BitCLTest.Class1")]
public class Class1
{
public Class1()
{
// do nothing
}
public string Method1()
{
return "This is a return string from method 1";
}
public int Property1
{
get {return 777;}
}
}
}
There are two parts to this answer. The first, problem as consultutah said was that I did not have the constructor marked as public.
The second answer is that there is a bug (I believe) in VS2008 that causes assemblies to never be registered in the 64-bit section of the registry, even if the setup project is configured for a target platform of x64.
I installed VS2010, rebuilt the exact same project and ran the Install. The assembly registered perfectly and I was able to successfully access it through COM using a 64bit process. I still have not found a solution for this in VS2008.