Main context
We're actually trying to get a multi-threading version of Ghostscript x64 DLL, to make use of it through Ghostscript .NET. This component is supposed to "allow runing multiple Ghostscript instances simultaneously within a single process", but, as we have checked in our project, works fine until concurrent requests are made to the application. Same behavior can be replicated lauching same method using Tasks. The error description that raises in both cases, just when a call to the process is made until the last is being executed, is:
An error occured when call to 'gsapi_new_instance' is made: -100
Even it does no seem to be related with .NET directly, I will post a sample of our C# method code, just for contextualize.
// Define switches...
string[] switchesArray = switches.ToArray();
using (GhostscriptProcessor procesador = new GhostscriptProcessor())
{
try
{
procesador.StartProcessing(switchesArray, null);
byte[] destinationFile = System.IO.File.ReadAllBytes(destinationPath);
return destinationFile;
}
catch (Exception ex)
{
throw ex;
}
finally
{
System.IO.File.Delete(sourceFile);
}
}
THREADSAFE solution
Starting our investigation, we found this KenS's answer on this post, indicating that Ghostscript DLL must be generated with GS_THREADSAFE compiler definition.
To clarify, as we make use of Ghostscript 9.52 x64 to generate our PDFs, we need this x64 DLL compiled for Release configuration. After trying to compile Ghostscript sources on Windows 10 x64 machine, using Visual Studio Community 2017 and Visual Studio Community 2019, we finally managed to build and generate all items (only with VS Community 2019) without GS_THREADSAFE parameter, just to confirm that compilation is fine, and we check that the DLLs and executables are working. For this process we took in mind all we found in Ghostscript official documentation.
As we have no other guide to include this GS_THREADSAFE parameter, we followed the instructions given in this solution, including XCFLAGS="-DGS_THREADSAFE=1" on nmake build commands, usign this sentence for Rebuild all option:
cd .. && nmake -f psi\msvc32.mak WIN64= SBR=1 DEVSTUDIO= XCFLAGS=-DGS_THREADSAFE=1 && nmake -f psi\msvc32.mak WIN64= DEVSTUDIO= XCFLAGS=-DGS_THREADSAFE=1 bsc
This approach, rises an error during build:
Error LNK2019 unresolved external symbol errprintf_nomem referenced in
function gs_log_error File \mkromfs.obj 1
As it seems, the file mkromfs.c has a method called errprintf_nomem, which can't be found when GS_THREADSAFE is set.
Questions
1 - Is there any public release of Ghostscript that include x64 DLLs compiled to be THREADSAFE?
And, if not (that's what I'm guessing...)
2 - Is it possible to get this DLL to be THREADSAFE without changing the source code?
3- Could anyone provide, please, a step by step guide or walkthrough to build a x64 Ghostscript DLL using GS_THREADSAFE using Visual Studio (or even any other possible alternative) over Windows 10 x64?
4 - A few posts talk about people achive to manage multithreading using Ghostscript .NET. I assume this examples are all using a GS_THREADSAFE DLL... Is any other workaround we have passed?
Thank a lot in advance.
To summarize all this questions, and as a guide for future developers having this same trouble, these are the answers we've found until now:
AS #KenS mentions in his reply: "No, the Ghostscript developers don't actually build thread-safe versions of the binaries."
At this very moment, clearly not, as it has been reported on this opened bug.
As it seems to be a matter of commercial licensing support, we avoid comment on this point anymore.
Thanks again to #HABJAN. I absolutely take back what I've stated on my question, as it is possible to have Ghostscript .NET working on multi-threading scenarios. Below comes the solution we applied, in case it could be useful for someone.
Based on HABJAN example, what we have done to achieve this was to create a custom class to capture Ghostscript logging:
protected class ConsoleStdIO : Ghostscript.NET.GhostscriptStdIO
{
public ConsoleStdIO(bool handleStdIn, bool handleStdOut, bool handleStdErr) : base(handleStdIn, handleStdOut, handleStdErr)
{
}
public override void StdIn(out string input, int count)
{
char[] userInput = new char[count];
Console.In.ReadBlock(userInput, 0, count);
input = new string(userInput);
}
public override void StdOut(string output)
{
//log
}
public override void StdError(string error)
{
//log
}
}
For our previous method, we simple include a call to this class and this avoids errors when multiple tasks are executed at the same time:
// Define switches...
string[] switchesArray = switches.ToArray();
using (GhostscriptProcessor procesador = new GhostscriptProcessor())
{
try
{
procesador.StartProcessing(switchesArray, new ConsoleStdIO(true, true, true));
byte[] destinationFile = System.IO.File.ReadAllBytes(destinationPath);
return destinationFile;
}
catch (Exception ex)
{
throw ex;
}
finally
{
System.IO.File.Delete(sourceFile);
}
}
Well, it seems to me that you are asking here for technical support.
You clearly want to use Ghostscript in a commercial undertaking, indeed one might reasonably say you want an enterprise version of Ghostscript. Presumably you don't want to alter the source in order to permit you to use an open source license, because you don't want to pay for a commercial license.
With that in mind the answers to your questions are:
No, the Ghostscript developers don't actually build thread-safe versions of the binaries.
Currently, no. That's probably an oversight.
That would be a technical support question, there's no guarantee of technical support to free users, it's the one of the few areas of leverage for dual license vendors to persuade people to take up a commercial license. So I hope you will understand that I'm not going to provide that.
as far as I can see, no.
I have a cross-platform build. On a *nix platform using GCC, I use the __attribute__((warn_unused_result)) to notify the consumer of my API if a return value is not checked. I assumed that _Check_return does the same thing on MSVC, but it doesn't appear to be working the way I expect.
The following code does not produce a warning as I expect. Warnings are set to /Wall.
_Check_return_ _Must_inspect_result_ int foo()
{
return 100;
}
int main()
{
foo();
return 0;
}
Code compiles without warnings. What am I doing wrong (or what should I be using to generate warnings for unchecked return codes)?
SAL annotations like _Check_return_ and _Must_inspect_result_ are only checked during code analysis builds (either by starting a code analysis build in the IDE or by building with the /analyze flag on the command line).
See "Understanding SAL" on MSDN for more information.
I am using Visual Studio 2010 and ReSharper 8.2.1 with extension ReSharper.ExternalAnnotations 8.2.1001. Despite of the assertion in the following code, ReSharper warns about a possible System.NullReferenceException. It even suggests adding an assertion as a fix.
static int Foo(string s)
{
Debug.Assert(s != null);
return s.Length; // Possible 'System.NullReferenceException'
}
I have unzipped C:\Program Files (x86)\JetBrains\ReSharper\v8.2\Bin\packages\ReSharper.ExternalAnnotations.8.2.1000.4556.nupkg and found the expected external annotation that should tell ReSharper to "understand" the assertion.
What could be wrong here?
Edit: It is a debug build.
If you are compiling a Release build, I believe R# will ignore the conditional call to Debug.Assert.
With a skeleton project with FirstView from HotTuna package, and with Build linker behavior set to "Link all assemblies", I get the following error:
System.MissingMethodException: Default constructor not found for type Cirrious.CrossCore.IoC.MvxPropertyInjector
Using NuGet package v3.1.1 for all MvvmCross (4 packages)
LinkerPleaseInclude file does have the line
[MonoTouch.Foundation.Preserve(AllMembers = true)]
Using the latest stable build:
On PC:
Xamarin for VS 1.12.278
Xamarin.iOS 1.12.278
Mac:
Xamarin.iOS 7.2.2.2
Of course with Linker behavior of SDK only, it runs fine. Any suggestions anyone?
Solved; So, with the basic project, there were three consecutive errors in the following order:
System.MissingMethodException: Default constructor not found for type Cirrious.CrossCore.IoC.MvxPropertyInjector
can be resolved either by --linkskip=Cirrious.Core (ugly), or by including the following in LinkerPleaseInclude.cs
public void Include(MvxPropertyInjector injector){
injector = new MvxPropertyInjector ();
}
Next error is:
Cirrious.CrossCore.Exceptions.MvxException: Failed to construct and initialize ViewModel for type {0} from locator MvxDefaultViewModelLocator - check MvxTrace for more information
This one is difficult; Simple fix is to ofcourse to do a --linkskip=portableLibrary, or to crate an instance of the ViewModel somewhere (perhaps in LinkerPleaseInclude.cs); problem with the second approach at-least in my case is, most of my VM doesn't have a parameter less constructor, and obviously using IOC in this case wouldn't help.
Final Error:
System.ArgumentNullException: missing source event info in MvxWeakEventSubscription
Parameter name: sourceEventInfo
Either use --linkskip=System (ugly), or add the following to LinkerPleaseInclude.cs
public void Include(INotifyPropertyChanged changed)
{
changed.PropertyChanged += (sender, e) => {
var test = e.PropertyName;
};
}
This was enough for my basic project to run with LinkAllAssemblies, Using LLVM optimizer, and Use SGen collector.
Hope this will help anyone looking for a solution.
I hit this when my XCode was out of sync with the latest Xamarin on my Mac. Upgrading XCode to the latest resolved the problem.
I'm using VS2012 and T4 templates and assemblies are supposed to be shadow copied, meaning that you can reference an assembly in a template and then recompile that assembly. But this simply doesn't work for me. When I try it, when I try to rebuild the assembly, I get errors like:
Unable to copy file "obj\Debug\xxx.dll" to "..\bin\xxx.dll".
The process cannot access the file '..\bin\xxx.dll' because it is being used by another process.
The only way around it is to restart Visual Studio, and this is so tedious that I'm ready to abandon T4 entirely. What could I be doing wrong?
So this isn't really an answer yet but hopefully we get there
Test ran the following in VS2013 (I realize you run VS2012)
<## assembly name = "$(SolutionDir)\TestProj\bin\Debug\TestProj.dll"#>
<## import namespace = "TestProj"#>
namespace ConsoleApplication1
{
class <#=Testing.Name#>
{
}
}
The TestProj contains the Testing class
namespace TestProj
{
public static class Testing
{
public static string Name
{
get { return "Tester" ;}
}
}
}
This did work very well in VS2013 and as far as I remember this worked in VS2012 as well.I will try to install VS2012 on one of my machines but do you mind testing this simple sample on your installation to validate it's not something in your solution that holds the dll?
In case you are interested in the project file you can find it here:
https://github.com/mrange/CodeStack/tree/master/q21118821
I work around similar issue. T4 design time template is processed in different App domain under the same process of visual studio. When rebuild the solution Visual Studio tries to replace the referenced DLL, and it cannot replace it because it is still in use.
I work around this issue by deleting the AppDomain in which T4 template is processed. See msdn