• Visitors can check out the Forum FAQ by clicking this link. You have to register before you can post: click the REGISTER link above to proceed. To start viewing messages, select the forum that you want to visit from the selection below. View our Forum Privacy Policy.
  • Want to receive the latest contracting news and advice straight to your inbox? Sign up to the ContractorUK newsletter here. Every sign up will also be entered into a draw to WIN £100 Amazon vouchers!
Collapse

You are not logged in or you do not have permission to access this page. This could be due to one of several reasons:

  • You are not logged in. If you are already registered, fill in the form below to log in, or follow the "Sign Up" link to register a new account.
  • You may not have sufficient privileges to access this page. Are you trying to edit someone else's post, access administrative features or some other privileged system?
  • If you are trying to post, the administrator may have disabled your account, or it may be awaiting activation.

Previously on "C# to C++ callback problem"

Collapse

  • suityou01
    replied
    Originally posted by VectraMan View Post
    No you don't. C++ means you can mix and match managed and unmanaged in the same function.

    Did it work in the end? Looking back at the code, the thing that jumps out at me is that you're passing a FIREWALL_MESSAGE that's on the stack. I didn't think you'd be able to pass a delegate in either, but obviously you can.
    Thank VM will look into this.

    Leave a comment:


  • doodab
    replied
    Originally posted by VectraMan View Post
    No you don't. C++ means you can mix and match managed and unmanaged in the same function.

    Did it work in the end? Looking back at the code, the thing that jumps out at me is that you're passing a FIREWALL_MESSAGE that's on the stack. I didn't think you'd be able to pass a delegate in either, but obviously you can.
    How do you do that? I thought the boundary was always at a function call i.e. you could have managed and unmanaged functions in a mixed assembly but each function is either managed or unmanaged.

    Good point though, the code might be easier to read and write.

    Leave a comment:


  • VectraMan
    replied
    Originally posted by doodab View Post
    Then you still have the problem of accessing the driver from managed code.
    No you don't. C++ means you can mix and match managed and unmanaged in the same function.

    Did it work in the end? Looking back at the code, the thing that jumps out at me is that you're passing a FIREWALL_MESSAGE that's on the stack. I didn't think you'd be able to pass a delegate in either, but obviously you can.

    Leave a comment:


  • doodab
    replied
    Originally posted by VectraMan View Post
    Why don't you just do the DLL in C++ CLR? Then you can make the interface all .NET, and still call the native code.
    Then you still have the problem of accessing the driver from managed code.

    Leave a comment:


  • VectraMan
    replied
    Why don't you just do the DLL in C++ CLR? Then you can make the interface all .NET, and still call the native code.

    Leave a comment:


  • suityou01
    replied
    Originally posted by doodab View Post
    The function in the DLL or the .Net app will be connected to the driver?

    I am presuming the DLL will be handling IO to the driver device and then the .Net app will be using the DLL as above?
    Yep that's it. I tried having the .net app talking direct to the driver but despite microsoft's claims, it just isn't as quick as unmanaged (native) code, fact. So this dll should handle all the io flak from the driver, and only pass important stuff up to the front end.

    Or so the theory goes.

    Leave a comment:


  • doodab
    replied
    Originally posted by suityou01 View Post
    The function is a stub, that I am using to test my .net app. Ultimately it will be connected up to my WFP driver, and it will be callback based.
    The function in the DLL or the .Net app will be connected to the driver?

    I am presuming the DLL will be handling IO to the driver device and then the .Net app will be using the DLL as above?

    Leave a comment:


  • suityou01
    replied
    Originally posted by doodab View Post
    Ah, now it makes sense. I've never seen anyone put a loop like that into a function called "registerCallback" before

    I thought you meant you registered the callback and then there was a thread in the DDL that called it.

    Why don't you just do away with the callback and put a loop in the mangled ^H^H^H^H aged code to call "getSomeData" every two seconds? That way you could perhaps pass in a reference to the destination structure and the marshalling would go more smoothly.
    The function is a stub, that I am using to test my .net app. Ultimately it will be connected up to my WFP driver, and it will be callback based.

    Leave a comment:


  • doodab
    replied
    Ah, now it makes sense. I've never seen anyone put a loop like that into a function called "registerCallback" before

    I thought you meant you registered the callback and then there was a thread in the DDL that called it.

    Why don't you just do away with the callback and put a loop in the mangled ^H^H^H^H aged code to call "getSomeData" every two seconds? That way you could perhaps pass in a reference to the destination structure and the marshalling would go more smoothly.

    Leave a comment:


  • suityou01
    replied
    Originally posted by doodab View Post
    What do you mean the API blocks the thread exactly? The GC runs in a different thread.

    What struct are you passing into the callback? Why don't you post the actual code with the problems?
    I posted stripped down code for brevity. The original problem was the callback not working. Having pedalled backwards to no parameters, and then primitive parameters I have something that seems to work.

    C++

    Code:
        typedef enum FWP_DIRECTION_ {
    	FWP_DIRECTION_OUTBOUND,
    	FWP_DIRECTION_INBOUND,
    	FWP_DIRECTION_MAX
        } FWP_DIRECTION;
    
            LIST_ENTRY listEntry;
    		int srcport;
            int destport;
            char sourceIp[16];
            char destIp[16];
    		int protocol;
    		long packetRef;
    		FWP_DIRECTION  direction; //FWP_DIRECTION Defined in Inspect.h
    		int type;
    		UINT64 processId;
    		int allow;
    } FIREWALL_MESSAGE;
    
    
    
    extern "C" _declspec(dllexport) void Cpkdll::listenForALEConnections(void (_stdcall *func)(int destPort, int srcPort))
    {
    	m_bListenForALEConnections=true;
    	FIREWALL_MESSAGE fwm;
    	while (m_bListenForALEConnections==true)
    	{
    		strcpy(fwm.destIp,"212.58.254.251");
    		fwm.destport = 80;
    		strcpy(fwm.sourceIp,"192.168.1.5");
    		fwm.packetRef = 111;
    		fwm.processId = 0;
    		fwm.protocol = 53;
    		fwm.srcport = 2453;
    		fwm.type = 1;
    		func(fwm.destport,fwm.srcport);
    		Sleep(2000);
    	}
    	return;
    }
    You can see here that I was trying to pass FIREWALL_MESSAGE back to CLR, to no avail, and then swapped to two ints for simplicity's sake.

    C#

    Code:
    [System.Runtime.InteropServices.StructLayoutAttribute(System.Runtime.InteropServices.LayoutKind.Sequential)]
            public struct LIST_ENTRY
            {
                /// _LIST_ENTRY*
                public System.IntPtr Flink;
    
                /// _LIST_ENTRY*
                public System.IntPtr Blink;
            }
    
            public struct FIREWALL_MESSAGE
            {
                public LIST_ENTRY listEntry;
                public Int32 srcport;
                public Int32 destport;
                public char[] sourceIp;
                public char[] destIp;
                public Int32 protocol;
                public Int32 packetRef;
                public EFWPDIRECTION direction; //FWP_DIRECTION Defined in Inspect.h
                public Int32 type;
            }
    
    [UnmanagedFunctionPointer(CallingConvention.StdCall)]
            public delegate void CallBackMethodDelegate(int destPort, int srcPort);
    
            [DllImport("C:\\Projects\\portknox\\User Mode Dll\\pk.dll\\Debug\\pk.dll.dll", EntryPoint = "?listenForALEConnections@Cpkdll@@QAEXP6GXHH@Z@Z", CallingConvention = CallingConvention.StdCall)]
            public static extern void listenForALEConnections(CallBackMethodDelegate del);
    
    
            static void aleCallBack(int destPort, int srcPort)
            {
                Console.WriteLine(destPort.ToString() + "," + srcPort.ToString());
                return;
            }
    
            static void Main(string[] args)
            {
                CallBackMethodDelegate del = new CallBackMethodDelegate(aleCallBack);
                listenForALEConnections(del);
                Console.WriteLine("Listening for ALE Connections");
            }
    So there you go, the whole sordid affair.

    @DimPrawn : Yes very good blog post, given me lots to think about C++ side.

    Leave a comment:


  • doodab
    replied
    Originally posted by suityou01 View Post
    The loop just calls the function pointer. That's it.

    The function pointer is valid, and the api blocks the thread so it's not going to get cleaned up (I hope).

    I have managed to pass primitive arguments to the callback, but not my struct, which gives the latest error. Presumably the managed code cannot marshal the structure. Whichever, having a callback with a very lot of arguments is a small price to pay if it's robust.
    What do you mean the API blocks the thread exactly? The GC runs in a different thread.

    What struct are you passing into the callback? Why don't you post the actual code with the problems?

    Leave a comment:


  • DimPrawn
    replied
    Does this help?

    Gotchas with Reverse Pinvoke (unmanaged to managed code callbacks) - David Notario's WebLog - Site Home - MSDN Blogs

    Leave a comment:


  • suityou01
    replied
    Originally posted by doodab View Post
    What happens without the loop? i.e. if your code just calls registerCallback(del) does the c++ code receive a valid function pointer at that point?

    I suspect that if you are keeping a copy of the pointer then you will hit problems because it points at a system generated "thunk" into managed code that is probably getting tidied up.
    The loop just calls the function pointer. That's it.

    The function pointer is valid, and the api blocks the thread so it's not going to get cleaned up (I hope).

    I have managed to pass primitive arguments to the callback, but not my struct, which gives the latest error. Presumably the managed code cannot marshal the structure. Whichever, having a callback with a very lot of arguments is a small price to pay if it's robust.

    Leave a comment:


  • doodab
    replied
    Originally posted by suityou01 View Post
    In point of fact I actually have a loop that runs in the dll that keeps firing the callback.
    What happens without the loop? i.e. if your code just calls registerCallback(del) does the c++ code receive a valid function pointer at that point?

    I suspect that if you are keeping a copy of the pointer then you will hit problems because it points at a system generated "thunk" into managed code that is probably getting tidied up.

    Interesting reading here: http://www.mono-project.com/Interop_...tive_Libraries

    The GC that .NET uses is not conservative. It knows all types involved, and can distinguish between an integer that looks like a pointer and an actual pointer value. It knows all stack-allocated variables, and what the scope of those variables is. Finally, the GC does not see into unmanaged code.

    The result of this is that it's possible the the GC to collect a class instance while a method of the instance is still executing .

    How is this possible? If the method no longer references class data (instance members), and no other code refers to it, the GC may collect the class. After all, if no instance members are used and no one is using the instance, what's it matter if the instance is collected?
    So perhaps try and find a way to trick you last Console.writeLine(); into keeping a reference to an instance variable e.g. by storing the message as a member.
    Last edited by doodab; 26 May 2011, 14:29.

    Leave a comment:


  • suityou01
    replied
    Originally posted by DimPrawn View Post
    Won't your console app just load run and then exit?

    What's keeping it running?
    The api call. In point of fact I actually have a loop that runs in the dll that keeps firing the callback.

    I have had some more success in that if I pass no parameters at all, and declare the function in the dll as _cdecl and then may the DllImport use CallingConvention.CDecl it works.

    So then I added the parameters back in and I get an access violation.

    Leave a comment:

Working...
X