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. C / C++ / MFC
  4. porting _beginthreadex from VS2005 to VS2017

porting _beginthreadex from VS2005 to VS2017

Scheduled Pinned Locked Moved C / C++ / MFC
helpc++tutorial
12 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.
  • J Offline
    J Offline
    jimNLX
    wrote on last edited by
    #1

    I'm attempting to port some old code from VS2005 C++ to VS2017. One problem that I don't know how to address is how to convert the old _beginthreadex to what would be the correct call in 2017. VS2005 code is calling a member function that is in a class: m_sendThread = (HANDLE)_beginthreadex(NULL, 0, sendData, this, 0, &this->m_sendThreadId); I've casted it it to: m_sendThread = (HANDLE)_beginthreadex(NULL, 0, (unsigned(__stdcall *)(void *))sendData, this, 0, &this->m_sendThreadId); Code compiles but will exit with code 1073741855. The class is a class that handles winsock connections and sendData is called to start the thread once the socket has been established. I am new to classes and even newer to threaded programs so it is hard for me to say how to fix this problem. Any help would be much appreciated. Thanks.

    J L 2 Replies Last reply
    0
    • J jimNLX

      I'm attempting to port some old code from VS2005 C++ to VS2017. One problem that I don't know how to address is how to convert the old _beginthreadex to what would be the correct call in 2017. VS2005 code is calling a member function that is in a class: m_sendThread = (HANDLE)_beginthreadex(NULL, 0, sendData, this, 0, &this->m_sendThreadId); I've casted it it to: m_sendThread = (HANDLE)_beginthreadex(NULL, 0, (unsigned(__stdcall *)(void *))sendData, this, 0, &this->m_sendThreadId); Code compiles but will exit with code 1073741855. The class is a class that handles winsock connections and sendData is called to start the thread once the socket has been established. I am new to classes and even newer to threaded programs so it is hard for me to say how to fix this problem. Any help would be much appreciated. Thanks.

      J Offline
      J Offline
      Jochen Arndt
      wrote on last edited by
      #2

      The _beginthreadex() version used by your code has not changed since VC 6.0 besides the return type: VS6: _beginthread, _beginthreadex[^]:

      unsigned long _beginthreadex( void *security, unsigned stack_size, unsigned ( __stdcall *start_address )( void * ), void *arglist, unsigned initflag, unsigned *thrdaddr );

      _beginthread, _beginthreadex | Microsoft Docs[^]:

      uintptr_t _beginthreadex( // NATIVE CODE
      void *security,
      unsigned stack_size,
      unsigned ( __stdcall *start_address )( void * ),
      void *arglist,
      unsigned initflag,
      unsigned *thrdaddr
      );

      If you need to cast the start_address parameter (your sendData function) to avoid compilation errors, you should change the function declaration instead. Never use casting for such (address of function) parameters but provide correct types. An exit code of 1073741855 (0X4000001F) is not a standard error code. You might use the debugger to find out when and under which conditions your application exits with that code. I guess that the problem is not related to _beginthreadex() but to the thread function itself or even any other parts of your application.

      J 1 Reply Last reply
      0
      • J jimNLX

        I'm attempting to port some old code from VS2005 C++ to VS2017. One problem that I don't know how to address is how to convert the old _beginthreadex to what would be the correct call in 2017. VS2005 code is calling a member function that is in a class: m_sendThread = (HANDLE)_beginthreadex(NULL, 0, sendData, this, 0, &this->m_sendThreadId); I've casted it it to: m_sendThread = (HANDLE)_beginthreadex(NULL, 0, (unsigned(__stdcall *)(void *))sendData, this, 0, &this->m_sendThreadId); Code compiles but will exit with code 1073741855. The class is a class that handles winsock connections and sendData is called to start the thread once the socket has been established. I am new to classes and even newer to threaded programs so it is hard for me to say how to fix this problem. Any help would be much appreciated. Thanks.

        L Offline
        L Offline
        leon de boer
        wrote on last edited by
        #3

        You are calling a class member function you must shim it thru a static function

        #include
        class foo
        {
        public:
        void startTheThread()
        {
        // Start the thread for the sendData (we send "this" in as a parameter for shim)
        // The shim code is a static block for all your class instances hence &foo::sendData
        // It creates a class member call from the value of "this" passed in
        sendHandle = _beginthreadex(0, 0, &foo::sendData, this, 0, &this->m_sendThreadId);
        }
        private:
        void sendDataMemberCall()
        {
        /* All the real send code goes here */
        }

        static unsigned \_\_stdcall sendData(void \*p\_this)
        {
        	/\* This is just a shim to convert a thread call to a member function call \*/
        	foo\* p\_foo = static\_cast(p\_this);
        	p\_foo->sendDataMemberCall(); // call Non-static member function!
        	return 0;
        }
        uintptr\_t sendHandle;
        unsigned m\_sendThreadId;
        

        };

        As a quick explaination a non static class function has a hidden invisible pointer which you know as "this". So if you look at the member function sendDataMemberCall it looks like this to you

        void sendDataMemberCall()

        At a code level it actually looks like this

        void sendDataMemberCall (foo* this);

        The compiler pushes down a hidden pointer to the actual instance of the class object So if we had two instances foo1 and foo2 when you call sendDataMemberCall they actually do this

        sendDataMemberCall (&foo1);
        sendDataMemberCall (&foo2);

        So the problem is the format we need for the thread function doesn't match the class function and we can't make them match because of the hidden local instance push. However the thread function does allow us to pass a parameter and we pass "this" as a parameter. So now what you can do is typecast this back to a pointer to it's type and get the compiler to call the pointer member function and it will magically push our hidden pointer. So all the shim is really doing is turning function + extra parameter into push paramater call class function.

        In vino veritas

        J 2 Replies Last reply
        0
        • J Jochen Arndt

          The _beginthreadex() version used by your code has not changed since VC 6.0 besides the return type: VS6: _beginthread, _beginthreadex[^]:

          unsigned long _beginthreadex( void *security, unsigned stack_size, unsigned ( __stdcall *start_address )( void * ), void *arglist, unsigned initflag, unsigned *thrdaddr );

          _beginthread, _beginthreadex | Microsoft Docs[^]:

          uintptr_t _beginthreadex( // NATIVE CODE
          void *security,
          unsigned stack_size,
          unsigned ( __stdcall *start_address )( void * ),
          void *arglist,
          unsigned initflag,
          unsigned *thrdaddr
          );

          If you need to cast the start_address parameter (your sendData function) to avoid compilation errors, you should change the function declaration instead. Never use casting for such (address of function) parameters but provide correct types. An exit code of 1073741855 (0X4000001F) is not a standard error code. You might use the debugger to find out when and under which conditions your application exits with that code. I guess that the problem is not related to _beginthreadex() but to the thread function itself or even any other parts of your application.

          J Offline
          J Offline
          jimNLX
          wrote on last edited by
          #4

          Thank you for your time and response. I didn't know this was responded too as my email has an issue.

          1 Reply Last reply
          0
          • L leon de boer

            You are calling a class member function you must shim it thru a static function

            #include
            class foo
            {
            public:
            void startTheThread()
            {
            // Start the thread for the sendData (we send "this" in as a parameter for shim)
            // The shim code is a static block for all your class instances hence &foo::sendData
            // It creates a class member call from the value of "this" passed in
            sendHandle = _beginthreadex(0, 0, &foo::sendData, this, 0, &this->m_sendThreadId);
            }
            private:
            void sendDataMemberCall()
            {
            /* All the real send code goes here */
            }

            static unsigned \_\_stdcall sendData(void \*p\_this)
            {
            	/\* This is just a shim to convert a thread call to a member function call \*/
            	foo\* p\_foo = static\_cast(p\_this);
            	p\_foo->sendDataMemberCall(); // call Non-static member function!
            	return 0;
            }
            uintptr\_t sendHandle;
            unsigned m\_sendThreadId;
            

            };

            As a quick explaination a non static class function has a hidden invisible pointer which you know as "this". So if you look at the member function sendDataMemberCall it looks like this to you

            void sendDataMemberCall()

            At a code level it actually looks like this

            void sendDataMemberCall (foo* this);

            The compiler pushes down a hidden pointer to the actual instance of the class object So if we had two instances foo1 and foo2 when you call sendDataMemberCall they actually do this

            sendDataMemberCall (&foo1);
            sendDataMemberCall (&foo2);

            So the problem is the format we need for the thread function doesn't match the class function and we can't make them match because of the hidden local instance push. However the thread function does allow us to pass a parameter and we pass "this" as a parameter. So now what you can do is typecast this back to a pointer to it's type and get the compiler to call the pointer member function and it will magically push our hidden pointer. So all the shim is really doing is turning function + extra parameter into push paramater call class function.

            In vino veritas

            J Offline
            J Offline
            jimNLX
            wrote on last edited by
            #5

            Thank you for the response. Just getting back to working on this and will look over and try to fix with your suggestions.

            1 Reply Last reply
            0
            • L leon de boer

              You are calling a class member function you must shim it thru a static function

              #include
              class foo
              {
              public:
              void startTheThread()
              {
              // Start the thread for the sendData (we send "this" in as a parameter for shim)
              // The shim code is a static block for all your class instances hence &foo::sendData
              // It creates a class member call from the value of "this" passed in
              sendHandle = _beginthreadex(0, 0, &foo::sendData, this, 0, &this->m_sendThreadId);
              }
              private:
              void sendDataMemberCall()
              {
              /* All the real send code goes here */
              }

              static unsigned \_\_stdcall sendData(void \*p\_this)
              {
              	/\* This is just a shim to convert a thread call to a member function call \*/
              	foo\* p\_foo = static\_cast(p\_this);
              	p\_foo->sendDataMemberCall(); // call Non-static member function!
              	return 0;
              }
              uintptr\_t sendHandle;
              unsigned m\_sendThreadId;
              

              };

              As a quick explaination a non static class function has a hidden invisible pointer which you know as "this". So if you look at the member function sendDataMemberCall it looks like this to you

              void sendDataMemberCall()

              At a code level it actually looks like this

              void sendDataMemberCall (foo* this);

              The compiler pushes down a hidden pointer to the actual instance of the class object So if we had two instances foo1 and foo2 when you call sendDataMemberCall they actually do this

              sendDataMemberCall (&foo1);
              sendDataMemberCall (&foo2);

              So the problem is the format we need for the thread function doesn't match the class function and we can't make them match because of the hidden local instance push. However the thread function does allow us to pass a parameter and we pass "this" as a parameter. So now what you can do is typecast this back to a pointer to it's type and get the compiler to call the pointer member function and it will magically push our hidden pointer. So all the shim is really doing is turning function + extra parameter into push paramater call class function.

              In vino veritas

              J Offline
              J Offline
              jimNLX
              wrote on last edited by
              #6

              Thanks again for the detailed response. I attempted to apply this calling convention into my program and really got twisted up with outer errors. So I'm trying now to do this again. Still getting errors: error C2664: '_beginthreadex' : cannot convert parameter 3 from 'unsigned int (__clrcall *)(void *)' to 'unsigned int (__stdcall *)(void *)' Address of a function yields __clrcall calling convention :confused: Jim

              L 1 Reply Last reply
              0
              • J jimNLX

                Thanks again for the detailed response. I attempted to apply this calling convention into my program and really got twisted up with outer errors. So I'm trying now to do this again. Still getting errors: error C2664: '_beginthreadex' : cannot convert parameter 3 from 'unsigned int (__clrcall *)(void *)' to 'unsigned int (__stdcall *)(void *)' Address of a function yields __clrcall calling convention :confused: Jim

                L Offline
                L Offline
                leon de boer
                wrote on last edited by
                #7

                The compiler is trying to link to managed code ... see the 4 different definitions of beginthreadex _beginthread, _beginthreadex[^] You are probably compiling with the managed code probably because you have clr compilation turned on. pull down menu .... debug -> program name properties -> general tab -> No Common Language Runtime Support Turn it to "No Common Language Runtime Support" If you dont understand managed vs native code Difference between managed and unmanaged code[^] Now the funny part if you do need managed code you will have to shim the shim ... yes an irony but the pointer that is being passed has to be converted. If you can't work it out drop me a line and I will do it for you.

                In vino veritas

                J 1 Reply Last reply
                0
                • L leon de boer

                  The compiler is trying to link to managed code ... see the 4 different definitions of beginthreadex _beginthread, _beginthreadex[^] You are probably compiling with the managed code probably because you have clr compilation turned on. pull down menu .... debug -> program name properties -> general tab -> No Common Language Runtime Support Turn it to "No Common Language Runtime Support" If you dont understand managed vs native code Difference between managed and unmanaged code[^] Now the funny part if you do need managed code you will have to shim the shim ... yes an irony but the pointer that is being passed has to be converted. If you can't work it out drop me a line and I will do it for you.

                  In vino veritas

                  J Offline
                  J Offline
                  jimNLX
                  wrote on last edited by
                  #8

                  Thank again Leon. Seems like anything I change in the compiler just makes things 1000 times worse. I looks like there is going to be no easy way to get this to work and I may have to take a couple of classes to get up to speed. Thanks for all your time and thorough answers. Jim :confused:

                  L 1 Reply Last reply
                  0
                  • J jimNLX

                    Thank again Leon. Seems like anything I change in the compiler just makes things 1000 times worse. I looks like there is going to be no easy way to get this to work and I may have to take a couple of classes to get up to speed. Thanks for all your time and thorough answers. Jim :confused:

                    L Offline
                    L Offline
                    leon de boer
                    wrote on last edited by
                    #9

                    No it's not that hard it means your code contains managed code (that is all the pointers are garbage collected), so put the settings back. I can't tell because I have no idea what the code itself looks like or does you just gave us a small piece. So all the issue is that you have managed code and you need the pointer to be passed to beginthreadex to be a managed pointer and if you want me to create the shim I can.

                    In vino veritas

                    J 1 Reply Last reply
                    0
                    • L leon de boer

                      No it's not that hard it means your code contains managed code (that is all the pointers are garbage collected), so put the settings back. I can't tell because I have no idea what the code itself looks like or does you just gave us a small piece. So all the issue is that you have managed code and you need the pointer to be passed to beginthreadex to be a managed pointer and if you want me to create the shim I can.

                      In vino veritas

                      J Offline
                      J Offline
                      jimNLX
                      wrote on last edited by
                      #10

                      I really wish I didn't have to keep dragging this one, but I still don't know why this won't work. It worked perfectly fine in VS2005, but now I can't make a thread? Doesn't make sense. From what I have learned the original code was built with /CLR:pure or managed. I've tried to remove this but the error are so extensive I don't think I would ever get through them. Is there another function I can use to create the thread? Or some other way to get this thread to run without rewriting the whole thing? Any help would be much appreciated. This is where I'm at now: #include "Connection.h" #include "Packet.h" #include "Opcodes.h" using Ig::Connection; using Ig::CriticalSection; using namespace Ig; CriticalSection::CriticalSection() { ... Connection::Connection() { ... } Connection::~Connection() { // Wait for the thread to exit. exitThreads(); // Clear any pending opcodes. clearPendingOpcodes(); } bool Connection::open(const char* ip, const int port, const int timeOut) { // Make sure the threads are not already running. exitThreads(); // Setup the ports // Setup the sockets. // Set the receive socket timeout. // Set up the send address. // Setup the receive address // Change the state to connecting // Connect to the sender address. if (::connect(m_sendSocket, (sockaddr *)&m_sendAddress, sizeof(m_sendAddress)) == SOCKET_ERROR) { int error = WSAGetLastError(); closesocket(m_sendSocket); return false; } // Bind to the receiver address. if (::bind(m_receiveSocket, (sockaddr *)&m_receiveAddress, sizeof(m_receiveAddress)) == SOCKET_ERROR) { int error = WSAGetLastError(); closesocket(m_sendSocket); closesocket(m_receiveSocket); return false; } // Clear pending opcodes. clearPendingOpcodes(); // Start the threads // THIS IS WHERE ALL MY PROBLEMS BEGIN!!!!!!!!!!!!!!!!!!!!!!!!!!!! // // m_sendThread = (HANDLE)_beginthreadex(NULL, 0, sendData, this, 0, &this->m_sendThreadId); m_receiveThread = (HANDLE)_beginthreadex(NULL, 0, receiveData, this, 0, &this->m_receiveThreadId); return true; } unsigned int Connection::sendData(void* param) { bool request_thread_exit = false; ConnectionState state = Connection::connecting; // The param should be an instance of the connection class. if (param == 0) return 0; // Cast it to a connection Connection* connection = static

                      L 1 Reply Last reply
                      0
                      • J jimNLX

                        I really wish I didn't have to keep dragging this one, but I still don't know why this won't work. It worked perfectly fine in VS2005, but now I can't make a thread? Doesn't make sense. From what I have learned the original code was built with /CLR:pure or managed. I've tried to remove this but the error are so extensive I don't think I would ever get through them. Is there another function I can use to create the thread? Or some other way to get this thread to run without rewriting the whole thing? Any help would be much appreciated. This is where I'm at now: #include "Connection.h" #include "Packet.h" #include "Opcodes.h" using Ig::Connection; using Ig::CriticalSection; using namespace Ig; CriticalSection::CriticalSection() { ... Connection::Connection() { ... } Connection::~Connection() { // Wait for the thread to exit. exitThreads(); // Clear any pending opcodes. clearPendingOpcodes(); } bool Connection::open(const char* ip, const int port, const int timeOut) { // Make sure the threads are not already running. exitThreads(); // Setup the ports // Setup the sockets. // Set the receive socket timeout. // Set up the send address. // Setup the receive address // Change the state to connecting // Connect to the sender address. if (::connect(m_sendSocket, (sockaddr *)&m_sendAddress, sizeof(m_sendAddress)) == SOCKET_ERROR) { int error = WSAGetLastError(); closesocket(m_sendSocket); return false; } // Bind to the receiver address. if (::bind(m_receiveSocket, (sockaddr *)&m_receiveAddress, sizeof(m_receiveAddress)) == SOCKET_ERROR) { int error = WSAGetLastError(); closesocket(m_sendSocket); closesocket(m_receiveSocket); return false; } // Clear pending opcodes. clearPendingOpcodes(); // Start the threads // THIS IS WHERE ALL MY PROBLEMS BEGIN!!!!!!!!!!!!!!!!!!!!!!!!!!!! // // m_sendThread = (HANDLE)_beginthreadex(NULL, 0, sendData, this, 0, &this->m_sendThreadId); m_receiveThread = (HANDLE)_beginthreadex(NULL, 0, receiveData, this, 0, &this->m_receiveThreadId); return true; } unsigned int Connection::sendData(void* param) { bool request_thread_exit = false; ConnectionState state = Connection::connecting; // The param should be an instance of the connection class. if (param == 0) return 0; // Cast it to a connection Connection* connection = static

                        L Offline
                        L Offline
                        leon de boer
                        wrote on last edited by
                        #11

                        Patched code. Exchange/MSNRouteEditor_VS2017.zip at master · LdB-ECM/Exchange · GitHub[^]

                        In vino veritas

                        J 1 Reply Last reply
                        0
                        • L leon de boer

                          Patched code. Exchange/MSNRouteEditor_VS2017.zip at master · LdB-ECM/Exchange · GitHub[^]

                          In vino veritas

                          J Offline
                          J Offline
                          jimNLX
                          wrote on last edited by
                          #12

                          Leon, Thank you for all your help with getting this working. Jim

                          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