0

I'm trying to use a function from a C++ dll that sets callbacks that I can use in the program for the future, but when I call that function the app crashes without displaying an error or anything.

C# Code:


        [DllImport("DocProc.dll", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
        public static extern ulong DPSetCallBacks(DPHandle hdl, IntPtr cbs);

        public delegate void ConnectedCB(DPHandle hdl);
        public delegate void DisconnectedCB(DPHandle hdl);
        public delegate void DocCompleteCB(DPHandle hdl);
        public delegate void DocImageCompleteCB(DPHandle hdl);
        public delegate void DocImageSnippetCompleteCB(DPHandle hdl);
        public delegate void DocReadCompleteCB(DPHandle hdl);
        public delegate void ExceptionCompleteCB(DPHandle hdl);
        public delegate void ExceptionInProgressCB(DPHandle hdl);
        public delegate void FlowStoppedCB(DPHandle hdl);
        public delegate void HopperEmptyCB(DPHandle hdl);
        public delegate void IdleCB(DPHandle hdl);
        public delegate void MachineDeadCB(DPHandle hdl);
        public delegate void PoweredDownCB(DPHandle hdl);
        public delegate void PoweredUpCB(DPHandle hdl);
        public delegate void PoweringUpCB(DPHandle hdl);
        public delegate void ReadyingCB(DPHandle hdl);
        public delegate void ReadyToProcessCB(DPHandle hdl);
        public delegate void StateExceptionCB(DPHandle hdl);
        public delegate void WarningCB(DPHandle hdl);
        public delegate void NvmReadCompleteCB(DPHandle hdl);
        public delegate void MakeReadyToFlowCompleteCB(DPHandle hdl);

        [StructLayout(LayoutKind.Sequential, CharSet=CharSet.Ansi)]
        public struct DPcbs
        {
            public int size;
            public ConnectedCB connectedCB;
            public DisconnectedCB disconnectedCB;
            public DocCompleteCB docCompleteCB;
            public DocImageCompleteCB docImageComplete;
            public DocImageSnippetCompleteCB docImageSnippetCompleteCB;
            public DocReadCompleteCB docReadComplete;
            public ExceptionCompleteCB exceptionCompleteCB;
            public ExceptionInProgressCB exceptionInProgressCB;
            public FlowStoppedCB flowStoppedCB;
            public HopperEmptyCB hopperEmptyCB;
            public IdleCB idleCB;
            public MachineDeadCB machineDeadCB;
            public PoweredDownCB poweredDownCB;
            public PoweredUpCB poweredUpCB;
            public PoweringUpCB poweringUpCB;
            public ReadyingCB readyingCB;
            public ReadyToProcessCB readyToProcessCB;
            public StateExceptionCB stateExceptionCB;
            public WarningCB warningCB;
            public NvmReadCompleteCB nvmReadCompleteCB;
            public MakeReadyToFlowCompleteCB makeReadyToFlowCompleteCB;
        }

C++ Code:

typedef struct { 
unsigned int size;
 ConnectedCB connectedCB;
 DisconnectedCB disconnectedCB;
 DocCompleteCB docCompleteCB;
 DocImageCompleteCB docImageComplete;
 DocImageSnippetCompleteCB docImageSnippetCompleteCB;
 DocReadCompleteCB docReadComplete;
 ExceptionCompleteCB exceptionCompleteCB;
 ExceptionInProgressCB exceptionInProgressCB;
 FlowStoppedCB flowStoppedCB;
 HopperEmptyCB hopperEmptyCB;
 IdleCB idleCB;
 MachineDeadCB machineDeadCB;
 PoweredDownCB poweredDownCB;
 PoweredUpCB poweredUpCB;
 PoweringUpCB poweringUpCB;
 ReadyingCB readyingCB;
 ReadyToProcessCB readyToProcessCB;
 StateExceptionCB stateExceptionCB;
 WarningCB warningCB; 
 NvmReadCompleteCB nvmReadCompleteCB;
 MakeReadyToFlowCompleteCB makeReadyToFlowCompleteCB;
}

unsigned long DPSetCallBacks(DPHandle hdl, DPcbs *dpcbs);

I use it like so:

 DPcbs cbs = new DPcbs();
               cbs.poweredUpCB = PoweredUp;

                ptr = Marshal.AllocHGlobal(Marshal.SizeOf(cbs));
                try
                {

                    // Copy the struct to unmanaged memory.
                    Marshal.StructureToPtr(cbs, ptr, false);

                    DPSetCallBacks(handle, ptr);

                }
                finally
                {
                    // Free the unmanaged memory.
                    Marshal.FreeHGlobal(ptr);
                }

Result is the application crashing without any visible errors. Any help will be appreciated. Thanks in advance!

xBones
  • 31
  • 5
  • If there are no errors, what do you mean it's crashing? I don't see any code where you're doing any kind of output, so couldn't it just be completing successfully? Do you mean the console window is closing? Add a `Console.ReadLine()` to the end of your C# program. – itsme86 Jul 03 '19 at 14:37
  • It's a Windows Forms application, the application exits whenever that function is ran. – xBones Jul 03 '19 at 14:41
  • The garbage collector probably runs somehow and your managed pointers are gone when called from managed code. Probably a duplicate of this: https://stackoverflow.com/questions/4906931/nullreferenceexception-during-c-callback-to-c-sharp-function – Simon Mourier Jul 03 '19 at 14:51
  • Hmmm, that is different from what I'm doing kind of though... – xBones Jul 03 '19 at 15:06
  • So is that C# rendition of the C++ struct exactly the same? And I mean *exactly* the same (padding, layout, size, etc.)? Looking and matching up the members is not proof of this. – PaulMcKenzie Jul 03 '19 at 15:41
  • Different from what? – Simon Mourier Jul 03 '19 at 15:45
  • Different from the link you sent me. @SimonMourier And I suppose it's the same isn't it – xBones Jul 03 '19 at 15:54
  • 1
    C# `ulong` is 64 bits, C++ `unsigned long` is 32 bits. There are loads of critical sections of code missing which could be the cause of the problem. We don't know whether the calling conventions match, whether the delegates are protected from collection, and probably more potential pitfalls besides. Unfortunately it is so common for pinvoke questions to be missing critical detail. – David Heffernan Jul 03 '19 at 16:00
  • @DavidHeffernan In this specific piece of code, the only thing I use is unsigned int (in the struct) and I set that as `int` but If you think that's wrong please tell me, I'm sorta new to this. Apologies. And the function return value should be ulong I think. Correct me if i'm wrong. – xBones Jul 03 '19 at 16:04
  • The calling conventions do match because I have a bunch of other functions and they all work with that convention. I'm pretty sure it is correct. – xBones Jul 03 '19 at 16:06
  • Have you read Hans' answer in the link I provided? You don't seem to fix callback references (pointer to managed functions). If you don't fix them, GC can move/destroy them as it see fits. – Simon Mourier Jul 03 '19 at 16:37
  • I already corrected you about the function return value. I explained why `ulong` is wrong. If you are so sure that you did everything right that you don't want to entertain criticism, then you've come to the wrong place. It's hard enough helping at the best of times, but it's even harder, and no fun at all, when you have to try to persuade a reluctant asker about their mistakes. – David Heffernan Jul 03 '19 at 16:43
  • You mean like this? ` DPcbs cbs = new DPcbs(); PoweredUpCB poweredUpCb = PoweredUp; cbs.poweredUpCB = poweredUpCb; ` Because that's basically Han's answer if I understand correctly. I don't really use direct `new` things other than that part. – xBones Jul 03 '19 at 16:43
  • @DavidHeffernan I can understand that it's wrong, but the fact that I have other functions with the same return value and they are working is a bit confusing to me, Ill give it a try though. – xBones Jul 03 '19 at 16:44
  • I have changed it into `uint` but I got the same result. Sadly. – xBones Jul 03 '19 at 16:58
  • You have to get everything right. Just because fixing one of many bugs doesn't solve the problem doesn't mean that you don't need to fix that one bug. With incomplete information it's not possible to give you a definitive answer fixing all defects. – David Heffernan Jul 03 '19 at 17:17
  • Yeah, I understand. Is there anything else you would like to see to be able to help more? I would fix it if I knew where the problem is. I looked into everything and it seems everything is correct from my perspective. – xBones Jul 03 '19 at 17:51
  • I already told you what was missing. Make it easy for us with a [mcve]. – David Heffernan Jul 03 '19 at 18:01
  • I'm not really sure how I can do that, since i'm using a DLL I can't really share... – xBones Jul 07 '19 at 14:16

1 Answers1

-1

If you want to compile such C++ code in a DLL its better to include it in a class and give an accessor method.

c# project could never have access to a compiled typedef struct without wrapping it!

Be aware of your runtime compiled DLL version

marcolomew
  • 11
  • 2