Why do libgit2 methods using kernel32.dll's GetProcAddress always return 0? - libgit2

I have the need to manually handle the loading / unloading of the actual git2.dll, instead of using [DllImport("git2")] in C#. I seem to have issues with creating an IntPtr for reference to the address of methods stored in libgit2.
Here're the good bits from my PluginManager class which are supposed to help facilitate manually loading, marshal/delegate (whenever I get this kink fixed), and unloading libraries.
public class PluginManager {
public const string LIB = "Assets\\Plugins\\git2.dll";
[DllImport( "kernel32.dll", CharSet = CharSet.Ansi )]
public static extern IntPtr LoadLibrary( [In, MarshalAs( UnmanagedType.LPStr )] string lib );
[DllImport( "kernel32.dll", CharSet = CharSet.Ansi, ExactSpelling = true, SetLastError = true )]
public static extern IntPtr GetProcAddress( [In] IntPtr reference, [In, MarshalAs( UnmanagedType.LPStr )] string method );
[DllImport( "kernel32.dll" )]
public static extern bool FreeLibrary( [In] IntPtr reference );
}
Here's where I attempt to use them:
//# Working; always non-zero.
IntPtr reference = PluginManager.LoadLibrary( PluginManager.LIB );
//# Should be valid -- LibGit2Sharp.Core.NativeMethods.cs calls this method, too.
//# Always returns IntPtr.Zero.
IntPtr methodReference = PluginManager.GetProcAddress( reference, "git_repository_open" );
Is the library not exposed to this type of loading? I've tried all kinds of methods present in the LibGit2Sharp native hooks, but they always return zero.

It seems that git2.dll has mangled export names, so git_repository_open is actually _git_repository_open#4. After researching some more on why this is happening, it seems that, according to This Post, and several others that I've run into while looking for a fix, that the functions may not be exported using extern "C" or may not be using a .def file.
I did look through some of the libgit2 code, and I saw extern used on a couple functions, but on others I saw no export keyword at all, but they're still being accessed externally from LigGit2Sharp's NativeMethods.cs class.
While all of that is foreign to me, I did find a very useful post about a tool shipped with Visual Studio that allows you to see all exported items, and their names: Dumpbin. With this, I was able to determine the exported names, and used the /OUT:filename flag to save them to a file: PasteBin
With all of the exported names at my disposal, I just have to follow function calls, that I'm actually using, and replace the the methods in NativeMethods.cs to look something like this: LibGit2Sharp Issue #341.

Related

How to properly store an HWND in a ref class?

I'm working on a C++/CLI library to be used with C#. I have a ref class (for use directly within managed code, so it has to be compatible) that stores an HWND, but I don't think I'm doing it right:
public ref class MyClass {
protected:
HWND hWnd;
}
Should I be using a native pointer like that inside a ref class? Or should I use something like ptr<T>?
A handle is not a pointer, HWND is fine. If you want C# code to derive from your class and access the handle then you need to expose it as an IntPtr. Which is compatible with a handle, it is 4 bytes in 32-bit mode and 8 bytes in 64-bit mode, just like a handle.
Best to wrap it with a property to hide the conversion:
protected:
property IntPtr Handle {
IntPtr get() { return IntPtr(hwnd); }
void set(IntPtr h) { hwnd = (HWND)h.ToPointer(); }
}
private:
HWND hWnd;
A SafeHandle might be useful, the lifetime of a HWND is however not typically under your control.
Native pointers/handles are completely safe inside ref classes. (They're just ints after all.) However, it would be more idiomatic to store them in the IntPtr class. (This is how WinForms stores them.)

Unable to find an entry point

I import two WinApi functions and use them in my class
using namespace System::Runtime::InteropServices;
[DllImport("user32",ExactSpelling = true)]
extern bool CloseWindow(int hwnd);
[DllImport("user32",ExactSpelling = true)]
extern int FindWindow(String^ classname,String^ windowname);
public ref class WinApiInvoke
{
public:
bool CloseWindowCall(String^ title)
{
int pointer = FindWindow(nullptr,title);
return CloseWindow(pointer);
}
};
Then I create object in main program and call CloseWindowCall method
Console::WriteLine("Window's title");
String ^s = Console::ReadLine();
WinApiInvoke^ obj = gcnew WinApiInvoke();
if (obj->CloseWindowCall(s))
Console::WriteLine("Window successfully closed!");
else Console::WriteLine("Some error occured!");
When I write in console for example Chess Titans to close I've got an error
Unable to find an entry point named 'FindWindow' in DLL 'user32'
What entry point?
You are using the ExactSpelling property inappropriately. There is no FindWindow function in user32.dll, just like the exception message says. There is FindWindowA and FindWindowW. The first one handles legacy 8-bit character strings, the second uses Unicode strings. Any Windows api function that accepts strings has two versions, you don't see this in C or C++ code because the UNICODE macro selects between the two.
Avoid ExactSpelling on winapi functions, the pinvoke marshaller knows how to deal with this. You have some other mistakes, the proper declaration is:
[DllImport("user32.dll", CharSet = CharSet::Auto, SetLastError = true)]
static IntPtr FindWindow(String^ classname, String^ windowname);

How do I set the class cursor to null?

Sorry about the long post! I have some explaining to do, I'm afraid... I have an application (in Unity3d, but for windows) that doesn't use WinForms, so I cannot use the Cursor class which is part of System.Windows.Forms namespace. But all the same, I'd like to be able to set the current shape of the cursor.
After much research and much googling, I've found that this is possible using P/Invoke calls to certain methods in user32.dll. I got it (sort of) working by:
Find a handle to the window using:
[DllImport("user32.dll")]
public static extern IntPtr FindWindow(string lpClassName, string lpWindowName);
And supply null for the classname and the title of the window for the windowname. Then use the returned IntPtr to call this:
[DllImport("user32.dll")]
public static extern IntPtr SetClassLong(IntPtr hwnd, int index, IntPtr dwNewLong);
And supply "-4" for the index in order to target the pointer to the WindowProc that handles all the lowlevel window messages, and then use:
System.Runtime.InteropServices.Marshal.GetFunctionPointerForDelegate()
To generate a native pointer to a new WndProc delegate which I implement in my managed code. Its signature looks like this:
public long WndProc(IntPtr hwnd, uint msg, uint wparam, int lparam);
In summary, I'm basically overriding the native window procedure with a managed callback, and it then becomes my responsibility to handle all the window messages. But I'm not interested in rewriting the entire implementation for the standard window proc, I just want to be able to control the way it draws its mouse cursor shape when the cursor is over the window. So, to do so, I can call the default window proc with this function:
[DllImport("user32.dll")]
public static extern long DefWindowProc(IntPtr hwnd, uint msg, uint wparam, int lparam);
And then immediately afterwards, set the cursor to something else using:
[DllImport("user32.dll", CharSet = CharSet.Auto, ExactSpelling = true)]
private static extern IntPtr SetCursor(IntPtr hCursor);
This sort of works. :) I say "sort of", because I'm seeing a bit of flickering that occurs because the default window proc first sets the cursor to the class cursor, and then immediately afterwards, my implementation sets it to the custom cursor I want using SetCursor. This situation can be remedied by setting the class cursor to null. Doing so causes the system to not draw the cursor and expect the application to set the cursor for every window message instead, and that's exactly what I'm doing, so it would stop them fighting over the who gets to set the cursor and eliminate the flickering. This is documented on MSDN at:
http://msdn.microsoft.com/en-us/library/windows/desktop/ms648393%28v=vs.85%29.aspx
Where they explain that one must set the class cursor to null. But that's where my knowledge falls short. :( The class cursor is set with SetClassLong as explained in the article above.
But the datatype for the new value of the cursor is IntPtr. This datatype is not nullable, the compiler complains if I pass in null, and passing in IntPtr.zero doesn't work. So how do I accomplish what the article advices? How do I set the class cursor to null using P/Invoke?

LNK2020 when making a variable static

I use C++/CLI to link between a .NET application and a dynamically loaded C dll.
So far all access to the DLL is instance based.
The class
namespace NxCore {
public class NativeConnector {
has variable for various references to methods:
HMODULE hLib;
NxCoreProcessTape pfNxProcessTape;
NxCorePriceToDouble pfNxPriceToDouble;
NxCoreGetDefinedString pfNxCoreGetDefinedString;
NxCoreGetSymbolAtom32 pfNxGetSymbolAtom32;
NxCoreStateGetMMQuotes pfNxStateGetMmQuotes;
I load those in a connect method:
hLib = ::LoadLibrary("NxCoreAPI.dll");
then
pfNxProcessTape = (NxCoreProcessTape)::GetProcAddress(hLib, cszNxCoreProcessTape);
pfNxPriceToDouble = (NxCorePriceToDouble)::GetProcAddress(hLib, cszNxCorePriceToDouble);
pfNxCoreGetDefinedString = (NxCoreGetDefinedString)::GetProcAddress(hLib, cszNxCoreGetDefinedString);
etc.
Now I need to move that to multi instances, so I want to load on first connect, unload on last disconnect. This means the variables must go static.
In C# I would just make them static. I try one:
static HMODULE hLib;
and linking fails:
4>NativeConnector.obj : error LNK2020: unresolved token (0A00006D) "private: static struct HINSTANCE__ * NxCore::NativeConnector::hLib" (?hLib#NativeConnector#NxCore#Connectivity#Tradex##0PAUHINSTANCE__##A)
Anyone an idea how to fix it? The header file is used on the .cpp file, so - it should not have different definitions.
Anyone can tell he how to fix that issue? As i said - I want to move the variables to be static and then use "usage counting" myself to make sure that I release on last disconnect.
From the code shown I'm not exactly clear on whether the problem occurs in a ref class (.NET class) or a native C++ class.
Here is my advice assuming a native type: You need to define the declared member
header
struct X
{
static int s_data;
};
cpp source:
#include "X.h"
int X::s_data /* = 42 */;
For ref types I'd actually expect the same semantics for static as with C#

C++ CLI error C3767: candidate function(s) not accessible

I'm new to C++ CLI coming from unmanaged C++ world.
I'm getting this error:
candidate function(s) not accessible
when I pass a std::string as part of the method argument.
Here's the exact code:
Lib Project (compiled as .dll project)
//Lib.h
#pragma once
public ref class Lib
{
public:
Lib(void);
public:
void Extract( std::string& data_ );
};
//Lib.cpp
#include "Lib.h"
Lib::Lib(void)
{
}
void Lib::Extract( std::string& data_ )
{
data_.empty();
}
LibTest Project (compiled as application.exe)
// LibTest.h
#pragma once
ref class LibTest
{
public:
LibTest(void);
};
// LibTest.cpp
#include "LibTest.h"
LibTest::LibTest(void)
{
Lib^ lib = gcnew Lib;
lib->Extract( std::string("test") );
}
int main()
{
return 0;
}
Compiler Error:
1>------ Build started: Project: LibTest, Configuration: Debug Win32 ------
1>Compiling...
1>LibTest.cpp
1>.\LibTest.cpp(7) : error C3767: 'Lib::Extract': candidate function(s) not accessible
The problem is that std::string will compile as a internal (non public) type. This is actually a change in VS 2005+:
http://msdn.microsoft.com/en-us/library/ms177253(VS.80).aspx:
Native types are private by default outside the assembly
Native types now will not be visible outside the assembly by default. For more information on type visibility outside the assembly, see Type Visibility. This change was primarily driven by the needs of developers using other, case-insensitive languages, when referencing metadata authored in Visual C++.
You can confirm this using Ildasm or reflector, you will see that your extract method is compiled as:
public unsafe void Extract(basic_string<char,std::char_traits<char>,std::allocator<char> >* modopt(IsImplicitlyDereferenced) data_)
with basic_string being compiled as:
[StructLayout(LayoutKind.Sequential, Size=0x20), NativeCppClass, MiscellaneousBits(0x40), DebugInfoInPDB, UnsafeValueType]
internal struct basic_string<char,std::char_traits<char>,std::allocator<char> >
Note the internal.
Unfortunately you are then unable to call a such a method from a different assembly.
There is a workaround available in some cases: You can force the native type to be compiled as public using the make_public pragma.
e.g. if you have a method Extract2 such as:
void Extract2( std::exception& data_ );
you can force std::exception to be compiled as public by including this pragma statement beforehand:
#pragma make_public(std::exception)
this method is now callable across assemblies.
Unfortunately make_public does not work for templated types (std::string just being a typedef for basic_string<>)
I don't think there is anything you can do to make it work. I recommend using the managed type System::String^ instead in all your public API. This also ensures that your library is easily callable from other CLR languages such as c#
if you simply must access the internal methods another work around would be making the projects as Friend Assemblies like that:
//Lib Project
#pragma once
//define LibTest as friend assembly which will allow access to internal members
using namespace System;
using namespace System::Runtime::CompilerServices;
[assembly:InternalsVisibleTo("LibTest")];
public ref class Lib
{
public:
Lib(void);
public:
void Extract( std::string& data_ );
};
//LibTest Project
#pragma once
#using <Lib.dll> as_friend
ref class LibTest
{
public:
LibTest(void);
};
In addition to the solutions described above, one can subclass the templated type to obtain a non-templated type, and include its definition in both projects, thus overcoming some of the problems mentioned above.