-2

I'm trying to create a C++/CLI wrapper for some native DLLs. There are seven of these DLLs and more in the future so I need to load them dynamically. They all have the same set of functions. LoadLibrary and GetProcAddress worked great in a native application to load these functions.

Whenever I load a DLL and call Initialize, I get AccessViolationException. Im testing with a C# Console app with platform x86 selected.

UPDATE: Not sure why I got down voted. This question hasn't been answered in any of my google searches. I've searched for half a week before even asking. All questions here about the same thing are using a different method. MSDN says AccessViolations in native interop are the sign of serious programming errors. I don't see what i'm doing wrong. I'm marshalling my strings, and checking for nullptrs before calling. The load functions seem to work. If i put in known bad function names, or a DLL path i know is incorrect it tells me that loading failed. If i put in the correct paths/function names it says everything worked, but then crashes when i try to call it. The function TSInit, for the DLL i'm testing doesnt actually do anything in this particular DLL it however might do some actual work for the other DLLs with the same interface.

Update 2:

I think this question is unanswerable. As I've said, there is several DLLs with the exact same interface. Now, i've found out some of them work, and some don't. I checked all of them with dumpbin to confirm they're all x86 compiled and they are. I'm not sure what is wrong with the DLLs that don't work. In native C++ applications, they all work as expected.

typedef long (WINAPI *TSRINIT)(long lType, HWND hParent, RECT *pRect);

namespace Imagery
{
    public ref class Recongizer
{
public:
    Recongizer(String^ DllPath) { LoadRecongizer(DllPath); }
    ~Recongizer() { UnloadLibrary(); }
    bool LoadRecongizer(String^ DllPath)
    {
        HInstance = ::LoadLibrary(msclr::interop::marshal_as<std::wstring>(DllPath).c_str());
        if (HInstance == nullptr) return false;
        if (!LoadFunctions())   return false;
        return true;
    }
    long Initalize(long lType)
    {
        if (HInstance == nullptr || TSInit == nullptr) return 0;
        return TSInit(0, nullptr, nullptr);
    }
private:
    void UnloadLibrary()
    {
        if (HInstance != nullptr) ::FreeLibrary(HInstance);
    }
    bool LoadFunctions()
    { 
        TSInit = (TSRINIT)::GetProcAddress(HInstance, "TSRInit");
        if (TSInit == nullptr)
        {
            ErrorMessage = "TSRInit could not be loaded.";
            return false;
        }
        return true;
    }
    property String^ ErrorMessage;
private:
    HINSTANCE HInstance{ nullptr };
    TSRINIT TSInit{ nullptr };
};

}

Deduplicator
  • 44,692
  • 7
  • 66
  • 118
Ray
  • 243
  • 2
  • 4
  • You cannot get a diagnostic for such a vague question. Start by *not* using LoadLibrary(), there is completely no point to it. Just link the import libraries of those DLLs and #include the relevant .h files. Three less failure modes. – Hans Passant Apr 03 '16 at 20:46
  • Access Violations aren't magic. You have a stack trace, for instance. – MSalters Apr 06 '16 at 15:02

1 Answers1

0

It might be a problem with calling conventions. Make sure all of the DLLs use the same calling convention (i.e. WINAPI according to your definition of TSRINIT), otherwise you might encounter stack corruptions as your code and the DLL's code might expect different cleanup behavior. See https://msdn.microsoft.com/en-us/library/984x0h58.aspx for an overview. Not sure why native C++ applications would work, though - just a wild guess.

JBartlau
  • 772
  • 5
  • 23