Custom Module is being used by batch classes and cannot be removed - kofax

I would like to remove my custom module from the Kofax administration module but I can't because I get the following error
Using the module multiple times increases the amount of batch classes listed there. But there is only one batch class so this can't be.
I removed the module from the batch class queue, stopped all background services and have no forms app running. The only way to remove this module is to export the batch class, delete it in the administration module, delete the custom module and reimport the batch class.
Maybe I don't exit the application properly?
My session management:
public void LoginToRuntimeSession()
{
login = new Login();
login.EnableSecurityBoost = true;
login.Login();
login.ApplicationName = Resources.CUSTOM_MODULE_ID;
login.Version = "1.0";
login.ValidateUser($"{Resources.CUSTOM_MODULE_ID}.exe", false);
session = login.RuntimeSession;
}
public void Logout()
{
session.Dispose();
login.Logout();
}
I get a new active batch with this code
public IBatch GetNextBatch()
{
return session.NextBatchGet(login.ProcessID);
}
and this is how I process the batch after polling for new ones
public void ProcessBatch(IBatch batch)
{
// ... IACDataElement stuff
batch.BatchClose(KfxDbState.KfxDbBatchReady, KfxDbQueue.KfxDbQueueNext, 0, "");
}
Any ideas how to fix this "bug"? Please let me know if you need more information!

The message you are seeing is only referring to the configuration in the Administration module. Therefore it is not related to what your module actually does when it is running or closing (no problem in your code can cause this).
If you are using Kofax Capture 11, previous published versions of the batch class remain in the system, so these probably still count as references to the module. If you go to the Publish dialog window, you can click the "Versions..." button to see and delete older versions. Try to remove your module again after you have deleted all the older versions that were still using it.
Additionally, you can look through the batch class properties to make sure that this module isn't set in one of the other settings, such as the module to start foldering on the Foldering tab, or the module to start Partial Batch Export on the Advanced tab.
If neither of those suggestions work, then you may want to open a case with Kofax Technical Support. One thing that either they or you can do is open the admin.xml file in the exported batch class cab file and see where your module ID is found. That will give context for finding out what is still referencing the module.

Related

Azure Logic App, Cant get data from CreateFile Function

So I've noticed a strange behavior which I would like to share and see if anyone has had the similar problem.
We are using on Prem solution where we pickup a file or a http event request, map it to an outgoing xml xsd/schema and then create the file later on prem.
The problem was that the system where we save the file does not cooperate so good with the logic app, the logic app failes sometime because the system takes the file before the logic app can finish writing the full content.
The system receiving the files only read .xml files, so we though we should first rename the files to tmp, let logic app create the files and then rename them.
This solution sounded quite simple before we started actually applying it to the logic app.
If we take FileSystem function which has Rename File function and use the parameters “Name” from the create file on prem
{
"statusCode": 404,
"message": "Resource not found"
}
We get the message 404 that the resource is not found, now this complicates a lot of things, I’ve checked the privileges on the account that should not be an issue.
What we also have tried is listing all files in the folder, creating a foreach and then adding a rule and the Rename File function. This makes it work but the logic app does not cope well with receiving a lof of files at ones with that solution.
But the Rename Files works when it’s in a foreach loop and we extract the file names in a list from root folder or normal folder.
But why does it not work with just using the Rename Function? Is this perhaps an azure function bug in the Logic app Rename File Function?
So after discussing with Microsoft support on Azure they have actually confirmed that there is a bug with the “Create File” function.
It looks like all the data and information is actually lost during that functions, the support technicians do not know why that is happening but they have had similar cases which people have reported.
I have not stumbled across any of those posts, but I will post how we solved the problem with a work around.
FYI, The support team has taken the case further so that the developers at azure should look into it, because it’s not just “name” tag which is lost from Create a File, ( it’s all valuable options are actually lost ).
So first we initialize a variable and then actually set the variable name with two steps before we create the file:
The name is set with a temp name and a GUID.
Next step is creating the file with the temp-name used in function “Set Variable Temp FileName”
And on the Rename File function we use the Path from where we store the temp file and add \”FILENAME”
And add the “New Name” which we want to use.
This proved to work but is a workaround, support confirmed that you should be able to just use the “RenameFile” after creating the file with a temp name and changing it to the desired name.
But since Create a File does not send or pass any information at all from this list we have to initialize Variables to make it work.
If anyone has stumbled on the same problem where the Backend system reads the files before they are managed to be created by the logic app and you need some workaround this worked good for me.
Hope it helps!
We recently had the same issue; and the workaround of renaming the file also failed.
The cause seems to be that the Azure On Prem Gateway creates a file (or renames a file), then releases its lock, before checking that the file exists. In the gap between releasing the lock and checking that the file exists, the file may be picked up (deleted) thus causing LogicApps to think the step failed (reporting a 404 error), and thus confusion.
Our workaround was to create a Windows service which we hosted on the file servers (so they'd be able to respond to file changes before anything else on the network). This service has a configuration file which accepts a list of paths and file filters, and it uses the FileSystemWatcher to monitor for new files, or renamed files. When it detects a match it takes out a read lock on the file. This ensure it's not blocked by anything writing to the file (i.e. so it doesn't have to wait for the On Prem Gateway's write aciton to complete before obtaining its own lock), but whilst our service holds its lock the file can't be deleted (so the consumer can't remove the file / buying time for the On Prem Gateway to perform it's post-write read and report success). Our service releases its own lock after a defined period (we've gone with 30 seconds, though you could likely get away with much less). At that point, the consumer can successfully consume the file.
Basic code for the file watch & locking logic below:
sing System;
using System.IO;
using System.Diagnostics;
using System.Threading.Tasks;
namespace AzureFileGatewayHelper
{
public class Interceptor: IDisposable
{
object lockable = new object();
bool disposed = false;
readonly FileSystemWatcher watcher;
readonly int lockTimeInMS;
public Interceptor(string path, string filter, int lockTimeInSeconds)
{
lockTimeInMS = lockTimeInSeconds * 1000;
watcher = new FileSystemWatcher();
watcher.Path = path;
watcher.Filter = filter;
watcher.NotifyFilter = NotifyFilters.LastAccess
| NotifyFilters.LastWrite
| NotifyFilters.FileName
| NotifyFilters.DirectoryName;
watcher.Created += OnIncercept;
watcher.Renamed += OnIncercept;
}
public Interceptor(InterceptorConfigElement config) : this(config.Path, config.Filter, config.TimeToLockInSeconds) { Debug.WriteLine($"Loaded config ${config.Key}: Path: '${config.Path}'; Filter: '${config.Filter}'; LockTime: : '${config.TimeToLockInSeconds}'."); }
public void Start()
{
watcher.EnableRaisingEvents = true;
}
public void Stop()
{
if (watcher != null)
watcher.EnableRaisingEvents = false;
}
private async void OnIncercept(object source, FileSystemEventArgs e)
{
using (var fs = new FileStream(e.FullPath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
{
Debug.WriteLine($"Locked: {e.FullPath} {e.ChangeType}");
await Task.Delay(lockTimeInMS);
}
Debug.WriteLine($"Unlocked {e.FullPath} {e.ChangeType}");
}
public void Dispose()
{
if (disposed) return;
lock (lockable)
{
if (disposed) return;
Stop();
watcher?.Dispose();
disposed = true;
}
}
}
}

kofax export script project setup

For my first export script I took the KCEC example and the APIRefExport.chm documentation to create my project by replacing the example code with my own.
I would like to create a clean export script from scratch.
I created a new class library project and called it EmptyExportScript (placeholder). The target framework is .Net 4. The platform target is x86 and the output path is .....\Program Files (x86)\Kofax\CaptureSS\ServLib\Bin\. When debugging I would like to start the administration module so I set this path .......\Program Files (x86)\Kofax\CaptureSS\ServLib\Bin\.
The option "Make assembly COM-Visible" is checked and I added the Kofax.ReleaseLib.Interop.dll to the references.
For the KfxReleaseScript.cs I added this code
[ClassInterface(ClassInterfaceType.None)]
[ProgId("KFXTS.EmptyExportScript.KfxReleaseScript")]
public class KfxReleaseScript
{
public ReleaseData documentData;
// public KfxReturnValue OpenScript()
// public KfxReturnValue ReleaseDoc()
// public KfxReturnValue CloseScript()
}
For the KfxReleaseScriptSetup.cs I added this code
[ClassInterface(ClassInterfaceType.None)]
[ProgId("KFXTS.EmptyExportScript.KfxReleaseScriptSetup")]
public class KfxReleaseScriptSetup
{
public ReleaseSetupData setupData;
// public KfxReturnValue OpenScript()
// public KfxReturnValue CloseScript()
// public KfxReturnValue RunUI()
// public KfxReturnValue ActionEvent(KfxActionValue actionID, string data1, string data2)
}
Lastly I added a Form to the project when running the UI.
For registration I added a EmptyExportScript.inf with this content
[Scripts]
Empty Export
[Empty Export]
SetupModule=EmptyExportScript.dll
SetupProgID=KFXTS.EmptyExportScript.KfxReleaseScriptSetup
SetupVersion=10.2
ReleaseModule=EmptyExportScript.dll
ReleaseProgID=KFXTS.EmptyExportScript.KfxReleaseScript
ReleaseVersion=10.2
SupportsNonImageFiles=True
SupportsKofaxPDF=True
RemainLoaded=True
SupportsOriginalFileName=False
When building the project .dll and .inf file get placed into the kofax bin directory.
I recognized that other scripts have a .pdb and .dll.config file in there too.
How do I get them?
When trying to install the custom script, I can add it to the script installation manager but I can't install it. There is nothing to install so I think I'm missing the .pdb and .dll.config file.
Is anything else missing?
Thanks for help :)
Kofax does not need a pdb file, but they are handy if you want to debug your connector and attach it to the release.exe process (learn more about them here).
I would not recommend changing the output path itself to Capture\Bin, but rather create a post-build event:
For example, the following line copies all required files to a separate folder under the CaptureSS\Bin folder:
xcopy "$(TargetDir)*" "C:\Program Files (x86)\Kofax\CaptureSS\ServLib\Bin\SmartCAP\kec\SmartCAP.KEC.Template\" /Y /S
Having a dll.config file is possible, but rare. I would rather recommend storing process-specific data in a custom storage string object of the respective batch class definition (which has the added benefit that you can just import/export the definition along with the batch class, and that you can display and have it changed it in setup form). Having said all that, back to your initial issue - the connector can't be installed.
COM visibility
The assembly needs to be COM-visible, but you mentioned that it was. For the sake of completeness, here's what you will need to do. Note that the GUID must be unique (only relevant if you copied an existing solution):
If you're installing the connector on a different machine, you will need to register it first using regasm.exe - here's an example:
"C:\Windows\Microsoft.NET\Framework\v4.0.30319\RegAsm.exe" SampleExport.dll /codebase /tlb:SampleExport.tlb
ProgIds
Then, your .inf file needs to contain the precise ProgIDs:
[Scripts]
SampleExport
[SampleExport]
SetupModule=SampleExport.dll
SetupProgID=SampleExport.Setup
SetupVersion=11.0
ReleaseModule=SampleExport.dll
ReleaseProgID=SampleExport
ReleaseVersion=11.0
SupportsNonImageFiles=True
SupportsKofaxPDF=True
Both your ReleaseScript.cs and ReleaseSetupScript.cs files need the correct attribute, for example:
[ProgId("SampleExport")]
public class ReleaseScript
If that all still does not work, please provide us with the detailed error message (to be found at CaptureSV\Logs).
I had to change the file format from UTF-8 to UTF-8 without BOM.
This worked for me.

Loaded SWF's wont preform their functions in air

Back for some help! So I am making an AIR application that loads SWF's into a container to be viewed by the user. However when I load the files into their containers, the SWF's that are loaded are unable to execute their own code. IE press an invisible button on the loaded SWF and it changes colour. I tried to google solutions for this since Security.allowDomain("*"); is throwing this error in flash. However from what I have read, AIR doesn't allow loaded swfs to execute code for some security reason but im not 100% sure on that either.
SecurityError: Error #3207: Application-sandbox content cannot access this feature.
at flash.system::Security$/allowDomain()
at BugFree()[D:\Desktop\BugFree\BugFree.as:72]
Without the Allow domain it throws this security error when attempting to click the invisible button.
*** Security Sandbox Violation ***
SecurityDomain 'file:///D:/Desktop/Rewritten Tester/TechDemoSwordNew.swf'
tried to access incompatible context 'app:/BugFree.swf'
*** Security Sandbox Violation ***
SecurityDomain 'file:///D:/Desktop/Rewritten Tester/TechDemoSwordNew.swf'
tried to access incompatible context 'app:/BugFree.swf'
SecurityError: Error #2047: Security sandbox violation: parent:
file:///D:/Desktop/Rewritten Tester/TechDemoSwordNew.swf cannot access
app:/BugFree.swf.
at flash.display::DisplayObject/get parent()
at TechDemoSwordNew_fla::Button_Play_21/onButtonPress()
This only shows in the Animate output bar. When I publish it, with application with runtime embeded, and open the exe it throws no errors but the invisible button still doesnt work.
Here is the code for the swf being loaded.
btnButton.addEventListener(MouseEvent.CLICK, onButtonPress, false, 0, true);
function onButtonPress(event:MouseEvent):void
{
MovieClip(parent).play();
}
stop();
This is timeline code within the button since that is how the game company who put my item in game did it. I originally submitted it with it all done in classes but that is besides the point. When the button is pressed the loaded SWF should play and then stop. But I get the above mentioned Sandbox violation.
The code used to load the SWF is below
public function WeaponLoad()
{
if(FileMenu.WeaponFileTxt.text != "")
{
LoadWeapon(FileMenu.WeaponFile.nativePath);
}
else if(FileMenu.WeaponFileTxt.text == "")
{
Character.mcChar.weapon.removeChildAt(0);
Character.mcChar.weaponOff.removeChildAt(0);
}
}
public function LoadWeapon(strFilePath: String)
{
WeaponLoader.contentLoaderInfo.addEventListener(Event.COMPLETE, CompleteWeaponLoad);
WeaponLoader.load(new URLRequest(strFilePath), new LoaderContext(false, new ApplicationDomain(ApplicationDomain.currentDomain)));
}
public function CompleteWeaponLoad(e: Event)
{
var WeaponClass: Class;
if (MiscMenu.WeaponSelect.MainClick.currentFrame != 3)
{
try
{
trace("WeaponOff");
WeaponClass = WeaponLoader.contentLoaderInfo.applicationDomain.getDefinition(FileMenu.WeaponLinkTxt.text) as Class;
this.Character.mcChar.weapon.removeChildAt(0);
this.Character.mcChar.weaponOff.removeChildAt(0);
this.Character.mcChar.weapon.addChild(new(WeaponClass)());
}
catch (err: Error)
{
trace("Either the weapon class doesnt exist or it is wrong");
this.Character.mcChar.weapon.removeChildAt(0);
this.Character.mcChar.weaponOff.removeChildAt(0);
}
}
else if (MiscMenu.WeaponSelect.MainClick.currentFrame == 3)
{
try
{
WeaponClass = WeaponLoader.contentLoaderInfo.applicationDomain.getDefinition(FileMenu.WeaponLinkTxt.text) as Class;
this.Character.mcChar.weapon.removeChildAt(0);
this.Character.mcChar.weaponOff.removeChildAt(0);
this.Character.mcChar.weapon.addChild(new(WeaponClass)());
this.Character.mcChar.weaponOff.addChild(new(WeaponClass)());
}
catch (err: Error)
{
trace("Either the weapon class doesnt exist or it is wrong");
this.Character.mcChar.weapon.removeChildAt(0);
this.Character.mcChar.weaponOff.removeChildAt(0);
}
}
}
Any help would be apreciated since I have no idea how to change any security sandbox settings within the publish settings since it is greyed out for me. Like I said I tried googling it but I couldn't seem to come up with any answers. Also worth noting is im a self taught novice and I do not know a lot of things in regards to AS3. I know my codes could be cleaner and I plan to clean it up and properly reduce memory consumption once I have the base program up and running. Thank you for the help!
It seems that you're not setting the application domain properly. Here is the code included in as3 documentation:
var loader:Loader = new Loader();
var url:URLRequest = new URLRequest("[file path].swf");
var loaderContext:LoaderContext = new LoaderContext(false, ApplicationDomain.currentDomain, null);
loader.load(url, loaderContext);
Use it in your LoadWeapon function.
In the meantime try not to use Uppercase letters for starting variables and method names. In ActionScript names starting with Uppercase represent Class names. It will widely improve readability of your code.
Can't you bundle your swfs with the AIR app and use File class to load them? If you want to use classes from the swfs, maybe consider making swc library?

Process CloseMainWindow() function doesn't work

I have a test method which requires Internet Explorer to be opened and closed numerous times during the test. I have been creating a process like this:
Process process = Process.Start(...);
And closing it like this:
process.CloseMainWindow();
However, I have found that I can only call this method once, otherwise I get the error message, "Process has exited, so the requested information is not available".
Once I have closed the process, I would then re-launch Internet Explorer. e.g.
process = Process.Start(...);
But this didn't work. I also tried nulling the Process variable before calling the Process.Start() method, but this didn't work.
I also tried using process.Kill(), but this caused problems too.
What is the correct way to do this?
UPDATE: Code
Process Browser;
[TestInitialize]
public void TestSetup()
{
Browser = TestBase.LaunchBrowser();
...
Browser.WaitForInputIdle();
Browser.CloseMainWindow();
Browser = null
Browser = Process.Start("IExplore.exe", ...);
}
[TestMethod]
public void MyTest()
{
// do things
Browser.Kill();
Browser = Process.Start("IExplore", "www.adifferentwebpage");
}
[TestCleanup]
public void TestCleanup
{
Browser.Kill();
}
I suggest to create another process without reusing the same variable.
Encapsulate your code inside a using statement to properly close and dispose the process variable
using(Process process = new Process())
{
// do you stuff
process.Start(.....);
process.CloseMainWindow();
}
Also remember that calling CloseMainWindow doesn't gurantees that the process will close. It only sends a request to close to the main window of the process. If the application ask for user confirmation before quitting it can refuse to quit.
I found a solution, but it only applies to those who have access to the Coded UI test DLL's (which I believe comes with Visual Studio Ultimate and Premium).
Therefore I will change the tags on the question.
If you create a Coded UI test project, these DLL references will already be there, but this using reference is what you need:
using Microsoft.VisualStudio.TestTools.UITesting;
To create a browser window:
BrowserWindow browser = BrowserWindow.Launch(new System.Uri("www.whatever.com"));
To close:
Browser.Close();
This worked no matter how many times I needed to relaunch the browser. This API also includes a multitude of other handy features like the ability to delete cookies, change the URL of the current browser, resize the window etc.

Data binding with plugins using MEF?

I have an application that has a class named: UploadItem. The application creates uploading tasks based on information it has, for example, an upload needs to be created to upload a file to sitex.com with this the application creates a new UploadItem and adds that to an ObservableCollection, the collection is bound to a listview.
Now comes the part that I cannot solve.. I decided to change the structure so that people can create their own plugins that can upload a file, the problem lies with the fact that the UploadItem class has properties such as:
string _PercentagedDone;
public string PercentageDone
{
get { return _PercentagedDone; }
set { _PercentagedDone = value + "%"; NotifyPropertyChanged("PercentageDone"); }
}
But the plugin controls on how a file is uploaded, so how would the plugin edit the PercentageDone property that is located in the UploadItem class? If there is no way to do such a thing, then is there another way to achieve the same, i.e. showing the progress on the main GUI?
You'll want to define an interface for the plugins. Something like:
public interface IUploadPlugin
{
Task<bool> Upload(IEnumerable<Stream> files);
int Progress { get; }
}
The plugins then need to implement this interface and export themselves:
[Export(typeof(IUploadPlugin))]
public class MyUploader : IUploadPlugin, INotifyPropertyChanged
{
// ...
}
Notice that this plugin implements INotifyPropertyChanged. This is an easy way to handle updating the progress. Fire PropertyChanged on the Progress property and then databind your ProgressBar control in the main view to this property. Make sure that you fire PropertyChanged on the UI thread.
Another option would be to fire a custom event when the property changes. You could handle this event in the main view logic and update the progress.
Notice that I'm using Task for the return. This allows the caller to wait until the upload task finishes. You could use a callback instead, but with the CTP of the next version of .NET, using Task<> will allow you to use the await keyword for your async programming. Check it out here and here.

Resources