Archived

This forum has been archived. Please start a new discussion on GitHub.

Ice in a DLL fails unexpectedly?

Okay, I'm trying to interface LabVIEW to the Ice protocol. The best way I can find to do this is to write a DLL, which LabVIEW can then load and call the functions. So, I've written up a simple DLL with one function that basically just encapsulates the simplePrinter example.

LabIce_DLL1.h:
__declspec(dllexport) void __stdcall LabIce_PrintLong(unsigned long pnum);

LabIce_DLL1.cpp:
#include "stdafx.h"
#include "LabIce_DLL1.h"
#include "Printer.h"
#include "C:\Ice-3.1.0\include\Ice\Ice.h"

using namespace std;
using namespace Demo;

__declspec(dllexport) void __stdcall LabIce_PrintLong(unsigned long pnum)
{
	bool ierr = false;
	try{

			Ice::CommunicatorPtr ic;
			Ice::ObjectPrx base;
			PrinterPrx printer;
			
			//emulate command line parameters
			char* argv[] = {"gdao"};
			int argc = 1;

			//no error yet
			ierr = false;

			ic = Ice::initialize(argc, argv);
			
			//base = ic->stringToProxy("SimplePrinter:default -p 10000");
			
			//printer = PrinterPrx::checkedCast(base);
			
			//if (!printer)
			//		ierr = true;			

			//printer->printLong( ((Ice::Long)(pnum)) );

			if(ic)
				ic->destroy();

		} catch(...) {
			//ierr = true;
		}
	//return !ierr;
}

Now, as you may notice, most of that is commented out. This is the debugging method I've been able to do so far: re-add lines of code until you get an error. But the error is very strange: for some reason, when I try to initialize, it just dies. LabVIEW reports error 1097, which it explains is 'an exception in the external code'. But it can't be something normal, because the entire function is wrapped in a try-catch which should stop errors from propagating.

Does anyone have any idea what it might be?

Comments

  • mes
    mes California
    Welcome to the forum.

    It's possible that a native Win32 exception was raised, which isn't trapped by the C++ try/catch mechanism. Normally I would suggest running (or attaching to) the process in a debugger and configuring the debugger to stop on Win32 exceptions. I'm not sure how easily you can do that with LabView, but it might be worth a try.

    Other possibilities that come to mind are missing DLLs or incompatible compiler options.

    Note that it's expensive to create a new communicator for every Ice invocation. If possible, I would suggest creating the communicator once.

    Good luck,
    - Mark
  • Ah, so native exceptions wouldn't be caught? That could be it then.

    Also, I know that it would be expensive to do that, this is just a test. I originally tried putting them in the DLL's global space, but I wasn't sure if that was causing the error.

    Unfortunately, I have a kind of chicken-and-egg problem in doing that with LabVIEW, because I'd first have to compile the labview project to an executable. And in order to do that, the DLL would have to work. (I think)

    I'll see what I can do, though. Thanks for the pointers.
  • Okay, now I at least have a new angle on the problem. I finally got a test program constructed that does nothing but call the function. I ran it in debug mode and got an 'access violation' error. I have a nagging suspicion that that has something to do with multithreading. If that's the case, what did I do wrong?

    Exception:
    Unhandled exception at 0x00000000 in TestApp.exe: 0xC0000005: Access violation reading location 0x00000000.
    

    TestApp.cpp:
    #include "stdafx.h"
    #include <windows.h>
    #include <stdio.h>
    
    int _tmain(int argc, _TCHAR* argv[])
    {
    
       /* get handle to dll */
    	HINSTANCE hGetProcIDDLL = LoadLibrary((LPCWSTR)"D:\\Coding\\C++ Projects\\LabIce_DLL1\\debug\\LabIce_DLL1.dll");
    
       /* get pointer to the function in the dll*/
       FARPROC lpfnGetProcessID = GetProcAddress(HMODULE(hGetProcIDDLL), "LabIce_PrintLong");
    
       /*
        Define the Function in the DLL for reuse. This is just prototyping
        the dll's function. A mock of it. Use "stdcall" for maximum
        compatibility.
       */
       typedef void (__stdcall * pICFUNC)(unsigned long);
    
       pICFUNC LPrintLong;
       LPrintLong = pICFUNC(lpfnGetProcessID);
    
       /* The actual call to the function contained in the dll */
       LPrintLong((unsigned long)200);
    
       /* Release the Dll */
       FreeLibrary(hGetProcIDDLL);
    }
    
  • mes
    mes California
    That access violation message usually indicates that your program is dereferencing a null pointer. For example, your program calls GetProcAddress and then dereferences the return value without checking whether it is NULL. If you're confident that the access violation occurs inside your function, I recommend building everything in debug mode with multi-threading enabled and run it in the debugger to get a stack trace.

    Take care,
    - Mark
  • After looking at the debugger, that actually *didn't* have to do with the DLL. Some sort of weird string conversion needs to be done to the pathname to load it. I'll let you know if/when I get an actual debug from the DLL.
  • Okay, I finally called it out. (I also had name mangling problems)

    But now, I get this inside the DLL, when calling Ice::initialize(argc,argv)

    Exception:
    Unhandled exception at 0x00439e92 in TestApp.exe: 0xC0000005: Access violation reading location 0xccccccd0.
    

    Something inside of Ice::initialize(argc,argv) is causing a problem, but I don't know what.

    I do know that all of the other DLLs needed are present, but I can't tell you much beyond that. Is there any information I can post from the debugger that would tell you anything?
  • marc
    marc Florida
    In many cases, such problems are caused by mixing debug and release libraries. Have a look at this FAQ for more information.
  • Yeah, just stumbled across that a moment ago. I'm working it right now...
  • That seems to have fixed the problem! Thanks! :)