What a great idea (the plugin)! Unfortunately I've found a couple of usage issues however (sorry!) so though I'd post them here in the hope that you can perhaps correct them!
I'm running build 3.5.8 of PDN and 1.0.3.7 of PSFilterPdn.dll on Windows 7 SP1 x64.
1) Shim crashes when certain plugins are executed
Sinedots II is a free PlugIn available here (in fact all the plugins available from this site exhibit the same problem).
As it's the shim that crashes I put it under a debugger with Reflector Pro so 'source' was available.
The callstack of the crash is:
PSFilterShim.exe!PSFilterLoad.PSApi.LoadPsFilter.OpenReadDescriptorProc(ref System.IntPtr param0, System.IntPtr param1) Line 1612 + 0x6 bytes C#
[Native to Managed Transition]
[Managed to Native Transition]
PSFilterShim.exe!PSFilterLoad.PSApi.LoadPsFilter.plugin_apply(PSFilterLoad.PSApi.PluginData pdata) Line 1652 C#
PSFilterShim.exe!PSFilterLoad.PSApi.LoadPsFilter.RunPlugin(PSFilterLoad.PSApi.PluginData pdata, bool showAbout) Line 2107 + 0x9 bytes C#
PSFilterShim.exe!PSFilterShim.Program.RunFilterThread(object argsObj) Line 159 + 0x17 bytes C#
mscorlib.dll!System.Threading.ThreadHelper.ThreadStart_Context(object state) + 0x83 bytes
mscorlib.dll!System.Threading.ExecutionContext.Run(System.Threading.ExecutionContext executionContext, System.Threading.ContextCallback callback, object state) + 0x6f bytes
mscorlib.dll!System.Threading.ThreadHelper.ThreadStart(object obj) + 0x4a bytes
The offending bit of code is:
private static IntPtr OpenReadDescriptorProc(ref IntPtr param0, IntPtr param1)
...
Label_005D:
if (aeteDict.Count > 0) <--- HERE
{
return readDescriptorPtr.AddrOfPinnedObject();
}
return IntPtr.Zero;
The variable aeteDict is null and accessing the Count property obviously causes a crash. Looking back through the stack, I see the following logic:
public bool RunPlugin(PSFilterLoad.PSApi.PluginData pdata, bool showAbout)
...
if (pdata.aete != null)
{
aete = pdata.aete;
if (!isRepeatEffect)
{
aeteDict = new Dictionary<uint, AETEValue>();
}
}
It would seem that pdata.aete was null when this was executed so the dictionary object is never assigned a value. Personally speaking I'd always ensure collections are created and have no content rather than rely on logic to check for null.
2a) PDN crashes when Run Filter is pressed whilst current operation is still running
A good scenario to reproduce the problem is to perform the Ghost effect [from Flaiming Pear's freebies pack] on an image. As it takes a while to complete it's possible to click the "Run Filter" button again. This will cause PDN to crash and the exception shows contention on the temporary image file:
Exception details:
System.IO.IOException: The process cannot access the file 'D:\Documents\Adam\Paint.NET User Files\proxysourceimg.png' because it is being used by another process.
at System.IO.__Error.WinIOError(Int32 errorCode, String maybeFullPath)
at System.IO.FileStream.Init(String path, FileMode mode, FileAccess access, Int32 rights, Boolean useRights, FileShare share, Int32 bufferSize, FileOptions options, SECURITY_ATTRIBUTES secAttrs, String msgPath, Boolean bFromProxy)
at System.IO.FileStream..ctor(String path, FileMode mode, FileAccess access, FileShare share, Int32 bufferSize, FileOptions options, String msgPath, Boolean bFromProxy)
at System.IO.FileStream..ctor(String path, FileMode mode, FileAccess access, FileShare share)
at PSFilterPdn.PsFilterPdnConfigDialog.Run32BitFilterProxy(EffectEnvironmentParameters eep, PluginData data)
at System.Threading.ExecutionContext.runTryCode(Object userData)
at System.Runtime.CompilerServices.RuntimeHelpers.ExecuteCodeWithGuaranteedCleanup(TryCode code, CleanupCode backoutCode, Object userData)
at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)
at System.Threading.ThreadHelper.ThreadStart()
My personal feeling (again, I apologise!) is that if this is simply a "work" file then one should be allocated using the Path.GetTempFileName method. That obviously does not correct the actual error (being able to invoke the effect whilst it's already processing a request) which can hopefully be covered with some form of access control around the Run Filter button.
2b) Shim process does not always shutdown
I've not worked out how/why but it's certainly possible to leave the process running - I have on a number of occasions. If I find a reproduceable scenario I'll let you know.
Q - Do you plan to release the source code to this plugin? Perhaps it could be hosted in a repository provided by Codeplex or similar? Might allow specific plugin issues to be fixed by those it affects rather than rely on yourself - of course you may want it that way!
Hopefully the above helps! Thanks again for putting the PlugIn together!