For some reason, whenever my C# .NET 2.0 application makes a call to GetProcAddress it always returns zero.
public class MyClass
{
internal static class UnsafeNativeMethods
{
[DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
internal static extern IntPtr LoadLibrary(string lpFileName);
[DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
internal static extern bool SetDllDirectory(string lpPathName);
[DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
internal static extern IntPtr GetProcAddress(IntPtr hModule, string procName);
}
private void MyFunc()
{
IntPtr _dllHandle;
IntPtr _fptr;
string _fullPath = ".\\mydll.dll";
string _procName = "MyDllFunc";
_dllHandle = UnsafeNativeMethods.LoadLibrary(_fullPath);
_fptr = UnsafeNativeMethods.GetProcAddress(_dllHandle, _procName); // <-- Always returns zero.
}
}
I'm sure the function name is spelled correctly, and _fullPath is presumably correct because _dllHandle is always assigned a non-zero value. Any insight you may be able to provide is appreciated. Thanks.
GetProcAddress only comes in an ANSI flavor, hence we help the runtime by telling it to always use ANSI when marshalling the string parameter. We also prevent the runtime looking for a non-existent GetProcAddressA, because the default for C# is to set ExactSpelling to false.
http://www.pinvoke.net/default.aspx/kernel32.getprocaddress
You really need to add some error checking. At least verify if _dllHandle != IntPtr.Zero. Also, depending on the current working directory is dangerous, use Assembly.GetEntryAssembly().Location to get a full path name.
The function name is probably wrong. Exports tends to be decorated, like _MyDllFunc or _MyDllFunc#4. More wildly if it was compiled by a C++ compiler. Use Dumpbin.exe /exports on your DLL to see the real names.
Back to error handling, use SetLastWin32Error in the [DllImport] attribute. Throw Win32Exception if the function returns false or IntPtr.Zero.
Edit: I see the real problem. Using CharSet.Auto for GetProcAddress() is wrong. Very unlucky, it is just about the only Windows API function that only has an ANSI version. You have to use CharSet.Ansi. A good place to get proper [DllImport] declarations is pinvoke.net
You have not shown how you export the function from the DLL, but I suspect the problem is that the exported name is not what you thing it is. You can run dumpbin /exports mydll.dll to view the exports of the dll to verify the name.
If you show the a code snippet of the export, I could provide more direct advice. You can try decorate the exported function with extern "C" to eliminate the name mangling as a test.
Does your export in the .DEF file for the DLL match the input here? You can use dumpbin to find out what's exported, per other replies here.
What is the underlying Win32 error on GetProcAddress(), per GetLastError()?
You could try this in native code to work out the correct inputs first without the additional baggage of P/Invoke.
Related
Function in Delphi is -
FuncName: PAnsiChar (stdcall)
I don't know the rest of the function code, cause i can't open the Dll.
And i tried to implement it to C# like this -
[DllImport("Lib2-2-1.dll", EntryPoint = "FuncName", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.StdCall)]
[return: MarshalAs(UnmanagedType.AnsiBStr)]
public static extern string FuncName();
when i'm trying to call this C# function in code - everything just closes without an Error, and the code stops executing. Could someone help me please and explain how to write it properly.
And another thing. I tried to open this Dll in DotPeek but it won't open and it says - Not supported, could someone please explain how can i view the code inside it.
okey
so, here is the answer, i found it in this question thread
here is the importing from Dll
[DllImport("Lib2-2-1.dll", EntryPoint = "FuncName", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.StdCall)]
[MethodImplAttribute(MethodImplOptions.PreserveSig)]
public static extern IntPtr FuncName();
And this how to call it
IntPtr ptr = FuncName();
string result = Marshal.PtrToStringAnsi(ptr);
I just encountered with strange behaviour of DllImport in C#, which I can't explain. I want to know how It is possible and where I can read about It. Case is that via DllImport one can call function that doesn't really exported form dll. In my case It is kernel32.dll and function ZeroMemory (but with Copy/Move/Fill memory such behavior). So, my code:
[DllImport("kernel32", EntryPoint = "LoadLibraryW", CharSet = CharSet.Unicode, SetLastError = true)]
public static extern IntPtr LoadLibrary(string libName);
[DllImport("kernel32.dll", CharSet = CharSet.Ansi, ExactSpelling = true, SetLastError = true)]
public static extern IntPtr GetProcAddress(IntPtr module, string procName);
//WTF???
[DllImport("kernel32.dll", SetLastError = true)]
public static extern bool ZeroMemory(IntPtr address, int size);
static void TestMemory()
{
IntPtr mem = Marshal.AllocHGlobal(100); //Allocate memory block of 100 bytes size
Marshal.WriteByte(mem, 55); //Write some value in the first byte
ZeroMemory(mem, 100); //Clearing block of memory
byte firstByte = Marshal.ReadByte(mem); //Read the first byte of memory block
Console.WriteLine(firstByte); //Output 0 (not 55) - ZeroMemory is working
//Getting address of ZeroMemory from kernel32.dll
IntPtr kernelHandle = LoadLibrary("kernel32.dll");
IntPtr address = GetProcAddress(kernelHandle, "ZeroMemory");
Console.WriteLine(address.ToString("X")); //Output 0 - Library kernel32.dll DOESN'T export function ZeroMemory!!!
//Testing GetProcAddress via getting address of some exported function
Console.WriteLine(GetProcAddress(kernelHandle, "AllocConsole").ToString("X")); //Output some address value - all is OK.
}
No EntryPointNotFoundException is thrown - code works fine. If change name of ZeroMemory to ZeroMemory1 or something like that - exception will be thrown. But in export table of kernel32.dll we see:
There is NO ZeroMemory function at all!
If we look in msdn, we read that ZeroMemory is just a macro in WinBase.h header file for C++. Inside that we see:
#define RtlMoveMemory memmove
#define RtlCopyMemory memcpy
#define RtlFillMemory(d,l,f) memset((d), (f), (l))
#define RtlZeroMemory(d,l) RtlFillMemory((d),(l),0)
#define MoveMemory RtlMoveMemory
#define CopyMemory RtlCopyMemory
#define FillMemory RtlFillMemory
#define ZeroMemory RtlZeroMemory
Obviously, that in C++ ZeroMemory actually works through RtlFillMemory from ntdll.dll. But it is in C++!!! Why is it work in C#?? On official documentation for DllImport attribute here we can read the next:
As a minimum requirement, you must supply the name of the DLL
containing the entry point.
But in that case kernel32.dll CANNOT contating entry point for ZeroMemory. What is going on?? Help, please.
The OP is correct in that kernel32.dll has no export ZeroMemory export, yet the C# DllImport somehow succeeds to magically resolve the ZeroMemory reference to the correct RtlZeroMemory export in .NET apps targeted at the Framework (but not at Core).
Turns out that a handful of Win32 APIs documented as inlines/macros (MoveMemory, CopyMemory FillMemory, ZeroMemory) are specifically checked by the Framework code and internally rerouted to the correct exports. While not formally documented, this was acknowledged in a MS-sanctioned comment under a .NET Runtime issue.
As an FYI, there were a few special cased P/Invoke names in .NET Framework: MoveMemory, CopyMemory, FillMemory, and ZeroMemory. All of these will work when pointing at kernel32 on .NET Framework, but will fail on .NET Core. Please use the EntryPoint property in the DllImport attribute to get the desired behavior. The proper export names can be found using dumpbin /exports kernel32.dll from a Visual Studio command prompt.
The above suggests adding an explicit EntryPoint for the declaration to work in both Framework and Core, for example:
[DllImport("kernel32.dll", EntryPoint = "RtlMoveMemory", SetLastError = false)]
public static extern void ZeroMemory(IntPtr address, IntPtr count);
The magic name remapping happens outside the open-sourced .NET code, but can be clearly seen in the disassembly contributed by Simon Mourier in a comment.
I am building C# library (.dll), where some classes use native Windows API functions. To be specific, functions GetPrivateProfileString and WritePrivateProfileString, like:
static class NativeMethods
{
// external functions for working with ini files
[DllImport("kernel32.DLL", EntryPoint = "GetPrivateProfileStringW",
SetLastError = true, CharSet = CharSet.Unicode, ExactSpelling = true,
CallingConvention = CallingConvention.StdCall)]
public static extern int GetPrivateProfileString(string lpAppName, string lpKeyName,
string lpDefault,
string lpReturnString,
int nSize,
string lpFilename);
[DllImport("kernel32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
public static extern bool WritePrivateProfileString(string lpAppName,
string lpKeyName,
string lpString,
string lpFileName);
}
And using them:
NativeMethods.GetPrivateProfileString(section, key, "", result, 127, this.path);
NativeMethods.WritePrivateProfileString(section, key, " " + value, this.path);
When I am using this class directly in another project (without using it from dll), it works without problem. But when I build it into dll, then reference this dll in another project, then these functions aren't working. They simply do nothing.
Your pinvoke for GetPrivateProfileString is wrong as Matthew says. You need to use StringBuilder when passing string data back to the caller.
You are not checking for errors. So it's entirely plausible that the functions are failing without you knowing that.
In order to know why your calls are failing you'd first need to fix these issues. Then you can look at the return values. Knowledge also of the values of the parameters that you are using would help. But only you have the ability to do that, at present.
The bigger problem is that you are not meant to call these functions at all. The documentation says:
This function is provided only for compatibility with 16-bit Windows-based applications.
These functions contain numerous compatibility shims that make using them a complete minefield. Don't go there. Find a decent third party native C~ ini file class and pretend you never heard of GetPrivateProfileString and WritePrivateProfileString.
Oh, I found error. I forced to find ini file path in current directory (in my DLL class code). As I call it from DLL, it was automatically looking for file in C:\Windows. After using Directory.GetCurrentDirectory() + iniFile , it works.
Opening the source code of EasyHook project, I can see that there are some DllImports importing the function RtlGetLastErrorString like this:
//DllName here is a const string equaling to "EasyHook32.dll"
[DllImport(DllName, CallingConvention = CallingConvention.StdCall, CharSet = CharSet.Unicode)]
public static extern String RtlGetLastErrorString();
So I assumed that function should exist. However the following code does not work expectedly (GetProcAddress returns 0):
[DllImport("kernel32", CharSet = CharSet.Ansi, SetLastError = true)]
static extern IntPtr GetProcAddress(IntPtr hModule, string procName);
[DllImport("kernel32.dll", CharSet = CharSet.Ansi)]
public static extern IntPtr GetModuleHandle(String path);
[DllImport("kernel32")]
public static extern IntPtr LoadLibrary(string path);
var mh = LoadLibrary("pathToEasyHook32.dll");
var procAddr = GetProcAddress(mh, "RtlGetLastErrorString");
mh is successfully returned. I've also tried different variant names: RtlGetLastErrorStringA, RtlGetLastErrorStringW but it's still the same.
GetLastError shows that the function name could not be found (error code: 127). So I believe it actual does not exist. But I wonder why the DllImport seems to find that function?
Is there any tool to view that function entry inside EasyHook32.dll? I've tried using OllyDbg but I'm not sure I used it well, I've tried viewing the Executable modules but they all look like the underlying modules loaded from Windows. I've tried finding all names in all modules and it seemed that there wasn't any entry named RtlGetLastErrorString. So looks like my understanding about DllImport has something wrong. At least the way DllImport obtains the function is different from the GetProcAddress does. It would be very nice if you could give me some explanation on this problem. Thank you very much!
You could use dependency walker to view the exported function name for dll.
The correct name for RtlGetLastErrorString is _RtlGetLastErrorString#0.
I've import dll in my code like that:
[DllImport("dll.dll", CharSet = CharSet.Ansi)]
private static extern int function(String pars, StringBuilder err);
I was wondered that function works, but it is not inside project and not inside Debug or Release folders. I.e. "dll.dll" should not be availabe because it is not in the current project folder, however it IS available. Now I want to know the exact full path of the dll used at runtime, but don't know how to get it.
You're going to have to use the win32 API.
First use GetModuleHandle passing "dll.dll" to it. Then pass that handle to GetModuleFileName.
string GetDllPath()
{
const int MAX_PATH = 260;
StringBuilder builder = new StringBuilder(MAX_PATH);
IntPtr hModule = GetModuleHandle("dll.dll"); // might return IntPtr.Zero until
// you call a method in
// dll.dll causing it to be
// loaded by LoadLibrary
Debug.Assert(hModule != IntPtr.Zero);
uint size = GetModuleFileName(hModule, builder, builder.Capacity);
Debug.Assert(size > 0);
return builder.ToString(); // might need to truncate nulls
}
[DllImport("kernel32.dll", CharSet=CharSet.Auto)]
public static extern IntPtr GetModuleHandle(string lpModuleName);
[DllImport("kernel32.dll", SetLastError=true)]
[PreserveSig]
public static extern uint GetModuleFileName
(
[In] IntPtr hModule,
[Out] StringBuilder lpFilename,
[In][MarshalAs(UnmanagedType.U4)] int nSize
);
See Dynamic-Link Library Search Order -- this should hold true with P/Invoke, but the behavior is slightly alterable depending upon load method. However it doesn't say how to determine the filename of a loaded DLL ;-)
A completely un-tested and perhaps ill-advised solution to find the DLL path at run-time. This assumes that P/Invoke and LoadLibrary use the same resolution (e.g. P/Invoke doesn't use LoadLibraryEx with LOAD_WITH_ALTERED_SEARCH_PATH) and that there are no awful conflicts with this approach.
Load the DLL with LoadLibrary or LoadLibaryEx.
Find the filename of the module using GetModuleFileName and the handle obtained in step #1.
Unload the module with FreeLibrary. P/Invoke should keep the module reference-count > 0, but again, this is untested ;-)
(There is no guarantee about the correctness or validity of the above solution. Suggestions, warnings and/or corrections welcome. YMMV.)
Happy coding.
If you really want to find out, use dependency-walker
It can even 'monitor' your application in runtime and detect dynamic loads so nothing remains hidden