DriverPackagePreinstall to work on 64 bit (compiled to 32 bit) - c#

Is there a way I can compile an application which calls the DriverPackagePreinstall() (using Pinvoke) in such a way that it can work on 64-bit devices (Windows 7) even though it's targeted to 32bit?
The reason being it will be run as part of an installer of a much bigger application (using Windows Installer Project), which will target 32 bit but must run on a 64 bit platform also.
Here is my code:
using System;
using System.Linq;
using System.Runtime.InteropServices;
namespace MyDriver
{
class Program
{
static void Main(string[] args)
{
if (args.Count() == 0)
{
Console.WriteLine("Please specify filename!");
return;
}
int result= DriverPackagePreinstall(args[0], 0);
if (result == 0)
{
Console.WriteLine("Success");
} else {
Console.WriteLine("Error: 0x{0}", result.ToString("X8"));
}
}
[DllImport("DIFxAPI.dll", CharSet = CharSet.Auto, SetLastError = true)]
public static extern Int32 DriverPackagePreinstall(
[MarshalAs(UnmanagedType.LPTStr)] string DriverPackageInfPath,
Int32 Flags);
}
}
}
If I build this targeting x86, and try to run on a 64-bit machine, I get error E0000235 (ERROR_IN_WOW64). This error goes away if I build targeting x64.
Now I don't mind compiling it twice and letting the installer decide which to install based on the platform it's being installed to. However, if I try to build the installer while including the 64-bit version I get the error,
263 File 'MyDriver.x64.exe' targeting 'AMD64' is not compatible with the project's target platform 'x86'
Alternatively a way of getting the Installer to overlook this error at build time (and run it anyway when the project is installing) would be good.

I worked around this by adding both the 64-bit and 32-bit versions of the application to a self-extracting zip-file together with a batch file which decides which one to execute.
The self-extractor is a 32-bit exe so as long no one tells Visual Studio that it contains a 64-bit one, it works.

Related

Excel 2016 VSTO Addin With Native Code DLL

Creating an Excel addin using an SDK from a 3rd party. The SDK contains a native code DLL (in both 32 and 64 bit versions). My addin code is in C# and it appears that addins only run if compiled under "AnyCPU" option.
When I attempt to run the app I get "An attempt was made to load a program with an incorrect format. (Exception from HRESULT: 0x8007000B)" which usually means a 64/32 mismatch, and the error is from attempting to load the 3rd party native code DLL.
My question is: are my assumptions correct about AnyCPU and is there a way to run native code DLL's from an addin compiled under AnyCPU? Thanks!
before .net 4.5 the AnyCPU depends on your current compile machine.
if your machine is 32bit CPU, AnyCPU will compile your program as 32bit program. if it's 64bit CPU, i t will compile as 64bits.
after .net 4.5, the AnyCPU changed:
If the process runs on a 32-bit Windows system, it runs as a 32-bit
process. IL is compiled to x86 machine code.
If the process runs on
a 64-bit Windows system, it runs as a 32-bit process. IL is compiled
to x86 machine code.
If the process runs on an ARM Windows system,
it runs as a 32-bit process. IL is compiled to ARM machine code.
If you want your program can run both 32bit and 64bit cpu, you should link your native code DLL with 32 bit version, otherwise you need to compile them in separate CPUs
Yes it is possible, you can create some wrappers functions that redirect the call to the native dll depending on the current architecture , example :
[DllImport("bin32\\Native86Dll", EntryPoint = "MyFunc", CharSet = CharSet.Ansi, ExactSpelling = true)]
public static extern int MyFunc_32(string sCommand);
[DllImport("bin64\\Native64Dll", EntryPoint = "MyFunc", CharSet = CharSet.Ansi, ExactSpelling = true)]
public static extern int MyFunc_64(string sCommand);
public static int MyFunc(string sCommand )
{
return System.Environment.Is64BitProcess ? MyFunc_64(sCommand) : MyFunc_32(sCommand);
}

"Could not find a part of the path," on path that does exist

I am attempting to update the lock screen background like this:
string filename = #"C:\app\screenshot.temp.jpg";
string finalLocation = #"C:\Windows\System32\oobe\info\backgrounds\backgroundDefault.jpg";
File.Move(filename, finalLocation);
Unfortunately this throws a System.IO.DirectoryNotFoundException exception:
An unhandled exception of type 'System.IO.DirectoryNotFoundException' occurred in mscorlib.dll
Additional information: Could not find a part of the path.
However when i browse to C:\Windows\System32\oobe\info\backgrounds in Windows Explorer, CMD, or Powershell it does exist. I also have the security to write, rename, and delete files in that location (and the C# process is running in my context). What is going on?
If you've encountered this, I am guessing you're executing the process on a 64 bit version of Windows.
Background:
On Windows 32 bit, there is a single System32 folder called "System32" that stores all 32 bit DLLs. On Windows 64 bit, there are two "System32" folders one still called System32 and another called SysWOW64.
These two folders store the opposite of what their names imply:
System32 stores 64 bit DLLs.
SysWOW64 stores 32 bit DLLs.
SysWOW64 stands for "Windows 32-bit on Windows 64-bit." So it is a folder that exists for backwards compatibility with 32 bit for 32 bit processes.
Why this breaks things?
Microsoft are obsessed with backwards compatibility, so when they added 32 bit emulation on 64 bit Windows, they wanted to make the bitness of the system invisible to the 32 bit processes running, and they introduced a bunch of compatibility shims (fixes).
One of these shims redirects IO requests for %WINDIR%\System32 to %WINDIR%\SysWOW64 for processes running in 32 bit mode only.
So when you request a move from:
C:\Windows\System32\oobe\info\backgrounds\backgroundDefault.jpg
Windows may actually instead request the move from:
C:\Windows\SysWOW64\oobe\info\backgrounds\backgroundDefault.jpg
Which does not exist. Thus explaining the error you're seeing.
The Fix
The easiest fix is to change your program to build as a 64 bit process. You can do this by:
Right Click on the Project -> Properties -> Build [Tab] -> Platform target -> x64
Now when you run, requests against %WINDIR%\System32 should actually hit %WINDIR%\System32 for real.
Alternatively if you need to run your process in 32 bit mode (e.g. due to library compatibility) you can ask Windows to disable the shim like this:
[DllImport("kernel32.dll", SetLastError = true)]
public static extern bool Wow64DisableWow64FsRedirection(ref IntPtr ptr);
private static void Main(string[] args)
{
IntPtr ptr = new IntPtr();
bool isWow64FsRedirectionDisabled = Wow64DisableWow64FsRedirection(ref ptr);
}
In either case requests should be handled more literally by the operating system, and you can update the lock screen background (or any other operation in System32).

Click One Report Viewer Error

I set
Microsoft System CLR Types for sql server 2012 x86
Microsoft System CLR Types for sql server 2012 x64
as prerequisites upon Click Once deployment. It seems to work fine on x64 machines but it crashes on x32 bit machines with the following message below. Was wondering how do I fix this?
Component Microsoft CLR types for sql server 2012 x64 has failed to install with the following error message:
"This installation package is not supported by this processor type. Contact your product vendor."
The following components were sucessfully installed:
Microsoft System CLR Types for sql server 2012 x86
The following components were not installed:
Microsoft report viewer 2012 runtime
The following components failed o install:
Microsoft System CLR Types for sql server 2012 x64
You're using the wrong package if you just want to display reports from a C# application. The easiest way of deploying the report viewer components is to include them with your ClickOnce deployment.
Go to the deployment settings and turn to the "Application files" tab and switch the deployment status to "Include" for the assemblies starting with "Microsoft.Report*".
Please note I'm using a German Visual Studio - the labels I quoted above may actually be named differently.
That is because you are trying to install a 64bit application on a 32bit machine. check what the machine is running prior to installing, and then set the applications required up for install.
This is how you can check what type the machine is running from C#
static bool is64BitProcess = (IntPtr.Size == 8);
static bool is64BitOperatingSystem = is64BitProcess || InternalCheckIsWow64();
[DllImport("kernel32.dll", SetLastError = true, CallingConvention = CallingConvention.Winapi)]
[return: MarshalAs(UnmanagedType.Bool)]
private static extern bool IsWow64Process(
[In] IntPtr hProcess,
[Out] out bool wow64Process
);
public static bool InternalCheckIsWow64()
{
if ((Environment.OSVersion.Version.Major == 5 && Environment.OSVersion.Version.Minor >= 1) ||
Environment.OSVersion.Version.Major >= 6)
{
using (Process p = Process.GetCurrentProcess())
{
bool retVal;
if (!IsWow64Process(p.Handle, out retVal))
{
return false;
}
return retVal;
}
}
else
{
return false;
}
}

Mono interop: Loading 32bit shared library does not work on my 64bit system

i have a problem running a simple interop example on my system.
I built a simple 32-bit shared library called libtest.so (c++)
g++ -c -fpic test.cpp -m32
g++ -shared -fpic -o libtest.so test.o -m32
My System:
Ubuntu Linux 10.04 x86_64
Mono C# compiler version 2.4.4.0
In addition i have a sample c# program using my shared library:
using System;
using System.ComponentModel;
using System.Runtime.InteropServices;
public class Test
{
[DllImport("libdl.so")]
static extern IntPtr dlopen(string filename, int flags);
[DllImport("libdl.so")]
static extern IntPtr dlclose(IntPtr handle);
[DllImport ("./libtest.so")]
private static extern void HelloWorld();
[DllImport ("./libtest.so",EntryPoint="Test")]
private static extern int Testl(int a,int b);
public static int Main(string[] args)
{
IntPtr handle = dlopen("./libtest.so",2);
if(handle == IntPtr.Zero)
{
Console.WriteLine("Error loading shared library");
return -1;
}
HelloWorld();
int ret = Testl(116,1);
Console.WriteLine("Result from shared-Librarry Call: " + ret);
dlclose(handle);
return 0;
}
}
The Problem: Loading the library does not work.
exporting MONO_LOG_LEVEL=debug gives me the following hint:
Mono-INFO: DllImport error loading library './libtest.so: Wrong ELF-Class: ELFCLASS32'.
Well i guess mono runs my program in 64-bit mode and therefore it cannot call a 32-bit shared library? If i build the shared library in 64 bit mode (without -m32) everything works fine!!
My Mono-Compiler 2.4.4. does not have the option to specify the platform with /platform:x86 and therefore i installed version 2.10, but using it does not work either.
/opt/mono-2.10/bin/gmcs /platform:x86 sharpCall.cs
Is there a possibility to load 32-bit shared libraries on a 64-bit system?
The problem is that you have a 64bit version of Mono installed on your system which can only P/Invoke into 64bit native libraries, it cannot P/Invoke into 32bit native libraries.
The -platform:x86 flag is meant for the C# compiler, not the runtime, and does not hint to the runtime to use a 32bit memory space.
You need to install the 32bit version of Mono on your Ubuntu system if you want to P/Invoke into 32bit native libraries.
You cannot load a 32 bit module into a 64 bit process. Either run a 32 bit process, or compile your native module as a 64 bit module.
Is there a possibility to load 32-bit shared libraries on a 64-bit
system?
Yes, but only if you compile the program that uses said shared libraries into a 32-bit process.
Well i guess mono runs my program in 64-bit mode and therefore it
cannot call a 32-bit shared library? If i build the shared library in
64 bit mode (without -m32) everything works fine!!
Of course this happen. Just compile the program with the m32 flag and you should have no problems.

Platform target x86 and Any CPU

I have small problem with simple code. This code is working properly on "x86" mode but not on "Any CPU" mode, maybe it is possible to run one class on "x86" and another class on "Any CPU" mode? Code:
namespace Software_Info_v1._0
{
using System;
using System.Collections.Generic;
using System.Text;
using Microsoft.Win32;
public class Adobe
{
public string GetAdobeVersion()
{
try
{
RegistryKey adobe = Registry.LocalMachine.OpenSubKey("Software").OpenSubKey("Adobe");
if (adobe != null)
{
RegistryKey acroRead = adobe.OpenSubKey("Acrobat Reader");
if (acroRead != null)
{
string[] acroReadVersions = acroRead.GetSubKeyNames();
foreach (string versionNumber in acroReadVersions)
{
Console.WriteLine("Acrobat Reader version: " + versionNumber);
}
}
}
}
catch
{
}
return null;
}
}
}
This is because of registry redirection.
The structure of the registry is different for 32-bit and 64-bit OS.
See this MSDN article for more information.
See also this SO thread.
Assuming you are running your application on a 64-bit machine, compiling for x86 target makes your program run using WOW64 mode (32-bit process on 64-bit) and you're reading keys under the Wow6432Node. See Weird behaviour when reading registry in C#
When running as 32bit, the registry key gets redirected. When you run as 64bit, it won't get redirected, and thus won't hit the key to which adobe's registry entry got redirected anymore.
So I'd create a Find32BitRegEntry(string path) function, that does nothing on 32bit, and adds the redirect on x64.
The registry keys can be in a different place on 64 bit machines - see this. (Notice that RegistryKey in your sample code comes from Microsoft.Win32 ?)
I think you need to use a Registry Redirector, there's some talk about it over here.

Categories

Resources