C# + LibreOffice SDK - c#

I am developing a desktop application in .NET (C# + WPF) and my machine works correctly, I can make the LibreOffice call, open a file and customize the interface all through my .NET application, but in order to work, it is necessary the version of the SDK is the same as that of LibreOffice installed on the machine, and the architecture of the application should be the same as that of LibreOffice (32 or 64 bits).
To work the integration, I had to add in the references of my project the DLLs that comes along with the SDK:
cli_basetypes.dll
cli_cppuhelper.dll
cli_oootypes.dll
cli_ure.dll
cli_uretypes.dll
So at first all right, but my question is this: I developed the application using LibreOffice 6.1 along with the SDK of the same version and now I need the application to run on another machine with a lower version of LibreOffice, which I can not currently get, with the following error occurring:
System.IO.FileNotFoundException: Could not load file or assembly 'cli_cppuhelper.dll' or one of its dependencies. The specified module could not be found.
Is it possible to run the application on another machine with a different version of LibreOffice? How? Also, is it possible to avoid errors because the application is developed in 64bit and LibreOffice installed is 32bit for example?

After many attempts I was able to solve the problem.
It was necessary to override the AssemblyResolve event to fetch the LibreOffice DLLs from the GAC (C:\Windows\Microsoft.NET\assembly).
In addition the application must run with the same LibreOffice architecture installed so it was necessary to generate two executables, one 32bits and another 64bits (checking/unchecking the "32-bit Preferred" project property) so that the AssemblyResolve event finds the right DLL in GAC.
Another necessary change was necessary to set in the environment variable "UNO_PATH" that can be found in the Windows registry;
string unoPath = "";
RegistryKey hkcuView32 = RegistryKey.OpenBaseKey(Microsoft.Win32.RegistryHive.CurrentUser, RegistryView.Default);
RegistryKey hkcuUnoInstallPathKey = hkcuView32.OpenSubKey(#"SOFTWARE\LibreOffice\UNO\InstallPath", false);
if (hkcuUnoInstallPathKey != null && hkcuUnoInstallPathKey.ValueCount > 0)
{
unoPath = (string)hkcuUnoInstallPathKey.GetValue(hkcuUnoInstallPathKey.GetValueNames()[hkcuUnoInstallPathKey.ValueCount - 1]);
}
else
{
RegistryKey hklmView32 = RegistryKey.OpenBaseKey(RegistryHive.LocalMachine, RegistryView.Default);
RegistryKey hklmUnoInstallPathKey = hklmView32.OpenSubKey(#"SOFTWARE\LibreOffice\UNO\InstallPath", false);
if (hklmUnoInstallPathKey != null && hklmUnoInstallPathKey.ValueCount > 0)
{
unoPath = (string)hklmUnoInstallPathKey.GetValue(hklmUnoInstallPathKey.GetValueNames()[hklmUnoInstallPathKey.ValueCount - 1]);
}
}
Environment.SetEnvironmentVariable("UNO_PATH", unoPath, EnvironmentVariableTarget.Process);
Environment.SetEnvironmentVariable("PATH", Environment.GetEnvironmentVariable("PATH") + #";" + unoPath, EnvironmentVariableTarget.Process);
After this steps, my application worked perfectly!

Related

pythonnet Embedding Python in .net example failing to load module

I'm trying to run the Embedding Python in .NET example from https://github.com/pythonnet/pythonnet. I've followed troubleshooting articles to set the proper %PYTHONPATH% and %PYTHONHOME% to my anaconda environment in the program base directory.
After activating my anaconda environment, I have successfully imported sys, and imp as a test, and also sucessfully used PythonEngine.RunSimpleString(), but the numpy example fails with Python.Runtime.PythonException: ImportError : No module named 'numpy'
importing numpy from python in this environment was successful, but this and other packages fail to import in pythonnet.
Pythonnet version: 2.3 x64 (installed using conda install -c pythonnet pythonnet)
Python version: Python 3.5 x64 (anaconda)
Operating System: Windows 10
The following code produces the error:
static void Main(string[] args)
{
string envPythonHome = AppDomain.CurrentDomain.BaseDirectory + "cntk-py35";
string envPythonLib = envPythonHome + #"\Lib";
Environment.SetEnvironmentVariable("PYTHONHOME", envPythonHome, EnvironmentVariableTarget.Process);
Environment.SetEnvironmentVariable("PATH", envPythonHome + ";" + Environment.GetEnvironmentVariable("PATH", EnvironmentVariableTarget.Machine), EnvironmentVariableTarget.Process);
Environment.SetEnvironmentVariable("PYTHONPATH", envPythonLib, EnvironmentVariableTarget.Process);
PythonEngine.PythonHome = envPythonHome;
PythonEngine.PythonPath = Environment.GetEnvironmentVariable("PYTHONPATH");
using (Py.GIL())
{
dynamic np = Py.Import("numpy");
Console.WriteLine(np.cos(np.pi * 2));
dynamic sin = np.sin;
Console.WriteLine(sin(5));
double c = np.cos(5) + sin(5);
Console.WriteLine(c);
dynamic a = np.array(new List<float> { 1, 2, 3 });
Console.WriteLine(a.dtype);
dynamic b = np.array(new List<float> { 6, 5, 4 }, dtype: np.int32);
Console.WriteLine(b.dtype);
Console.WriteLine(a * b);
Console.ReadKey();
}
}
It seems that any package under site-packages in my environment similarly fail. Adding to %PATH% did not work. Is there a way to get pythonnet to recognize and load these modules?
Setting up your python environment in .NET is a bit cumbersome.This issue is not well detailed on pythonnet website or most of suggested solutions I have found on the internet did not work for my computer. The reason is that every computer may have a different python setup environment (depending how you have installed python and the libraries). It took me a while as well but finally I have succeeded to call python modules and .py scripts from .NET. Here is what I did.
Pythonnet version: 2.4.0 x64 (installed using pip install # Anaconda CMD prompt)
Python version: Python 3.7 x64 (Anaconda)
Operating System: Windows 10
Keep in mind that everyone has a different Python environment, that is why you have to configure your environment first (in your VS project).
First, we need to assign "PATH", "PYTHONHOME" and "PYTHONPATH" variables.
in C# use:
string pythonPath1 = #"C:\Users\<your username>\Anaconda3";
string pythonPath2 = #"C:\Users\<your username>\Anaconda3\lib\site-packages";
Environment.SetEnvironmentVariable("PATH", pythonPath1, EnvironmentVariableTarget.Process);
Environment.SetEnvironmentVariable("PYTHONHOME", pythonPath1, EnvironmentVariableTarget.Process);
Environment.SetEnvironmentVariable("PYTHONPATH", pythonPath2, EnvironmentVariableTarget.Process);
I have used Anaconda to install python runtime and packages. Note that default Anaconda installation is under C:\Users(your username assigned in your computer)\Anaconda3. (You can find yours using code by (How can I get the current user directory?). If you did not use Anaconda, you need to locate the directory where python packages are installed on your computer.
1-C:\Users\\Anaconda3 directory must have your version of python DLL (i.e.python37.dll).
2-C:\Users\\Anaconda3\lib\site-packages has the "modules" (i.e. python frameworks like 'numpy').
3-You must reference python runtime in your project (Python.Runtime.dll).(use Windows File Explorer to find the file. If you use Anaconda the runtime is under C:\Users\\Anaconda3 directory).
4-Add following on top of your code:
using Python.Runtime;
5-In VS Solution Explorer right click on your project and select 'Properties'
and make sure to set 'Platform Target' (either x64 or x86)
6-After doing all this, if you can NOT run some of the 'modules' and receive a "Can not load module" or "can not find module" exception message, then follow the instruction here (https://github.com/microsoft/vscode-python/issues/9218)
Usually, uninstalling/re-installing the module will resolve the issue by updating the version. (i.e. pip uninstall numpy/pip install numpy).
NOTE: The code still works, even if you do not set PYTHONPATH variable above. PYTHONPATH variable is used, when you need to call a custom .py script, where you identify the directory where your file resides. A descriptive example can be found at https://stackoverflow.com/a/57910578/7675537
UPDATE: I have realized that one easy way to configure your Python Environment is using Visual Studio (I use VS 2017 Community version). Just go to Python in Visual Studio and go through the example. In VS under 'Python Environments' you can observe all the setups you have in your computer. I had problems to run .py scripts, like not being able to use 'import matplotlib.pyplot' and spent several hours reading articles on the internet but could not find a solution. Finally I switched my environment to 'C:\Users\\AppData\Local\Programs\Python\Python37\' and installed all the missing packages from visual studio's list (of suggestions) and it worked. I think calling Anaconda environment from .NET (via pythonnet or else) has problems. I would suggest not to use your Anaconda python environment if you make .NET calls to python. I use:
private static string pythonPath1 = #"C:\Users\<your name>\AppData\Local\Programs\Python\Python37";
static void Main(string[] args)
{
Test();
}
private static void Test()
{
string pathToPython = pythonPath1;
string path = pathToPython + ";" +
Environment.GetEnvironmentVariable("PATH", EnvironmentVariableTarget.Machine);
Environment.SetEnvironmentVariable("PATH", path, EnvironmentVariableTarget.Process);
Environment.SetEnvironmentVariable("PYTHONHOME", pathToPython, EnvironmentVariableTarget.Process);
var lib = new[]
{
#"C:\Users\<your name>\<your python code is here>",
Path.Combine(pathToPython, "Lib"),
Path.Combine(pathToPython, "DLLs")
};
string paths = string.Join("; ", lib);
Environment.SetEnvironmentVariable("PYTHONPATH", paths, EnvironmentVariableTarget.Process);
using (Py.GIL()) //Initialize the Python engine and acquire the interpreter lock
{
try
{
// import your script into the process
dynamic sampleModule = Py.Import("yourpythoncode");
}
catch (PythonException error)
{
Console.WriteLine("Error occured: ", error.Message);
}
}
}
I was able to import the modules by adding Lib/site-packages to the PYTHONPATH variable (rather than the PATH) which adds the folder to sys.path. It was necessary for any other python libraries and custom python code to add the corresponding folder to PYTHONPATH.

GhostscriptLibraryNotInstalledException running under 32-bit process requires native library

Using nuget in Visual Studio 2013, I installed Ghostscript.NET into my project on my Windows x64 PC.
Just to make sure I wasn't crazy, I checked it:
PM> Install-Package Ghostscript.NET
'Ghostscript.NET 1.2.0' already installed.
Project already has a reference to 'Ghostscript.NET 1.2.0'.
PM>
The project is used by multiple developers. It targets Any CPU, and needs to remain that way.
Here is my code:
public static void GhostscriptNetProcess(String fileName, String outputPath)
{
var version = GhostscriptVersionInfo.GetLastInstalledVersion();
var source = (fileName.IndexOf(' ') == -1) ? fileName : String.Format("\"{0}\"", fileName);
var output_file = (outputPath.IndexOf(' ') == -1) ? outputPath : String.Format("\"{0}\"", outputPath);
var gsArgs = new List<String>();
gsArgs.Add("-q");
gsArgs.Add("-dNOPAUSE");
gsArgs.Add("-dNOPROMPT");
gsArgs.Add("-sDEVICE=pdfwrite");
gsArgs.Add(String.Format(#"-sOutputFile={0}", output_file));
gsArgs.Add("-f");
gsArgs.Add(source);
var processor = new GhostscriptProcessor(version, false);
processor.Process(gsArgs.ToArray());
}
Whenever I attempt to debug the application, I get the following error message:
GhostscriptLibraryNotInstalledException was unhandled
An unhandled exception of type 'Ghostscript.NET.GhostscriptLibraryNotInstalledException' occurred in Ghostscript.NET.dll
Additional information: This managed library is running under 32-bit process and requires 32-bit Ghostscript native library installation on this machine! To download proper Ghostscript native library please visit: http://www.ghostscript.com/download/gsdnld.html
Looking up the Ghostscript.NET.GhostscriptLibraryNotInstalledException did not provide any useful information, though this post on CodeProject indicated that the debugger is running in 32-bit mode whereas I have the 64-bit version installed.
That's all well and good know, but how do I go about testing the new code I wrote that uses Ghostscript?
If you are testing with MS Test you have to set the processor architecture in which the tests are run, because Ghostscript.Net verifies the process architecture (Environment.Is64BitProcess) to search for the ghostscript installation in the registry.
In Menu > Test > Test Settings > Default Processor Architecture > X64.
Have you actually installed Ghostscript ?
Ghostscript.NET is merely a .NET interface to Ghostscript, it looks to me like the message:
"This managed library is running under 32-bit process and requires 32-bit Ghostscript native library installation on this machine! To download proper Ghostscript native library please visit: http://www.ghostscript.com/download/gsdnld.html"
is trying to tell you that you don;t have a 32-bit version of Ghostscript installed. It even tells you where to go to download a copy.
So have you installed Ghostscript ? Have you installed the 32-bit version of Ghostscript ?

Registry and Wow6432Node on C#

I´m trying to access a path in the registry inside Wow6432Node, to write a value inside it, but it is not working. I tried with different codes, but it´s still not working. I am running it as "Any CPU" on a x64 bit Windows 10. I suspect it has something to do with the difference on the registry between x86 and x64. Am I wrong?
if (rv3.Checked == true)
{
string line2 = File.ReadLines(AppDomain.CurrentDomain.BaseDirectory + "simulators.txt").Skip(3).Take(1).First();
MessageBox.Show(line2);
if (System.IO.Directory.Exists(line2))
{
var baseReg = RegistryKey.OpenBaseKey(RegistryHive.LocalMachine, RegistryView.Registry64);
var Key = baseReg.OpenSubKey(#"SOFTWARE\Wow6432Node\Microsoft\Microsoft Games\flight simulator\10.0\");
if (Key != null)
{
RegistryKey key2 = baseReg.OpenSubKey(#"SOFTWARE\Wow6432Node\Microsoft\Microsoft Games\flight simulator\10.0\");
key2.SetValue("SetupPath", line2);
key2.Close();
}
}
}
Kind regards!
I ran into similar issues when working with the registry, and I suspect you're a victim of "virtualization".
On a machine with User Account Control (UAC) you aren't strictly denied permission to write to the registry, but the calls get virtualised. See if the values you are expected to see are turning up at HKEY_USERS\<User SID>_Classes\VirtualStore\Machine\Software\.
The solution is to add an application manifest file to the solution, and set requestedExecutionLevel level="requireAdministrator", which means whenever you run the application on a machine with UAC it will ask "Are you sure?". You also need to ensure the project properties specify the manifest to use.
I then ran into a second problem, which is that when you're debugging through Visual Studio, it will run with VS execution level, not those specified in the manifest (see here). The easiest solution is to set VS to run as Administrator in the shortcut properties.

File exists in Windows Explorer and notepad, but is not accessable in my program

Why does the following problem happen?
Scenario:
Make sure that IIS is installed
Execute "notepad
%WINDIR%\System32\inetsrv\config\applicationHost.config" using admin
account
Actual Result: the file is successfully opened in notepad
Execute the following code in admin account's context:
string filePath = #"%WINDIR%\System32\inetsrv\config\applicationHost.config";
Console.WriteLine(File.Exists(Environment.ExpandEnvironmentVariables(filePath)));
Actual Result: False
Expected Result: True
The problem is if you are running a 32-bit application on a 64-bit OS, the .Net framework automatically redirects the request from %WINDIR%\System32 to %WINDIR%\SysWOW64.
If you change your project to target 64-bit, this will solve your problem.
You can also resolve the problem by changing System32 to sysnative, but only if you leave the application as a 32-bit app:
string filePath = #"%WINDIR%\sysnative\inetsrv\config\applicationHost.config";
This might be due to file system redirection. AFAIK t happens either for 32/64 bit mismatch or in case of low-privilege (UAC) processes.
I know of now way of disabling that behavior using managed APIs. You need to use http://msdn.microsoft.com/en-us/library/windows/desktop/aa365743(v=vs.85).aspx and/or be a high privilege process.
If you change your project to target 64-bit, this is likely to solve your problem.
I can't reproduce your result. When I run this from an administrator command line prompt, I get exists = True.
string s = #"%WINDIR%/System32\inetsrv\config\applicationHost.config";
bool exists = File.Exists(Environment.ExpandEnvironmentVariables(s));
Console.WriteLine("exists = {0}", exists);
I'm running Windows Server 2008, 64-bit. .NET 4.0.

Using C# How to detect if Windows Installer 4.5 is Installed

I am trying to figure out the most efficient way to determine if Windows Installer 4.5 is installed on a machine.
I have a 2.0 application (cannot convert at this time to 3.5) and we are upgrading from MSDE to SQL 2008 Express. One of the requirements of 2008 Express is that Windows Installer 4.5 is installed on the machine. This application is deployed globally to machines both on and off of an internal network.
I would prefer to run a batch file or C# code to determine the installer version.
Please let me know your recommended methods and provide some code (or links to code).
Thanks!
You can read the file version of the msi.dll library in the system directory:
using System.Diagnostics;
using System.IO;
public bool IsWindowsInstaller45Installed()
{
FileVersionInfo info;
string fileName = Path.Combine(Environment.SystemDirectory, "msi.dll");
try {
info = FileVersionInfo.GetVersionInfo(fileName);
} catch (FileNotFoundException) {
return false;
}
return (info.FileMajorPart > 4
|| info.FileMajorPart == 4 && info.FileMinorPart >= 5);
}
Check the version of the MSI.DLL file that's in your System32 directory.
You should be able to use GetFileVersionInfo or GetFileVersionInfoEx to get out the version number.
This MSDN article has some sample code: Unsafe Code Tutorial
Like Ho1 said, you can go by the version of MSI.dll in System32 but you don't need to P/Invoke you can use the FileVersionInfo class found in System.Diagnostics.

Categories

Resources