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
CODE PROJECT For Those Who Code
  • Home
  • Articles
  • FAQ
Community
  1. Home
  2. General Programming
  3. Managed C++/CLI
  4. Access controls from other modules of a program

Access controls from other modules of a program

Scheduled Pinned Locked Moved Managed C++/CLI
c++questionwinformshelp
9 Posts 2 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.
  • E Offline
    E Offline
    eugk
    wrote on last edited by
    #1

    I created a Windows Forms Application, put a TextBox and a Button on it. When I press the Button its event handler calls a function in another CPP module in my project that does the whole bunch of work. As it is doing that work I want it to send some progress text messages to the TextBox on the Form. How can I do this? This was a simple task before as I just used pointers, but with Managed C++ I just can't figure it out. Can somebody help, please?

    M 1 Reply Last reply
    0
    • E eugk

      I created a Windows Forms Application, put a TextBox and a Button on it. When I press the Button its event handler calls a function in another CPP module in my project that does the whole bunch of work. As it is doing that work I want it to send some progress text messages to the TextBox on the Form. How can I do this? This was a simple task before as I just used pointers, but with Managed C++ I just can't figure it out. Can somebody help, please?

      M Offline
      M Offline
      mid 5741
      wrote on last edited by
      #2

      Take a look at GetFunctionPointerForDelegate() in MSDN. You define a delegate in managed code, get a function pointer for it, cast it as function pointer for the native function, and then hand it off to the native code to use as a callback into your managed code.

      E 1 Reply Last reply
      0
      • M mid 5741

        Take a look at GetFunctionPointerForDelegate() in MSDN. You define a delegate in managed code, get a function pointer for it, cast it as function pointer for the native function, and then hand it off to the native code to use as a callback into your managed code.

        E Offline
        E Offline
        eugk
        wrote on last edited by
        #3

        Michael, thanks a lot for your reply. I did try delegates even before my desperate call for help and now I tried it again, but still no luck. Here is what I put on top of my Form1.h: delegate void MyFormMethod (void); // declare the delegate. typedef void (*PFUNC)(void); // type for the method I want to call from outside. PFUNC pFunc (void); // actually create a public pointer for my method. Then in the form's constructor I do this: public: Form1(void) { InitializeComponent(); MyFormMethod^ m = gcnew MyFormMethod(this, &Form1::MyMethod); // create instance of my delegate. IntPtr pint = Marshal::GetFunctionPointerForDelegate (m); // get the pointer my method. PFUNC pFunc = (PFUNC)pint.ToPointer (); // save it in the global pointer. } So far so good, but if I try to use pFunc () anywhere in the code the program does not link. Even if I use it in the same Form's Button handler I get an error: error LNK2028: unresolved token (0A00000A) "void (__clrcall*__clrcall pFunc(void))(void)" (?pFunc@@$$FYMP6MXXZXZ) referenced in function "private: void __clrcall My2::Form1::button1_Click(class System::Object ^,class System::EventArgs ^)" (?button1_Click@Form1@My2@@$$FA$AAMXP$AAVObject@System@@P$AAVEventArgs@4@@Z) There is just no simple example anywhere that I could start from. I saw the console app examples where they create a delegate in the main() function and then use it in that main() function. That works, but when I try to move the same concept into my form...:confused: There should be some obvious problem in my understanding of things, could you please point me to it? Many thanks! Eugene

        M 1 Reply Last reply
        0
        • E eugk

          Michael, thanks a lot for your reply. I did try delegates even before my desperate call for help and now I tried it again, but still no luck. Here is what I put on top of my Form1.h: delegate void MyFormMethod (void); // declare the delegate. typedef void (*PFUNC)(void); // type for the method I want to call from outside. PFUNC pFunc (void); // actually create a public pointer for my method. Then in the form's constructor I do this: public: Form1(void) { InitializeComponent(); MyFormMethod^ m = gcnew MyFormMethod(this, &Form1::MyMethod); // create instance of my delegate. IntPtr pint = Marshal::GetFunctionPointerForDelegate (m); // get the pointer my method. PFUNC pFunc = (PFUNC)pint.ToPointer (); // save it in the global pointer. } So far so good, but if I try to use pFunc () anywhere in the code the program does not link. Even if I use it in the same Form's Button handler I get an error: error LNK2028: unresolved token (0A00000A) "void (__clrcall*__clrcall pFunc(void))(void)" (?pFunc@@$$FYMP6MXXZXZ) referenced in function "private: void __clrcall My2::Form1::button1_Click(class System::Object ^,class System::EventArgs ^)" (?button1_Click@Form1@My2@@$$FA$AAMXP$AAVObject@System@@P$AAVEventArgs@4@@Z) There is just no simple example anywhere that I could start from. I saw the console app examples where they create a delegate in the main() function and then use it in that main() function. That works, but when I try to move the same concept into my form...:confused: There should be some obvious problem in my understanding of things, could you please point me to it? Many thanks! Eugene

          M Offline
          M Offline
          mid 5741
          wrote on last edited by
          #4

          I highly recommend getting Nishant Sivakumar's "C++/CLI In Action" book if you're looking for examples. He covers a lot of confusing stuff with remarkable clarity and brevity. How are you using pFunc? It's a pointer for the native code to use. If you want to use a native function pointer, you'd use GetDelegateForFunctionPointer() in managed code. Also, I'm not certain, but I'm concerned about the scope of your variables. When m goes out of the scope of Form1(void) it may be garbage collected.

          E 1 Reply Last reply
          0
          • M mid 5741

            I highly recommend getting Nishant Sivakumar's "C++/CLI In Action" book if you're looking for examples. He covers a lot of confusing stuff with remarkable clarity and brevity. How are you using pFunc? It's a pointer for the native code to use. If you want to use a native function pointer, you'd use GetDelegateForFunctionPointer() in managed code. Also, I'm not certain, but I'm concerned about the scope of your variables. When m goes out of the scope of Form1(void) it may be garbage collected.

            E Offline
            E Offline
            eugk
            wrote on last edited by
            #5

            Thanks, the book I am working with now is "Pro Visual C++/CLI" by Stephen Fraser, but I will look into the book you recommend too. I see, I guess I am trying to use pFunc() in the managed code itself. But you know, it actually works if I call pFunc() right at the end of the Form constructor. I get a warning message box that it is unsafe to call function pointers from managed code, but when I click "Continue" the pFunc() is actually called, it does its work and returns properly. However, if I call pFunc() from the Button handler of the Form or from elsewhere the project does not even build:

            public:
            Form1(void)
            {
            InitializeComponent();

                MyFormMethod^ m = gcnew MyFormMethod(this, &Form1::MyMethod); // create instance of my delegate.
                IntPtr pint = Marshal::GetFunctionPointerForDelegate (m); // get the pointer my method.
                PFUNC pFunc = (PFUNC)pint.ToPointer (); // save it in the global pointer.
                `**pFunc();**                   // works.`
            }
            

            private: System::Void button1_Click(System::Object^ sender, System::EventArgs^ e) {
            **pFunc();** // does not link, unresolved external pFunc.
            }

            It's a good point about m garbage collected at some point. Although it should be OK since I only needed it at the time I extracted pointer out of it. Then the pointer is stored in pFunc, which is global and should not get deallocated. By the way, should we be even talking about calls between managed/unmanaged code here? My test app in my example is just a plain WinFormsApp "Hello World" example (should be all "managed") with a few mods: I put function foo() in my WinFormsApp.CPP with the code to access something on the form (in Form1.h), say a textBox. I press the button to call foo() and foo() writes some text, that's it. I cannot use Form1::textBox::Text = "Text" in foo(), I tried to create a new public method in my Form that does this->textBox->Text = "Text", but the compiler says "cannot access a non-static member". OK, I make my method static but then I cannot access the textBox from it anymore: error C2597: illegal reference to non-static member 'System::Windows::Forms::Form::Text'. Of course, I will keep reading and searching for the example that does exactly what I am trying to do, but the solution to my problem should be very simple. Maybe it is so simple that they do n

            M 1 Reply Last reply
            0
            • E eugk

              Thanks, the book I am working with now is "Pro Visual C++/CLI" by Stephen Fraser, but I will look into the book you recommend too. I see, I guess I am trying to use pFunc() in the managed code itself. But you know, it actually works if I call pFunc() right at the end of the Form constructor. I get a warning message box that it is unsafe to call function pointers from managed code, but when I click "Continue" the pFunc() is actually called, it does its work and returns properly. However, if I call pFunc() from the Button handler of the Form or from elsewhere the project does not even build:

              public:
              Form1(void)
              {
              InitializeComponent();

                  MyFormMethod^ m = gcnew MyFormMethod(this, &Form1::MyMethod); // create instance of my delegate.
                  IntPtr pint = Marshal::GetFunctionPointerForDelegate (m); // get the pointer my method.
                  PFUNC pFunc = (PFUNC)pint.ToPointer (); // save it in the global pointer.
                  `**pFunc();**                   // works.`
              }
              

              private: System::Void button1_Click(System::Object^ sender, System::EventArgs^ e) {
              **pFunc();** // does not link, unresolved external pFunc.
              }

              It's a good point about m garbage collected at some point. Although it should be OK since I only needed it at the time I extracted pointer out of it. Then the pointer is stored in pFunc, which is global and should not get deallocated. By the way, should we be even talking about calls between managed/unmanaged code here? My test app in my example is just a plain WinFormsApp "Hello World" example (should be all "managed") with a few mods: I put function foo() in my WinFormsApp.CPP with the code to access something on the form (in Form1.h), say a textBox. I press the button to call foo() and foo() writes some text, that's it. I cannot use Form1::textBox::Text = "Text" in foo(), I tried to create a new public method in my Form that does this->textBox->Text = "Text", but the compiler says "cannot access a non-static member". OK, I make my method static but then I cannot access the textBox from it anymore: error C2597: illegal reference to non-static member 'System::Windows::Forms::Form::Text'. Of course, I will keep reading and searching for the example that does exactly what I am trying to do, but the solution to my problem should be very simple. Maybe it is so simple that they do n

              M Offline
              M Offline
              mid 5741
              wrote on last edited by
              #6

              I'm sorry. I took "This was a simple task before as I just used pointers" to mean that you had existing native C++ code calling the C++ module that does all the work and were moving that existing code into C++/CLI. In your case, you can define an event to update the text:

              delegate void UpdateText( String^ );

              ref class SomeClass
              {
              public:
              event UpdateText^ OnUpdateText;
              };

              public ref class Form1 : Form
              {
              public:

              Form1()
              {
                InitializeComponent();
                
                someClass\_ = gcnew SomeClass();
                
                someClass\_->OnUpdateText += gcnew UpdateText( this, &Form1::UpdateTextHandler );
              }
              

              private:

              SomeClass^ someClass\_;
              
              void UpdateTextHandler( String^ text )
              {
                textBox->Text = text;
              }
              

              };

              In the implementation of SomeClass, call OnUpdateText( "New text" ) when you want to update the text. -- modified at 22:59 Monday 13th August, 2007 [Some corrections made to above code.]

              E 1 Reply Last reply
              0
              • M mid 5741

                I'm sorry. I took "This was a simple task before as I just used pointers" to mean that you had existing native C++ code calling the C++ module that does all the work and were moving that existing code into C++/CLI. In your case, you can define an event to update the text:

                delegate void UpdateText( String^ );

                ref class SomeClass
                {
                public:
                event UpdateText^ OnUpdateText;
                };

                public ref class Form1 : Form
                {
                public:

                Form1()
                {
                  InitializeComponent();
                  
                  someClass\_ = gcnew SomeClass();
                  
                  someClass\_->OnUpdateText += gcnew UpdateText( this, &Form1::UpdateTextHandler );
                }
                

                private:

                SomeClass^ someClass\_;
                
                void UpdateTextHandler( String^ text )
                {
                  textBox->Text = text;
                }
                

                };

                In the implementation of SomeClass, call OnUpdateText( "New text" ) when you want to update the text. -- modified at 22:59 Monday 13th August, 2007 [Some corrections made to above code.]

                E Offline
                E Offline
                eugk
                wrote on last edited by
                #7

                Well, it did not work exactly as was written, but certainly led me to the working code, thank you very much! However, the solution I finally got seems ugly to me:

                // I added public here so compiler stops giving a warning:
                // 'OnUpdateText': signature of non-private member contains assembly private
                // type 'EventTest::UpdateText'.
                public delegate void UpdateText( String^ );

                // Needed to add public here so I can use this class as a base class later.
                public ref class SomeClass
                {
                public:
                event UpdateText^ OnUpdateText;
                };

                public ref class Form1 : Form
                {
                public:
                Form1()
                {
                InitializeComponent();
                someClass_ = gcnew SomeClass();
                someClass_->OnUpdateText += gcnew UpdateText( UpdateTextHandler );
                }

                private:
                SomeClass^ someClass_;
                void UpdateTextHandler( String^ text )
                {
                textBox->Text = text;
                }

                // This is just my button handler. It calls foo() located in MyCode.CPP, which calls
                // MyClass_UpdateText(), which fires an OnUpdateText event.
                System::Void button1_Click (System::Object^ sender, System::EventArgs^ e) {
                void foo (String^ Text);
                foo ("Text for textBox");
                }

                };

                Now here is MyCode.CPP:

                #include "stdafx.h"
                #include "Form1.h"

                using namespace EventTest;

                // I had to add MyClass based on SomeClass as otherwise the compiler gives the error:
                // error C3767: 'EventTest::SomeClass::OnUpdateText::raise': candidate function(s) not accessible. I
                // looked up the error at MSDN: "Compiler Error C3767" and they had the example to avoid it via an extra
                // class MyClass.

                public ref class MyClass: public SomeClass { public: void MyClass_UpdateText (String^ Text) { SomeClass^ EventKeeper = gcnew SomeClass; EventKeeper->OnUpdateText (Text); } };

                void foo (String^ Text) {
                MyClass^ y = gcnew MyClass();
                y->MyClass_UpdateText (Text);
                }

                Question #1: does it really have to be that twisted-complicated or it is just me being a beginner? To update a property on a Form from outside the Form I need to create and delegate an event, that has to be a member of SomeClass. Then to fire this event we have to create a new MyClass based on SomeClass with the actual event handler code and create an instance of it. And only then we can raise this event. Wow! Did I

                M 1 Reply Last reply
                0
                • E eugk

                  Well, it did not work exactly as was written, but certainly led me to the working code, thank you very much! However, the solution I finally got seems ugly to me:

                  // I added public here so compiler stops giving a warning:
                  // 'OnUpdateText': signature of non-private member contains assembly private
                  // type 'EventTest::UpdateText'.
                  public delegate void UpdateText( String^ );

                  // Needed to add public here so I can use this class as a base class later.
                  public ref class SomeClass
                  {
                  public:
                  event UpdateText^ OnUpdateText;
                  };

                  public ref class Form1 : Form
                  {
                  public:
                  Form1()
                  {
                  InitializeComponent();
                  someClass_ = gcnew SomeClass();
                  someClass_->OnUpdateText += gcnew UpdateText( UpdateTextHandler );
                  }

                  private:
                  SomeClass^ someClass_;
                  void UpdateTextHandler( String^ text )
                  {
                  textBox->Text = text;
                  }

                  // This is just my button handler. It calls foo() located in MyCode.CPP, which calls
                  // MyClass_UpdateText(), which fires an OnUpdateText event.
                  System::Void button1_Click (System::Object^ sender, System::EventArgs^ e) {
                  void foo (String^ Text);
                  foo ("Text for textBox");
                  }

                  };

                  Now here is MyCode.CPP:

                  #include "stdafx.h"
                  #include "Form1.h"

                  using namespace EventTest;

                  // I had to add MyClass based on SomeClass as otherwise the compiler gives the error:
                  // error C3767: 'EventTest::SomeClass::OnUpdateText::raise': candidate function(s) not accessible. I
                  // looked up the error at MSDN: "Compiler Error C3767" and they had the example to avoid it via an extra
                  // class MyClass.

                  public ref class MyClass: public SomeClass { public: void MyClass_UpdateText (String^ Text) { SomeClass^ EventKeeper = gcnew SomeClass; EventKeeper->OnUpdateText (Text); } };

                  void foo (String^ Text) {
                  MyClass^ y = gcnew MyClass();
                  y->MyClass_UpdateText (Text);
                  }

                  Question #1: does it really have to be that twisted-complicated or it is just me being a beginner? To update a property on a Form from outside the Form I need to create and delegate an event, that has to be a member of SomeClass. Then to fire this event we have to create a new MyClass based on SomeClass with the actual event handler code and create an instance of it. And only then we can raise this event. Wow! Did I

                  M Offline
                  M Offline
                  mid 5741
                  wrote on last edited by
                  #8

                  You are definitely doing too much regarding Question #1. You don't need to create an object every time you need to fire an event. I'm sorry my example code wasn't better. I just typed it into a text editor. I should have grabbed it from a working project. Regarding Question #2, there's definitely a better way. I just stuck everything into one place for simplicity. I'd only confuse you more if I tried to describe a better way, so I'll make a working example in C++/CLI and send that to you. -- modified at 22:39 Monday 13th August, 2007 To be a little clearer and more correct, here's the form class with irrelevant stuff stripped out:

                  #include "WorkerClass.h"

                  namespace WinApp1
                  {
                  public ref class Form1 : public Form
                  {
                  public:

                    Form1()
                    {
                       InitializeComponent();
                  
                       workerClass\_ = gcnew WorkerClass();
                  
                       workerClass\_->OnUpdateText += gcnew UpdateText( this, &Form1::UpdateTextHandler );
                    }
                  

                  private:

                    TextBox^ textBox\_;
                    Button^ button\_;
                  
                    WorkerClass^ workerClass\_;
                  
                    void button\_\_Click( System::Object^ sender, System::EventArgs^ e )
                    {
                       workerClass\_->DoSomething();
                    }
                  
                    void UpdateTextHandler( String^ text )
                    {
                       textBox\_->Text = text;
                    }
                  

                  };
                  }

                  And, in another file called WorkerClass.h, here's WorkerClass, which was SomeClass in my previous example:

                  namespace WinApp1
                  {
                  delegate void UpdateText( String^ );

                  ref class WorkerClass
                  {
                  public:

                    event UpdateText^ OnUpdateText;
                  
                    void DoSomething()
                    {
                       ++serialNumber\_;
                       OnUpdateText( Convert::ToString( serialNumber\_ ) );
                    }
                  

                  private:

                    int serialNumber\_;
                  

                  };
                  }

                  You don't need to derive your class from WorkerClass. All you need is an event of type UpdateText^ to which Form1 can attach a handler.

                  E 1 Reply Last reply
                  0
                  • M mid 5741

                    You are definitely doing too much regarding Question #1. You don't need to create an object every time you need to fire an event. I'm sorry my example code wasn't better. I just typed it into a text editor. I should have grabbed it from a working project. Regarding Question #2, there's definitely a better way. I just stuck everything into one place for simplicity. I'd only confuse you more if I tried to describe a better way, so I'll make a working example in C++/CLI and send that to you. -- modified at 22:39 Monday 13th August, 2007 To be a little clearer and more correct, here's the form class with irrelevant stuff stripped out:

                    #include "WorkerClass.h"

                    namespace WinApp1
                    {
                    public ref class Form1 : public Form
                    {
                    public:

                      Form1()
                      {
                         InitializeComponent();
                    
                         workerClass\_ = gcnew WorkerClass();
                    
                         workerClass\_->OnUpdateText += gcnew UpdateText( this, &Form1::UpdateTextHandler );
                      }
                    

                    private:

                      TextBox^ textBox\_;
                      Button^ button\_;
                    
                      WorkerClass^ workerClass\_;
                    
                      void button\_\_Click( System::Object^ sender, System::EventArgs^ e )
                      {
                         workerClass\_->DoSomething();
                      }
                    
                      void UpdateTextHandler( String^ text )
                      {
                         textBox\_->Text = text;
                      }
                    

                    };
                    }

                    And, in another file called WorkerClass.h, here's WorkerClass, which was SomeClass in my previous example:

                    namespace WinApp1
                    {
                    delegate void UpdateText( String^ );

                    ref class WorkerClass
                    {
                    public:

                      event UpdateText^ OnUpdateText;
                    
                      void DoSomething()
                      {
                         ++serialNumber\_;
                         OnUpdateText( Convert::ToString( serialNumber\_ ) );
                      }
                    

                    private:

                      int serialNumber\_;
                    

                    };
                    }

                    You don't need to derive your class from WorkerClass. All you need is an event of type UpdateText^ to which Form1 can attach a handler.

                    E Offline
                    E Offline
                    eugk
                    wrote on last edited by
                    #9

                    Well, this code actually works. And the designer works too, BTW. You just saved another soul that almost started to hate the new technology :-D Thanks! Eugene

                    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