I am trying to load a win32 dll in C# using the LoadLibraryEx.
It is not working - I get a message stating in visual studio "vshost32.exe has stopped working". No exceptions or any clue as to why it doesn't work.
I don't believe it is a dependency problem because if I alter the search paths for the dependencies I get a message box stating "xyz.dll could not be found".
I am wondering if there is a way I can find out why it doesn't load properly. The program stops working on the line:
IntPtr pDll = LoadLibraryEx(#"C:\Program Files\XXX\XXX.dll", IntPtr.Zero, flags);
[UnmanagedFunctionPointer(CallingConvention.StdCall)]
private delegate void ImportResults();
[DllImport("kernel32.dll", SetLastError = true)]
public static extern IntPtr LoadLibraryEx(string dllToLoad, IntPtr hFile, LoadLibraryFlags flags);
[DllImport("kernel32.dll", SetLastError = true)]
public static extern IntPtr GetProcAddress(IntPtr hModule, string procedureName);
[DllImport("kernel32.dll", SetLastError = true)]
public static extern bool FreeLibrary(IntPtr hModule);
[System.Flags]
public enum LoadLibraryFlags : uint
{
DONT_RESOLVE_DLL_REFERENCES = 0x00000001,
LOAD_IGNORE_CODE_AUTHZ_LEVEL = 0x00000010,
LOAD_LIBRARY_AS_DATAFILE = 0x00000002,
LOAD_LIBRARY_AS_DATAFILE_EXCLUSIVE = 0x00000040,
LOAD_LIBRARY_AS_IMAGE_RESOURCE = 0x00000020,
LOAD_WITH_ALTERED_SEARCH_PATH = 0x00000008,
LOAD_LIBRARY_SEARCH_DLL_LOAD_DIR = 0x00000100,
LOAD_LIBRARY_SEARCH_SYSTEM32 = 0x00000800,
LOAD_LIBRARY_SEARCH_DEFAULT_DIRS = 0x00001000
}
public void Import()
{
LoadLibraryFlags flags = LoadLibraryFlags.LOAD_LIBRARY_SEARCH_DEFAULT_DIRS |
LoadLibraryFlags.LOAD_LIBRARY_SEARCH_DLL_LOAD_DIR;
IntPtr pDll = LoadLibraryEx(#"C:\Program Files\XXX\XXX.dll", IntPtr.Zero, flags);
IntPtr pAddressOfFunctionToCall = GetProcAddress(pDll, "ImportResults");
ImportResults import = (ImportResults)Marshal.GetDelegateForFunctionPointer(pAddressOfFunctionToCall,
typeof(ImportResults));
import();
bool result = FreeLibrary(pDll);
}
Update:
I have downloaded the windows sdk and am attempting to use the cdb.exe to debug the problem using the process described here: http://blogs.msdn.com/b/junfeng/archive/2006/11/20/debugging-loadlibrary-failures.aspx
When running the utility I am using this command line:
"C:\Program Files (x86)\Windows Kits\8.1\Debuggers\x86\cdb.exe" loadlib "C:\Program Files\XXX\XXX\XXX.DLL"
But I get this error:
The file definitely exists so I am unsure what I am doing wrong here.
I installed the windows debugging tools: https://msdn.microsoft.com/en-US/windows/desktop/bg162891
I then downloaded the Windows Symbol packages: https://msdn.microsoft.com/en-us/windows/hardware/gg463028.aspx
Then set an environment variable to tell the debugger where to look for symbols:
_NT_SYMBOL_PATH = SRV*C:\dev\symbols*http://msdl.microsoft.com/download/symbols;C:\Symbols
(I installed the symbol package to C:\Symbols)
Then I started my application and attached the debugger with this command:
"C:\Program Files (x86)\Windows Kits\8.1\Debuggers\x86\cdb.exe" -pb -p <pid>
-pb means it won't break on exceptions
-p is the pid of the thread you want to debug
From this I have been able to determine where the error is happening. Still haven't figured out why it's happening though.
Related
I work in a place where directories have such a looong name and are in such a looong tree.
And I'm having problems with too long path names for folders in an external applicatoin (I can't change this external application, but I can give it shortened path names).
I know Microsoft operating systems can shorten path names such as transforming C:\TooLongName\TooLongSubDirectory in something like C:\TooLon~1\TooLon~1.
But how can I do this in C# and still keep the nave valid and usable?
PS: I'm not using the standard FileInfo and DirectoryInfo classes, I'm using just strings that will be sent to an external application that I cannot change in any way.
If you are unable to use the long path support build into Windows 10 you are able to use the Win32 command GetShortPathName . In order to generate a suitable path.
class Program
{
[DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
static extern uint GetShortPathName(
[MarshalAs(UnmanagedType.LPTStr)]
string lpszLongPath,
[MarshalAs(UnmanagedType.LPTStr)]
StringBuilder lpszShortPath,
uint cchBuffer);
[DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
static extern uint GetShortPathName(string lpszLongPath, char[] lpszShortPath, int cchBuffer);
static void Main(string[] args)
{
StringBuilder builder = new StringBuilder(260);
var shortPath = GetShortPathName(#"C:\Projects\Databases\ReallllllllllllllyLOOOOOOOOOOOOOOOOOOOOOONGPATHHHHHHHHHHH\StillllllllllllllllllGOoooooooooooooooooooooooing", builder, (uint)builder.Capacity);
Console.WriteLine(builder.ToString());
Console.ReadKey();
}
}
Produces C:\Projects\DATABA~1\REALLL~1\STILLL~1
Currently i get the error message, that vcruntime140.dll was not found on a client computer. But I'm delivering the following dlls for x64 and x86:
vcruntime140.dll
vccorlib140.dll
msvcp140.dll
concrt140.dll
in a \bin32\ and \bin64\ directory (for each platform). This directories are registered on application startup:
Dll-Import
[DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
static extern bool SetDllDirectory(string lpPathName);
[DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
static extern bool AddDllDirectory(string lpPathName);
And for x86 the registration code:
if (System.Environment.OSVersion.Version.Major > 5)
{
AddDllDirectory(System.Windows.Forms.Application.StartupPath + "\\bin32");
}
else
{
SetDllDirectory(System.Windows.Forms.Application.StartupPath + "\\bin32");
}
What do I need to do additionally?
Thank you all!
When I was searching on Google I found a useful class which let us change the icon of any .exe file using the following line of code :
WindowsFormsApplication1.IconInjector.InjectIcon("myfile.exe", "myicon.ico", 200, 1);
Where 200 and 1 are respectively icon GroupID and icon BaseID which I can determine using Resource Hacker. In this case the file's icon changes successfully without corrupting the file.
So i planned to use this class on my program which is a SFX / Software protector, the output file always hasn't an icon, all what I can see on Resource hacker is the below :
i can't see icon group id nor the base id, anyway, (I don't know what to put instead of 200 and 1 in this case) So I tried to change the icon using the same line of code mentioned above, I used the following line of code (same as above):
WindowsFormsApplication1.IconInjector.InjectIcon("myfile.exe", "myicon.ico", 200, 1);
The file icon was successfully changed but the file doesn't work anymore!
When I tried to reopen the file using ResourceHacker, I found the below:
It seems that the icon resources were successfully added, but i can't figure out why the file doesn't work anymore, it seems that is corrupted.
Any help would be appreciated.
Note : I tried using this class with unprotected file and it works like a charm!
The class I am using is the below:
// IconInjector.cs
using System;
using System.Runtime.InteropServices;
using System.Diagnostics;
namespace WindowsFormsApplication1
{
/// <summary>
/// IconInjectorクラスの定義
/// </summary>
public class IconInjector
{
[DllImport("kernel32.dll", SetLastError = true)]
//static extern bool UpdateResource(IntPtr hUpdate, string lpType, string lpName, ushort wLanguage, IntPtr lpData, uint cbData);
static extern int UpdateResource(IntPtr hUpdate, uint lpType, uint lpName, ushort wLanguage, byte[] lpData, uint cbData);
[DllImport("kernel32.dll", SetLastError = true)]
static extern IntPtr BeginUpdateResource(string pFileName,
[MarshalAs(UnmanagedType.Bool)]bool bDeleteExistingResources);
[DllImport("kernel32.dll", SetLastError = true)]
static extern bool EndUpdateResource(IntPtr hUpdate, bool fDiscard);
/// <summary>
/// アプリケーションのメイン エントリ ポイントです。
/// </summary>
[STAThread]
public static void InjectIcon(string execFileName, string iconFileName, uint iconGroupID, uint iconBaseID)
{
const uint RT_ICON = 3;
const uint RT_GROUP_ICON = 14;
// アイコンファイルの読み込み
IconFile iconFile = new IconFile();
iconFile.Load(iconFileName);
// リソースの更新開始
IntPtr hUpdate = BeginUpdateResource(execFileName, false);
Debug.Assert(hUpdate != IntPtr.Zero);
// RT_GROUP_ICON 書き込み
byte[] data = iconFile.CreateIconGroupData(iconBaseID);
UpdateResource(hUpdate, RT_GROUP_ICON, iconGroupID, 0, data, (uint)data.Length);
// RT_ICON書き込み
for (int i = 0; i < iconFile.GetImageCount(); i++)
{
byte[] image = iconFile.GetImageData(i);
UpdateResource(hUpdate, RT_ICON, (uint)(iconBaseID + i), 0, image, (uint)image.Length);
}
// リソースの更新終了
EndUpdateResource(hUpdate, false);
}
}
}
Any help or suggestion on adding the icon to the protected file without corrupting it?
It sounds like the protection application is verifying that the contents of the file haven't been tampered with. Injecting an icon is definitely a form of tampering, and unless the protection software is updated to ignore it, it will always fail. Alternatively if you own the protection software you could update it to not strip the icons.
I just experienced the same issue with a 7zip Self-Extractor exe.
Updating the icon of the 7zS.sfx (instead of the exe) before creating the Self-Extractor exe does the trick and the exe is not corrupted.
Your application's icon can be added to this executable with a tool like Resource Hacker.
and visit http://georezo.net/jparis/MI_Enviro/Icons/adding_w_RH.htm
In order to avoid registry redirection to Wow64 keys, how to translate the following code that uses Microsoft.Win32 APIs
public void SetKeyAccessControl(
RegistryKey rootKey, string subKeyName, string identity,
RegistryRights rights, InheritanceFlags inheritanceFlags,
PropagationFlags propagationFlags, AccessControlType accessType)
{
using (RegistryKey regKey = rootKey.OpenSubKey(subKeyName, true))
{
RegistrySecurity acl = new RegistrySecurity();
RegistryAccessRule rule = new RegistryAccessRule(identity, rights, inheritanceFlags, propagationFlags, accessType);
acl.AddAccessRule(rule);
regKey.SetAccessControl(acl);
}
}
into using advapi32 RegSetKeySecurity API
[DllImport(#"advapi32.dll", EntryPoint = "RegSetKeySecurity", SetLastError = true)]
internal static extern int RegSetKeySecurity(IntPtr handle, uint securityInformation, IntPtr pSecurityDescriptor);
To avoid Registry redirection, you could do something like this...
SafeRegistryHandle handle = rootKey.Handle;
RegistryKey rootKey32 = RegistryKey.FromHandle(handle, RegistryView.Registry32);
RegistryKey rootKey64 = RegistryKey.FromHandle(handle, RegistryView.Registry64);
You can then use rootKey32 or rootKey64 to open a subkey and you'll get the subkey of the view requested.
At least it works in the few test cases I've tried. And, according to the documentation for FromHandle...
The view parameter for this method is used in subsequent operations,
such as opening subkeys
Another native method needs to be involved and given an SDDL, the following code sets ACLs on the right registry key:
[DllImport("Advapi32.dll", CallingConvention = CallingConvention.Winapi, SetLastError = true, CharSet = CharSet.Auto)]
internal static extern bool ConvertStringSecurityDescriptorToSecurityDescriptor(string stringSecurityDescriptor, int stringSDRevision, out IntPtr ppSecurityDescriptor, ref int securityDescriptorSize);
string sddl = "...";
IntPtr secDescriptor = IntPtr.Zero;
int size = 0;
ConvertStringSecurityDescriptorToSecurityDescriptor
(
sddl,
1, // revision 1
out secDescriptor,
ref size
);
// get handle with RegOpenKeyEx
RegSetKeySecurity
(
handle,
0x00000004, // DACL_SECURITY_INFORMATION
secDescriptor
);
I am making use of an external unmanaged dll using PInvoke and the DllImport attribute. eg.
[DllImport("mcs_apiD.dll", CharSet = CharSet.Auto)]
private static extern byte start_api(byte pid, byte stat, byte dbg, byte ka);
I am wondering if it is possible to alter the dll file details (mcs_apiD.dll in this example) dynmically in some manner, if for instance I wanted to build against another dll version
Yes this is possible, you'll have to do part of the job that the P/Invoke marshaller does. Loading the DLL and finding the entry point of the exported function. Start by declaring a delegate whose signature matches the exported function:
private delegate byte start_api(byte pid, byte stat, byte dbg, byte ka);
Then use code like this:
using System.ComponentModel;
using System.Runtime.InteropServices;
...
static IntPtr dllHandle;
...
if (dllHandle == IntPtr.Zero) {
dllHandle = LoadLibrary("mcs_apiD.dll");
if (dllHandle == IntPtr.Zero) throw new Win32Exception();
}
IntPtr addr = GetProcAddress(dllHandle, "_start_api#16");
if (addr == IntPtr.Zero) throw new Win32Exception();
var func = (start_api)Marshal.GetDelegateForFunctionPointer(addr, typeof(start_api));
var retval = func(1, 2, 3, 4);
...
[DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
private static extern IntPtr LoadLibrary(string name);
[DllImport("kernel32.dll", CharSet = CharSet.Ansi, SetLastError = true)]
private static extern IntPtr GetProcAddress(IntPtr hModule, string name);
Lots of ways to get this wrong of course. Do note that you have to use the actual exported name from the DLL, you no longer get the help from the P/Invoke marshaller to help with name decoration. Use dumpbin.exe /exports on the DLL if you are not sure what the export name looks like.
you can't change the name of the dll but you can alter the path of the library being loaded (like by reading it from the registry or a configuration file) and load it manually with LoadLibrary kernel32's function: see my answer there.