Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • World
  • Users
  • Groups
Skins
  • Light
  • Cerulean
  • Cosmo
  • Flatly
  • Journal
  • Litera
  • Lumen
  • Lux
  • Materia
  • Minty
  • Morph
  • Pulse
  • Sandstone
  • Simplex
  • Sketchy
  • Spacelab
  • United
  • Yeti
  • Zephyr
  • Dark
  • Cyborg
  • Darkly
  • Quartz
  • Slate
  • Solar
  • Superhero
  • Vapor

  • Default (No Skin)
  • No Skin
Collapse
Code Project
  1. Home
  2. General Programming
  3. Managed C++/CLI
  4. Mapping a function pointer (CALLBACK) to a delegate to use in BacgroundWorker function parameter

Mapping a function pointer (CALLBACK) to a delegate to use in BacgroundWorker function parameter

Scheduled Pinned Locked Moved Managed C++/CLI
c++tutorialquestion
16 Posts 3 Posters 0 Views 1 Watching
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • A Offline
    A Offline
    alleyes 0
    wrote on last edited by
    #1

    I know that seemed like a bit vague, let me explain. I have in native code a callback that is used for passing to a function for means of acting as a percent complete mechanism in a native console app. The signature is as follows: typedef bool (APIENTRY *CBUpdateValue)(unsigned PercentComplete); That is passed as a parameter to a function that uses it for file reads and writes: DLLAPI HRESULT APIENTRY GetFile(size_t FileSize, BYTE* Data, CBUpdateValue CompletStatus) In the native code that uses the callback, an example of the use of the callback is bool APIENTRY UpdateStatus(unsigned PercentComplete) { printf("\r%d%%...", PercentComplete); return false; } The goal is to use this signature, but replace the printf call to send information to a BackgroundWorker object. It takes an unsigned and returns a bool. Because of this constraint, is it possible to use this for a BGW? I realize I have to map the function pointer to a delegate. Has anyone used something like this? Thanks in advance

    L N 2 Replies Last reply
    0
    • A alleyes 0

      I know that seemed like a bit vague, let me explain. I have in native code a callback that is used for passing to a function for means of acting as a percent complete mechanism in a native console app. The signature is as follows: typedef bool (APIENTRY *CBUpdateValue)(unsigned PercentComplete); That is passed as a parameter to a function that uses it for file reads and writes: DLLAPI HRESULT APIENTRY GetFile(size_t FileSize, BYTE* Data, CBUpdateValue CompletStatus) In the native code that uses the callback, an example of the use of the callback is bool APIENTRY UpdateStatus(unsigned PercentComplete) { printf("\r%d%%...", PercentComplete); return false; } The goal is to use this signature, but replace the printf call to send information to a BackgroundWorker object. It takes an unsigned and returns a bool. Because of this constraint, is it possible to use this for a BGW? I realize I have to map the function pointer to a delegate. Has anyone used something like this? Thanks in advance

      L Offline
      L Offline
      Luc Pattyn
      wrote on last edited by
      #2

      Hi, this article[^] of mine explains P/Invoke, including native code calling callbacks. While all examples use C# or VB.NET, similar things are possible using C++/CLI. Pay special attention to the STDCALL keyword. :)

      Luc Pattyn [Forum Guidelines] [Why QA sucks] [My Articles] Nil Volentibus Arduum

      Please use <PRE> tags for code snippets, they preserve indentation, and improve readability.

      A 1 Reply Last reply
      0
      • L Luc Pattyn

        Hi, this article[^] of mine explains P/Invoke, including native code calling callbacks. While all examples use C# or VB.NET, similar things are possible using C++/CLI. Pay special attention to the STDCALL keyword. :)

        Luc Pattyn [Forum Guidelines] [Why QA sucks] [My Articles] Nil Volentibus Arduum

        Please use <PRE> tags for code snippets, they preserve indentation, and improve readability.

        A Offline
        A Offline
        alleyes 0
        wrote on last edited by
        #3

        I should have mentioned that I am using IJW. The article provided no help but thanks anyway

        L 1 Reply Last reply
        0
        • A alleyes 0

          I should have mentioned that I am using IJW. The article provided no help but thanks anyway

          L Offline
          L Offline
          Luc Pattyn
          wrote on last edited by
          #4

          OK. Seems like IJW is a bit of a misnomer then? :-D Anyway, managed methods are always called in STDCALL (there is no way to change that), your native code must adhere to that. :)

          Luc Pattyn [Forum Guidelines] [Why QA sucks] [My Articles] Nil Volentibus Arduum

          Please use <PRE> tags for code snippets, they preserve indentation, and improve readability.

          A 1 Reply Last reply
          0
          • L Luc Pattyn

            OK. Seems like IJW is a bit of a misnomer then? :-D Anyway, managed methods are always called in STDCALL (there is no way to change that), your native code must adhere to that. :)

            Luc Pattyn [Forum Guidelines] [Why QA sucks] [My Articles] Nil Volentibus Arduum

            Please use <PRE> tags for code snippets, they preserve indentation, and improve readability.

            A Offline
            A Offline
            alleyes 0
            wrote on last edited by
            #5

            Well perhaps, but compared to using a P/Invoke solution, it seems more natural to use C++/CLI especially when interoperation with native code is required.

            1 Reply Last reply
            0
            • A alleyes 0

              I know that seemed like a bit vague, let me explain. I have in native code a callback that is used for passing to a function for means of acting as a percent complete mechanism in a native console app. The signature is as follows: typedef bool (APIENTRY *CBUpdateValue)(unsigned PercentComplete); That is passed as a parameter to a function that uses it for file reads and writes: DLLAPI HRESULT APIENTRY GetFile(size_t FileSize, BYTE* Data, CBUpdateValue CompletStatus) In the native code that uses the callback, an example of the use of the callback is bool APIENTRY UpdateStatus(unsigned PercentComplete) { printf("\r%d%%...", PercentComplete); return false; } The goal is to use this signature, but replace the printf call to send information to a BackgroundWorker object. It takes an unsigned and returns a bool. Because of this constraint, is it possible to use this for a BGW? I realize I have to map the function pointer to a delegate. Has anyone used something like this? Thanks in advance

              N Offline
              N Offline
              Nish Nishant
              wrote on last edited by
              #6

              So what part are you stuck on? Converting between the function pointer/delegate? Or handling the background worker?

              Regards, Nish


              My technology blog: voidnish.wordpress.com Code Project Forums : New Posts Monitor This application monitors for new posts in the Code Project forums.

              A 1 Reply Last reply
              0
              • N Nish Nishant

                So what part are you stuck on? Converting between the function pointer/delegate? Or handling the background worker?

                Regards, Nish


                My technology blog: voidnish.wordpress.com Code Project Forums : New Posts Monitor This application monitors for new posts in the Code Project forums.

                A Offline
                A Offline
                alleyes 0
                wrote on last edited by
                #7

                Handling the Backgroundworker! At the risk of being wordy, let me give a little more detail. It may help. In native code, I have a callback used as a percent complete mechanism. Its signature is below:

                typedef bool (APIENTRY *CB_UpdateStatus)(unsigned PercentComplete);

                The function is below:

                bool APIENTRY UpdateStatus(unsigned PercentComplete)
                {
                printf("\r%d%%...", PercentComplete);
                return false;
                }

                Passed as an arg to a native function: HRESULT Result = NativeFileRead(Size, Data, UpdateStatus); I need to wrap this function so it can be used as-is in native code but when wrapped will allow use in a graphical program by use of the background worker to get status back to a UI. I modified the function pointer signature:

                typedef bool (APIENTRY *CB_UpdateStatus)(unsigned PercentComplete, void* context);

                and its use by the calling function:

                bool APIENTRY UpdateStatus(unsigned PercentComplete, void* context)
                {
                printf("\r%d%%...", PercentComplete);
                return false;
                }

                The native function that uses the callback now has an added parameter "void* context" - it's signature is below:

                DLLAPI HRESULT APIENTRY NativeFileRead(size_t DataSize, BYTE* Data, CB_UpdateStatus UpdateStatus, void* context)

                In native code I just pass a NULL so it causes no harm during debug and development. In managed code I need to wrap the function and use a BGW. In my wrapper class I have this function signature:

                Wrapper::FileRead(UInt32 DataSize, String^ managedFileHandle, BackgroundWorker^ worker)

                My callback in the wrapper class now looks like:

                bool __stdcall UpdateStatus(unsigned PercentComplete, void* context)
                {
                BackgroundWorker^ worker = static_cast<BackgroundWorker^>(&context);
                worker->ReportProgress(PercentComplete);
                //Console::Write("\r{0}...", PercentComplete);
                return false;
                }

                I want to pass in the worker to the native function.

                HRESULT Result = NativeFileRead(DataSize, Data, UpdateStatus, context);

                The problem is now handling the BGW for a function that expects a void pointer. Thanks Nish

                N 1 Reply Last reply
                0
                • A alleyes 0

                  Handling the Backgroundworker! At the risk of being wordy, let me give a little more detail. It may help. In native code, I have a callback used as a percent complete mechanism. Its signature is below:

                  typedef bool (APIENTRY *CB_UpdateStatus)(unsigned PercentComplete);

                  The function is below:

                  bool APIENTRY UpdateStatus(unsigned PercentComplete)
                  {
                  printf("\r%d%%...", PercentComplete);
                  return false;
                  }

                  Passed as an arg to a native function: HRESULT Result = NativeFileRead(Size, Data, UpdateStatus); I need to wrap this function so it can be used as-is in native code but when wrapped will allow use in a graphical program by use of the background worker to get status back to a UI. I modified the function pointer signature:

                  typedef bool (APIENTRY *CB_UpdateStatus)(unsigned PercentComplete, void* context);

                  and its use by the calling function:

                  bool APIENTRY UpdateStatus(unsigned PercentComplete, void* context)
                  {
                  printf("\r%d%%...", PercentComplete);
                  return false;
                  }

                  The native function that uses the callback now has an added parameter "void* context" - it's signature is below:

                  DLLAPI HRESULT APIENTRY NativeFileRead(size_t DataSize, BYTE* Data, CB_UpdateStatus UpdateStatus, void* context)

                  In native code I just pass a NULL so it causes no harm during debug and development. In managed code I need to wrap the function and use a BGW. In my wrapper class I have this function signature:

                  Wrapper::FileRead(UInt32 DataSize, String^ managedFileHandle, BackgroundWorker^ worker)

                  My callback in the wrapper class now looks like:

                  bool __stdcall UpdateStatus(unsigned PercentComplete, void* context)
                  {
                  BackgroundWorker^ worker = static_cast<BackgroundWorker^>(&context);
                  worker->ReportProgress(PercentComplete);
                  //Console::Write("\r{0}...", PercentComplete);
                  return false;
                  }

                  I want to pass in the worker to the native function.

                  HRESULT Result = NativeFileRead(DataSize, Data, UpdateStatus, context);

                  The problem is now handling the BGW for a function that expects a void pointer. Thanks Nish

                  N Offline
                  N Offline
                  Nish Nishant
                  wrote on last edited by
                  #8

                  I don't understand why FileRead is passed a BackgroundWorker argument. Shouldn't FileRead be called from the worker thread's DoWork event? And secondly, you cannot pass a managed reference through a void*. Instead create a delegate with managed arguments, and convert that to a function pointer before invoking the native FileRead method (so when the native FileRead invokes the native callback, what gets called eventually is your managed delegate handler). In the managed version, make the 2nd argument an Object^ (so that it can represent a BackgroundWorker). Hope that made sense.

                  Regards, Nish


                  My technology blog: voidnish.wordpress.com Code Project Forums : New Posts Monitor This application monitors for new posts in the Code Project forums.

                  A 1 Reply Last reply
                  0
                  • N Nish Nishant

                    I don't understand why FileRead is passed a BackgroundWorker argument. Shouldn't FileRead be called from the worker thread's DoWork event? And secondly, you cannot pass a managed reference through a void*. Instead create a delegate with managed arguments, and convert that to a function pointer before invoking the native FileRead method (so when the native FileRead invokes the native callback, what gets called eventually is your managed delegate handler). In the managed version, make the 2nd argument an Object^ (so that it can represent a BackgroundWorker). Hope that made sense.

                    Regards, Nish


                    My technology blog: voidnish.wordpress.com Code Project Forums : New Posts Monitor This application monitors for new posts in the Code Project forums.

                    A Offline
                    A Offline
                    alleyes 0
                    wrote on last edited by
                    #9

                    FileRead is called from the DoWork event in the C# app. Just left out. As to the second... In the wrapper.h:

                    delegate bool UpdateProgressDelegate(unsigned int, Object^);

                    Wrapper::FileRead(....)

                    UpdateProgressDelegate^ upd = gcnew UpdateProgressDelegate(UpdateStatus);
                    GCHandle gch = GCHandle::Alloc(upd);
                    IntPtr ip = Marshal::GetFunctionPointerForDelegate(upd);
                    CB_UpdateStatus update = static_cast<HD_CB_UpdateStatus>(ip.ToPointer());

                    Then calling the native function:

                    Result = NativeFileRead(DataSize, Data, UpdateStatus &context);

                    Is that what you are suggesting? How does the native callback return percentcomplete through a BGW? I still need a native callback that takes the two args. Not real clear then

                    N 1 Reply Last reply
                    0
                    • A alleyes 0

                      FileRead is called from the DoWork event in the C# app. Just left out. As to the second... In the wrapper.h:

                      delegate bool UpdateProgressDelegate(unsigned int, Object^);

                      Wrapper::FileRead(....)

                      UpdateProgressDelegate^ upd = gcnew UpdateProgressDelegate(UpdateStatus);
                      GCHandle gch = GCHandle::Alloc(upd);
                      IntPtr ip = Marshal::GetFunctionPointerForDelegate(upd);
                      CB_UpdateStatus update = static_cast<HD_CB_UpdateStatus>(ip.ToPointer());

                      Then calling the native function:

                      Result = NativeFileRead(DataSize, Data, UpdateStatus &context);

                      Is that what you are suggesting? How does the native callback return percentcomplete through a BGW? I still need a native callback that takes the two args. Not real clear then

                      N Offline
                      N Offline
                      Nish Nishant
                      wrote on last edited by
                      #10

                      alleyes wrote:

                      Is that what you are suggesting? How does the native callback return percentcomplete through a BGW? I still need a native callback that takes the two args. Not real clear then

                      I quickly put together a small sample that should clarify what I am talking about. It's simplified code but you should get the gist:

                      typedef bool (*CB_UpdateStatus)(unsigned PercentComplete);

                      HRESULT NativeFileRead(size_t DataSize, BYTE* Data, CB_UpdateStatus UpdateStatus)
                      {
                      UpdateStatus(100);
                      return 0;
                      }

                      bool UpdateStatus(unsigned PercentComplete)
                      {
                      printf("From native code: %d\r\n", PercentComplete);
                      return false;
                      }

                      ref class Test
                      {
                      private:
                      BackgroundWorker^ worker;

                      public:
                      delegate bool ManagedUpdateStatus(unsigned int);

                      int FileRead(int dataSize, array<byte>^ data, ManagedUpdateStatus^ updateStatus, BackgroundWorker^ worker)
                      {
                      	pin\_ptr<ManagedUpdateStatus^> tmp =  &updateStatus;
                      	NativeFileRead(0, NULL, (CB\_UpdateStatus)Marshal::GetFunctionPointerForDelegate(updateStatus).ToPointer());  
                      
                      	return 0;
                      }
                      
                      void Foo() 
                      {
                      	worker = gcnew BackgroundWorker();
                      	worker->WorkerReportsProgress = true;
                      	worker->DoWork += gcnew DoWorkEventHandler(this, &Test::Worker\_DoWork);
                      	worker->ProgressChanged  += gcnew ProgressChangedEventHandler(this, &Test::Worker\_ProgressChanged);
                      	worker->RunWorkerAsync();
                      }
                      
                      bool DoManagedUpdateStatus(unsigned int percentage)
                      {
                      	worker->ReportProgress(percentage);
                      	return false;
                      }
                      
                      void Worker\_DoWork(Object^ sender, DoWorkEventArgs^ e)
                      {
                      	FileRead(0, nullptr, gcnew ManagedUpdateStatus(this, &Test::DoManagedUpdateStatus), (BackgroundWorker^)sender);
                      }
                      
                      void Worker\_ProgressChanged(Object^ sender, ProgressChangedEventArgs^ e)
                      {
                      	Console::WriteLine("From the worker thread : {0}", e->ProgressPercentage);
                      }
                      

                      };

                      int main(array<System::String ^> ^args)
                      {
                      NativeFileRead(0, NULL, UpdateStatus);
                      (gcnew Test())->Foo();
                      Console::ReadKey();
                      return 0;
                      }

                      Regards, Nish


                      My technology blog: voidnish.wordpress.com Code Project Forums : New Posts Monitor This application monitors for new posts in the Code Project forums.

                      A 1 Reply Last reply
                      0
                      • N Nish Nishant

                        alleyes wrote:

                        Is that what you are suggesting? How does the native callback return percentcomplete through a BGW? I still need a native callback that takes the two args. Not real clear then

                        I quickly put together a small sample that should clarify what I am talking about. It's simplified code but you should get the gist:

                        typedef bool (*CB_UpdateStatus)(unsigned PercentComplete);

                        HRESULT NativeFileRead(size_t DataSize, BYTE* Data, CB_UpdateStatus UpdateStatus)
                        {
                        UpdateStatus(100);
                        return 0;
                        }

                        bool UpdateStatus(unsigned PercentComplete)
                        {
                        printf("From native code: %d\r\n", PercentComplete);
                        return false;
                        }

                        ref class Test
                        {
                        private:
                        BackgroundWorker^ worker;

                        public:
                        delegate bool ManagedUpdateStatus(unsigned int);

                        int FileRead(int dataSize, array<byte>^ data, ManagedUpdateStatus^ updateStatus, BackgroundWorker^ worker)
                        {
                        	pin\_ptr<ManagedUpdateStatus^> tmp =  &updateStatus;
                        	NativeFileRead(0, NULL, (CB\_UpdateStatus)Marshal::GetFunctionPointerForDelegate(updateStatus).ToPointer());  
                        
                        	return 0;
                        }
                        
                        void Foo() 
                        {
                        	worker = gcnew BackgroundWorker();
                        	worker->WorkerReportsProgress = true;
                        	worker->DoWork += gcnew DoWorkEventHandler(this, &Test::Worker\_DoWork);
                        	worker->ProgressChanged  += gcnew ProgressChangedEventHandler(this, &Test::Worker\_ProgressChanged);
                        	worker->RunWorkerAsync();
                        }
                        
                        bool DoManagedUpdateStatus(unsigned int percentage)
                        {
                        	worker->ReportProgress(percentage);
                        	return false;
                        }
                        
                        void Worker\_DoWork(Object^ sender, DoWorkEventArgs^ e)
                        {
                        	FileRead(0, nullptr, gcnew ManagedUpdateStatus(this, &Test::DoManagedUpdateStatus), (BackgroundWorker^)sender);
                        }
                        
                        void Worker\_ProgressChanged(Object^ sender, ProgressChangedEventArgs^ e)
                        {
                        	Console::WriteLine("From the worker thread : {0}", e->ProgressPercentage);
                        }
                        

                        };

                        int main(array<System::String ^> ^args)
                        {
                        NativeFileRead(0, NULL, UpdateStatus);
                        (gcnew Test())->Foo();
                        Console::ReadKey();
                        return 0;
                        }

                        Regards, Nish


                        My technology blog: voidnish.wordpress.com Code Project Forums : New Posts Monitor This application monitors for new posts in the Code Project forums.

                        A Offline
                        A Offline
                        alleyes 0
                        wrote on last edited by
                        #11

                        Thank you Nish, I get the gist. The signature: typedef bool (*CB_UpdateStatus)(unsigned PercentComplete, void* context); is what I am pursuing although I appreciate the suggestion. Isn't it possible to box a managed object and get a pointer to it?

                        N 1 Reply Last reply
                        0
                        • A alleyes 0

                          Thank you Nish, I get the gist. The signature: typedef bool (*CB_UpdateStatus)(unsigned PercentComplete, void* context); is what I am pursuing although I appreciate the suggestion. Isn't it possible to box a managed object and get a pointer to it?

                          N Offline
                          N Offline
                          Nish Nishant
                          wrote on last edited by
                          #12

                          alleyes wrote:

                          Isn't it possible to box a managed object and get a pointer to it?

                          It may be theoretically doable with some hacks, pinning, gchandles, manually marshalling/copying data-bytes etc. but I've never seen anyone marshal a managed object through a native callback via a native pointer and then marshal it back to a managed object. In your example, there's no real need to do it that way, unless what you showed me was a very simplified version, and your actual code is way more complicated and for some reason cannot access a member field?

                          Regards, Nish


                          My technology blog: voidnish.wordpress.com Code Project Forums : New Posts Monitor This application monitors for new posts in the Code Project forums.

                          A 1 Reply Last reply
                          0
                          • N Nish Nishant

                            alleyes wrote:

                            Isn't it possible to box a managed object and get a pointer to it?

                            It may be theoretically doable with some hacks, pinning, gchandles, manually marshalling/copying data-bytes etc. but I've never seen anyone marshal a managed object through a native callback via a native pointer and then marshal it back to a managed object. In your example, there's no real need to do it that way, unless what you showed me was a very simplified version, and your actual code is way more complicated and for some reason cannot access a member field?

                            Regards, Nish


                            My technology blog: voidnish.wordpress.com Code Project Forums : New Posts Monitor This application monitors for new posts in the Code Project forums.

                            A Offline
                            A Offline
                            alleyes 0
                            wrote on last edited by
                            #13

                            gcroot/auto_gcroot templates?

                            struct MyStruct
                            {
                            msclr::auto_gcroot<BackgroundWorker^> worker;
                            }

                            In the native callback

                            bool APIENTRY UpdateStatus(unsigned PercentComplete, void* Context)
                            {
                            MyStruct* strct = context;
                            strct->worker->ReportProgress(PercentComplete);
                            return false;
                            }

                            In the call to the managed FileRead, pass the BackgroundWorker to the Context arg of the NativeFileRead That's what I am talking about.

                            N 1 Reply Last reply
                            0
                            • A alleyes 0

                              gcroot/auto_gcroot templates?

                              struct MyStruct
                              {
                              msclr::auto_gcroot<BackgroundWorker^> worker;
                              }

                              In the native callback

                              bool APIENTRY UpdateStatus(unsigned PercentComplete, void* Context)
                              {
                              MyStruct* strct = context;
                              strct->worker->ReportProgress(PercentComplete);
                              return false;
                              }

                              In the call to the managed FileRead, pass the BackgroundWorker to the Context arg of the NativeFileRead That's what I am talking about.

                              N Offline
                              N Offline
                              Nish Nishant
                              wrote on last edited by
                              #14

                              Okay, that means you are invoking a managed call from your "native" callback method. That defeats the purpose of wrapping this using C++/CLI in my opinion. Keep your native code native. If for some reason you do not want to invoke the worker via the member field (maybe due to some peculiarity in your design), you could do this:

                              typedef bool (*CB_UpdateStatus)(unsigned PercentComplete, void* pContext);

                              HRESULT NativeFileRead(size_t DataSize, BYTE* Data, CB_UpdateStatus UpdateStatus, void* pContext)
                              {
                              UpdateStatus(100, pContext);
                              return 0;
                              }

                              struct MyStruct
                              {
                              auto_gcroot<BackgroundWorker^> worker;
                              };

                              In the ref class:

                              int FileRead(int dataSize, array<byte>^ data, ManagedUpdateStatus^ updateStatus, BackgroundWorker^ worker)
                              {
                              pin_ptr<ManagedUpdateStatus^> tmp = &updateStatus;
                              MyStruct myStruct;
                              myStruct.worker = worker;
                              NativeFileRead(0, NULL, (CB_UpdateStatus)Marshal::GetFunctionPointerForDelegate(updateStatus).ToPointer(), &myStruct);
                              return 0;
                              }

                              bool DoManagedUpdateStatus(unsigned int percentage, IntPtr pContext)
                              {
                              MyStruct* pMyStruct = (MyStruct*)pContext.ToPointer();
                              pMyStruct->worker->ReportProgress(percentage);
                              return false;
                              }

                              This way you native code does not need to know of the managed code, and you still end up invoking the worker's progress event.

                              Regards, Nish


                              My technology blog: voidnish.wordpress.com Code Project Forums : New Posts Monitor This application monitors for new posts in the Code Project forums.

                              A 1 Reply Last reply
                              0
                              • N Nish Nishant

                                Okay, that means you are invoking a managed call from your "native" callback method. That defeats the purpose of wrapping this using C++/CLI in my opinion. Keep your native code native. If for some reason you do not want to invoke the worker via the member field (maybe due to some peculiarity in your design), you could do this:

                                typedef bool (*CB_UpdateStatus)(unsigned PercentComplete, void* pContext);

                                HRESULT NativeFileRead(size_t DataSize, BYTE* Data, CB_UpdateStatus UpdateStatus, void* pContext)
                                {
                                UpdateStatus(100, pContext);
                                return 0;
                                }

                                struct MyStruct
                                {
                                auto_gcroot<BackgroundWorker^> worker;
                                };

                                In the ref class:

                                int FileRead(int dataSize, array<byte>^ data, ManagedUpdateStatus^ updateStatus, BackgroundWorker^ worker)
                                {
                                pin_ptr<ManagedUpdateStatus^> tmp = &updateStatus;
                                MyStruct myStruct;
                                myStruct.worker = worker;
                                NativeFileRead(0, NULL, (CB_UpdateStatus)Marshal::GetFunctionPointerForDelegate(updateStatus).ToPointer(), &myStruct);
                                return 0;
                                }

                                bool DoManagedUpdateStatus(unsigned int percentage, IntPtr pContext)
                                {
                                MyStruct* pMyStruct = (MyStruct*)pContext.ToPointer();
                                pMyStruct->worker->ReportProgress(percentage);
                                return false;
                                }

                                This way you native code does not need to know of the managed code, and you still end up invoking the worker's progress event.

                                Regards, Nish


                                My technology blog: voidnish.wordpress.com Code Project Forums : New Posts Monitor This application monitors for new posts in the Code Project forums.

                                A Offline
                                A Offline
                                alleyes 0
                                wrote on last edited by
                                #15

                                Nish, Please understand, I AM of the opinion to keep native code just that - native. My wrapper being a mixed mode design straddles both. That is why I place the native struct with manged object. Isn't your post of putting the native struct with managed member in native code outside of that perspective? There is really no peculiarity of design. The native function works fine when a NULL is passed to pContext. The native callback writes to stdout in a native console app. It is the wrapping of the native function that required an additional arg be added so the use of a background worker can be used. Thanks very much for all the invaluable help. I wished more was covered on this topic in your book.

                                N 1 Reply Last reply
                                0
                                • A alleyes 0

                                  Nish, Please understand, I AM of the opinion to keep native code just that - native. My wrapper being a mixed mode design straddles both. That is why I place the native struct with manged object. Isn't your post of putting the native struct with managed member in native code outside of that perspective? There is really no peculiarity of design. The native function works fine when a NULL is passed to pContext. The native callback writes to stdout in a native console app. It is the wrapping of the native function that required an additional arg be added so the use of a background worker can be used. Thanks very much for all the invaluable help. I wished more was covered on this topic in your book.

                                  N Offline
                                  N Offline
                                  Nish Nishant
                                  wrote on last edited by
                                  #16

                                  alleyes wrote:

                                  I wished more was covered on this topic in your book.

                                  Well, hindsight is always 20-20 :-)

                                  Regards, Nish


                                  My technology blog: voidnish.wordpress.com Code Project Forums : New Posts Monitor This application monitors for new posts in the Code Project forums.

                                  1 Reply Last reply
                                  0
                                  Reply
                                  • Reply as topic
                                  Log in to reply
                                  • Oldest to Newest
                                  • Newest to Oldest
                                  • Most Votes


                                  • Login

                                  • Don't have an account? Register

                                  • Login or register to search.
                                  • First post
                                    Last post
                                  0
                                  • Categories
                                  • Recent
                                  • Tags
                                  • Popular
                                  • World
                                  • Users
                                  • Groups