callbacks

Collapse
This topic is closed.
X
X
 
  • Time
  • Show
Clear All
new posts
  • WAkthar

    callbacks

    Hi,

    can anyone show me how to be able to pass the name of method to a dll
    function which will call this method when something inside the dll calling
    function happens.
    Is this called a callback?

    Are there any websites that show how to implement something like this
    easily??


  • Nico Gerber

    #2
    Re: callbacks

    Yes this is called a callback. You must just remember to "lock" your method
    as "unsafe". If you do not so this the garbage collector might move your
    methods' code around at some stage, and the DLL might call the "old" address
    of your function ... which might not be the correct address ... causing some
    problems, with difficult debugging!

    "WAkthar" <wakthar@hotmai l.com> wrote in message
    news:%23VQvz4Ca FHA.1088@TK2MSF TNGP14.phx.gbl. ..[color=blue]
    > Hi,
    >
    > can anyone show me how to be able to pass the name of method to a dll
    > function which will call this method when something inside the dll calling
    > function happens.
    > Is this called a callback?
    >
    > Are there any websites that show how to implement something like this
    > easily??
    >
    >[/color]


    Comment

    • Willy Denoyette [MVP]

      #3
      Re: callbacks


      "Nico Gerber" <ngerber@telkom sa.net> wrote in message
      news:O3skPXDaFH A.3840@tk2msftn gp13.phx.gbl...[color=blue]
      > Yes this is called a callback. You must just remember to "lock" your
      > method as "unsafe". If you do not so this the garbage collector might move
      > your methods' code around at some stage, and the DLL might call the "old"
      > address of your function ... which might not be the correct address ...
      > causing some problems, with difficult debugging!
      >[/color]

      This is not true, code never moves, the GC only moves objects in the GC
      heap, code is not store in the GC heap!

      Willy.


      Comment

      • Eyal Safran

        #4
        Re: callbacks

        Guys guys...
        The guy is looking for code examples...

        I hope this will clear some stuff:

        On your Cpp side:

        You need to define a function pointer such as:
        typedef void (__stdcall *LPFN_MANAGED_C ALLBACK)(unsign ed int x,unsigned
        int y);

        ** don't forget the __stdcall

        and a method to receive the EventHandler from the Managed side such as:
        void MyCppMethod(LPF N_MANAGED_CALLB ACK lpfnManagedCall back)
        {
        // To call the callback do:
        lpfnManagedCall back(10 /*x value*/, 20 /*y value*/);
        }


        On the C# side:
        1) you should define a delegate such as:
        public delegate void PointEventHandl er(uint x, uint y);

        2) a member to hold the PointEventHandl er so that it won't be
        collected:
        private PointEventHandl er m_pointCallback ;

        3) a p/Invoke for the Cpp method:
        [DllImport("CppD ll.dll", CallingConventi on=CallingConve ntion.StdCall)]
        extern private static void CppMethod(Point EventHandler pointCB);

        4) you need to create a method to handle the Cpp call:
        private void CppCallbackHand ler(uint x, uint y)
        {
        Console.WriteLi ne("Received a call from Cpp with X={0} & y={1}", x,
        y);
        }

        5) you need to create the callback:
        m_pointCallback = new PointEventHandl er(CppCallbackH andler);

        6) and now you can pass the callback to Cpp side:
        CppMethod(m_poi ntCallback);

        Cheers,
        Eyal Safran

        Comment

        • WAkthar

          #5
          Re: callbacks

          Thanks Eyal,

          My scenario is a little different. There are two people involved in the
          project.

          I am writing the UI part and my collegue is writing a dll which will
          communicate with teh serial port.

          What we have is the ability for me to call functions that communicate with
          the serial port. Now when certain events happen at the serial port, I need
          to be notified.
          To implement is I thought about using delegates as callbacks. The dll is
          also written in C#.

          When I create an object from the dll, I pass the function pointer (delegate)
          to it. When an event happens on the serial port, this delegate is called and
          I can update the UI.

          Can you show how I can implement something like this please??

          Thanks in advance!


          "Eyal Safran" <eyal@mokedor.c om> wrote in message
          news:1117819926 .671559.175300@ f14g2000cwb.goo glegroups.com.. .[color=blue]
          > Guys guys...
          > The guy is looking for code examples...
          >
          > I hope this will clear some stuff:
          >
          > On your Cpp side:
          >
          > You need to define a function pointer such as:
          > typedef void (__stdcall *LPFN_MANAGED_C ALLBACK)(unsign ed int x,unsigned
          > int y);
          >
          > ** don't forget the __stdcall
          >
          > and a method to receive the EventHandler from the Managed side such as:
          > void MyCppMethod(LPF N_MANAGED_CALLB ACK lpfnManagedCall back)
          > {
          > // To call the callback do:
          > lpfnManagedCall back(10 /*x value*/, 20 /*y value*/);
          > }
          >
          >
          > On the C# side:
          > 1) you should define a delegate such as:
          > public delegate void PointEventHandl er(uint x, uint y);
          >
          > 2) a member to hold the PointEventHandl er so that it won't be
          > collected:
          > private PointEventHandl er m_pointCallback ;
          >
          > 3) a p/Invoke for the Cpp method:
          > [DllImport("CppD ll.dll", CallingConventi on=CallingConve ntion.StdCall)]
          > extern private static void CppMethod(Point EventHandler pointCB);
          >
          > 4) you need to create a method to handle the Cpp call:
          > private void CppCallbackHand ler(uint x, uint y)
          > {
          > Console.WriteLi ne("Received a call from Cpp with X={0} & y={1}", x,
          > y);
          > }
          >
          > 5) you need to create the callback:
          > m_pointCallback = new PointEventHandl er(CppCallbackH andler);
          >
          > 6) and now you can pass the callback to Cpp side:
          > CppMethod(m_poi ntCallback);
          >
          > Cheers,
          > Eyal Safran
          >[/color]


          Comment

          • Eyal Safran

            #6
            Re: callbacks

            Hi,
            [color=blue]
            > When I create an object from the dll, I pass the function pointer (delegate)
            > to it. When an event happens on the serial port, this delegate is called and
            > I can update the UI.
            >
            > Can you show how I can implement something like this please??
            >
            > Thanks in advance![/color]

            well it's you lucky day, (I hope thats what you ment).
            I already wrapped unmanaged code to interact with the serial port:

            [Flags]
            public enum CommEvents
            {
            /// <summary>
            /// No events
            /// </summary>
            EV_NONE = 0x0000,
            /// <summary>
            /// Any Character received
            /// </summary>
            EV_RXCHAR = 0x0001,
            /// <summary>
            /// Received certain character
            /// </summary>
            EV_RXFLAG = 0x0002,
            /// <summary>
            /// Transmit Queue Empty
            /// </summary>
            EV_TXEMPTY = 0x0004,
            /// <summary>
            /// CTS changed state
            /// </summary>
            EV_CTS = 0x0008,
            /// <summary>
            /// DSR changed state
            /// </summary>
            EV_DSR = 0x0010,
            /// <summary>
            /// RLSD changed state
            /// </summary>
            EV_RLSD = 0x0020,
            /// <summary>
            /// BREAK received
            /// </summary>
            EV_BREAK = 0x0040,
            /// <summary>
            /// Line status error occurred
            /// </summary>
            EV_ERR = 0x0080,
            /// <summary>
            /// Ring signal detected
            /// </summary>
            EV_RING = 0x0100,
            /// <summary>
            /// Printer error occurred
            /// </summary>
            EV_PERR = 0x0200,
            /// <summary>
            /// Receive buffer is 80 percent full
            /// </summary>
            EV_RX80FULL = 0x0400,
            /// <summary>
            /// Provider specific event 1
            /// </summary>
            EV_EVENT1 = 0x0800,
            /// <summary>
            /// Provider specific event 2
            /// </summary>
            EV_EVENT2 = 0x1000
            }

            protected CommEvents commEvents = CommEvents.EV_N ONE;
            private EventHandlerLis t events;

            protected EventHandlerLis t Events
            {
            get
            {
            if (events == null)
            {
            lock(this)
            {
            if (events == null)
            {
            events = new EventHandlerLis t();
            }
            }
            }
            return events;
            }
            }

            // Event objects
            private static readonly object EventCharacterR eceived;
            private static readonly object EventCertainCha racterReceived;
            private static readonly object EventTransmitQu eueEmpty;
            private static readonly object EventCTSStateCh anged;
            private static readonly object EventDSRStateCh anged;
            private static readonly object EventRLSDStateC hanged;
            private static readonly object EventBreakRecei ved;
            private static readonly object EventLineStatus ErrorOccurred;
            private static readonly object EventRingSignal Detected;
            private static readonly object EventPrintError Occurred;
            private static readonly object EventReceiveBuf ferIs80PercentF ull;
            private static readonly object EventProviderSp ecificEvent1;
            private static readonly object EventProviderSp ecificEvent2;

            static Port() // static constructor
            {
            EventCharacterR eceived = new object();
            EventCertainCha racterReceived = new object();
            EventTransmitQu eueEmpty = new object();
            EventCTSStateCh anged = new object();
            EventDSRStateCh anged = new object();
            EventRLSDStateC hanged = new object();
            EventBreakRecei ved = new object();
            EventLineStatus ErrorOccurred = new object();
            EventRingSignal Detected = new object();
            EventPrintError Occurred = new object();
            EventReceiveBuf ferIs80PercentF ull = new object();
            EventProviderSp ecificEvent1 = new object();
            EventProviderSp ecificEvent2 = new object();
            }

            // example to an event "Character Received" you register on:
            public event EventHandler CharacterReceiv ed // Any Character received
            {
            add
            {
            if (Events[EventCharacterR eceived] == null)
            {
            commEvents |= CommEvents.EV_R XCHAR;
            SetEvents();
            }
            Events.AddHandl er(EventCharact erReceived, value);
            }
            remove
            {
            Events.RemoveHa ndler(EventChar acterReceived, value);
            if (Events[EventCharacterR eceived] == null)
            {
            commEvents &= ~CommEvents.EV_ RXCHAR;
            SetEvents();
            }
            }
            }

            protected void SetEvents()
            {
            if (commEvents == CommEvents.EV_N ONE)
            {
            return;
            }
            if (Trace.debug())
            {
            Trace.debug("Se tting {0} communication port events:\n{1}", PortName,
            commEvents);
            }
            bool result = _SetCommMask(hP ort, (int)commEvents );
            if (result == false)
            {
            throw new CommunicationEx ception("Failed to SetCommMask (set the
            events)");
            }
            }

            [DllImport("kern el32.dll", EntryPoint="Set CommMask",
            SetLastError=tr ue,
            CharSet=CharSet .Unicode, ExactSpelling=t rue,
            CallingConventi on=CallingConve ntion.StdCall)]
            protected static extern bool _SetCommMask(
            Int32 hFile,
            int lpEvtMask);

            [DllImport("kern el32.dll", EntryPoint="Wai tCommEvent",
            SetLastError=tr ue,
            CharSet=CharSet .Unicode, ExactSpelling=t rue,
            CallingConventi on=CallingConve ntion.StdCall)]
            protected static extern bool _WaitCommEvent(
            Int32 hFile,
            ref CommEvents Mask,
            IntPtr lpOverlap);

            public void WaitForEvents()
            {
            if (commEvents == CommEvents.EV_N ONE)
            {
            throw new CommunicationEx ception("No events have been registered.");
            }
            CommEvents eventsReceived = CommEvents.EV_N ONE;
            bool result = _WaitCommEvent( hPort, ref eventsReceived, IntPtr.Zero);
            if (result == false)
            {
            throw new CommunicationEx ception("Failed Waiting for comm events.");
            }
            // CharacterReceiv ed
            object[] args = new object[]{this, EventArgs.Empty };
            EventHandler invoker = null;
            if ((eventsReceive d & CommEvents.EV_R XCHAR) == CommEvents.EV_R XCHAR)
            {
            invoker = (EventHandler)E vents[Port.EventChara cterReceived];
            if ( invoker != null)
            {
            invoker.Dynamic Invoke(args);
            }
            }
            }


            Remark:
            In this code, the user registers on the events, the first registration
            on each event adds a flag to the member: "commEvents ".
            After all the clients unregistered from an the event, the flag is
            removed from: "commEvents ".

            The collection of events is sent to the RS-232 port.

            when the WaitForEvents is called, the thread is waiting for any of the
            registered events to occur.
            When they do, the C# event of the corresponding RS-232 event is
            triggered.

            Eyal.

            Comment

            Working...