Distinguish between “fundamental” ctypes data types and subclasses thereof?2019 Community Moderator ElectionGetting method parameter names in PythonWhat are the differences between type() and isinstance()?How to use C++ classes with ctypes?Receiving non Null-Terminated data in Python Ctypes callbackAdding data to a C buffer passed to a Python Ctypes callbackc_void_p arguments in callbacks using ctypes in PythonSubclassing ctypes typesPython 3.x ctype c_wchar_p and c_char_p return status different from ctypes docHow to create c_void_p PyObject from C++, pass it to Python and retrieve it back to C++Python ctypes : create user defined types and exchange with function in dll

DisplayForm problem with pi in FractionBox

Knife as defense against stray dogs

Pre-Employment Background Check With Consent For Future Checks

Did Nintendo change its mind about 68000 SNES?

When should a starting writer get his own webpage?

CLI: Get information Ubuntu releases

Do I need an EFI partition for each 18.04 ubuntu I have on my HD?

How to test the sharpness of a knife?

Single word to change groups

What kind of footwear is suitable for walking in micro gravity environment?

The English Debate

is this saw blade faulty?

Exposing a company lying about themselves in a tightly knit industry: Is my career at risk on the long run?

Was World War I a war of liberals against authoritarians?

Do people actually use the word "kaputt" in conversation?

Writing in a Christian voice

Exit shell with shortcut (not typing exit) that closes session properly

How to find the largest number(s) in a list of elements, possibly non-unique?

What is the tangent at a sharp point on a curve?

Friend wants my recommendation but I don't want to

Would mining huge amounts of resources on the Moon change its orbit?

Should I be concerned about student access to a test bank?

Turning a hard to access nut?

Have any astronauts/cosmonauts died in space?



Distinguish between “fundamental” ctypes data types and subclasses thereof?



2019 Community Moderator ElectionGetting method parameter names in PythonWhat are the differences between type() and isinstance()?How to use C++ classes with ctypes?Receiving non Null-Terminated data in Python Ctypes callbackAdding data to a C buffer passed to a Python Ctypes callbackc_void_p arguments in callbacks using ctypes in PythonSubclassing ctypes typesPython 3.x ctype c_wchar_p and c_char_p return status different from ctypes docHow to create c_void_p PyObject from C++, pass it to Python and retrieve it back to C++Python ctypes : create user defined types and exchange with function in dll










2















Introduction



I am working on a code generator that would generate functions around ctypes.cdll loaded functions. The generator would take information about the ctypes of the arguments and the return value, and generate something that behaves (and, to some extent, looks) like this:



func = getattr(dll, 'UglyLongAndUselessCName')
func.argtypes = [ctypes.c_uint32, ctypes.c_int8, ctypes.c_char_p]
func.restype = ctypes.c_int16

def nice_python_name(handle: int, arg1: int, arg2: str) -> int:
return func(handle, arg1, arg2)


Notice how python type annotations play nicely with the ctypes data types of the function arguments. Also notice that there is no conversion code between the python types in nice_python_name function and func function. This is what my question is about.



Getting close to the problem



The ctypes docs say that if the argtypes attribute of a loaded DLL function is specified using "fundamental data types", then when calling the loaded DLL functions, ctypes will do the conversion to python types for you. This is great, because in this case my generated code will look like the example above - I won't need to explicitly convert ctypes objects to python-typed values for returned values, and the reverse for the arguments.



However, the docs also say that for "subclasses of the fundamental data types" this trick will not work, and calling a loaded DLL function will require ctypes objects for arguments, and the result will be a ctypes object.



This is the excerpt from the ctypes docs about it:




Fundamental data types, when returned as foreign function call results, or, for example, by retrieving structure field members or array items, are transparently converted to native Python types. In other words, if a foreign function has a restype of c_char_p, you will always receive a Python bytes object, not a c_char_p instance.



Subclasses of fundamental data types do not inherit this behavior. So, if a foreign functions restype is a subclass of c_void_p, you will receive an instance of this subclass from the function call. Of course, you can get the value of the pointer by accessing the value attribute.




So, I would like to get around this.



It seems that I need to know if a type is "fundamental" or a "subclass". This will help me define the way the code is generated, i.e. for "fundamental" types the generated code would look similar to the above example, and for "subclasses of fundamental" types it will have the extra conversion from ctypes objects into reasonable python types (or the generator will just throw an exception saying "this is not supported").



Question:



How can I distinguish between "fundamental ctypes data types" and "subclasses of fundamental ctypes data types"?



I looked into the code of ctypes python module and discovered that both c_void_p and c_char_p are subclasses of ctypes._SimpleCData, hence one is not a subclass of the other in any way.



Also, do I misunderstand it that this problem also applies to the input arguments, or is this only the deal for the returned values?










share|improve this question


























    2















    Introduction



    I am working on a code generator that would generate functions around ctypes.cdll loaded functions. The generator would take information about the ctypes of the arguments and the return value, and generate something that behaves (and, to some extent, looks) like this:



    func = getattr(dll, 'UglyLongAndUselessCName')
    func.argtypes = [ctypes.c_uint32, ctypes.c_int8, ctypes.c_char_p]
    func.restype = ctypes.c_int16

    def nice_python_name(handle: int, arg1: int, arg2: str) -> int:
    return func(handle, arg1, arg2)


    Notice how python type annotations play nicely with the ctypes data types of the function arguments. Also notice that there is no conversion code between the python types in nice_python_name function and func function. This is what my question is about.



    Getting close to the problem



    The ctypes docs say that if the argtypes attribute of a loaded DLL function is specified using "fundamental data types", then when calling the loaded DLL functions, ctypes will do the conversion to python types for you. This is great, because in this case my generated code will look like the example above - I won't need to explicitly convert ctypes objects to python-typed values for returned values, and the reverse for the arguments.



    However, the docs also say that for "subclasses of the fundamental data types" this trick will not work, and calling a loaded DLL function will require ctypes objects for arguments, and the result will be a ctypes object.



    This is the excerpt from the ctypes docs about it:




    Fundamental data types, when returned as foreign function call results, or, for example, by retrieving structure field members or array items, are transparently converted to native Python types. In other words, if a foreign function has a restype of c_char_p, you will always receive a Python bytes object, not a c_char_p instance.



    Subclasses of fundamental data types do not inherit this behavior. So, if a foreign functions restype is a subclass of c_void_p, you will receive an instance of this subclass from the function call. Of course, you can get the value of the pointer by accessing the value attribute.




    So, I would like to get around this.



    It seems that I need to know if a type is "fundamental" or a "subclass". This will help me define the way the code is generated, i.e. for "fundamental" types the generated code would look similar to the above example, and for "subclasses of fundamental" types it will have the extra conversion from ctypes objects into reasonable python types (or the generator will just throw an exception saying "this is not supported").



    Question:



    How can I distinguish between "fundamental ctypes data types" and "subclasses of fundamental ctypes data types"?



    I looked into the code of ctypes python module and discovered that both c_void_p and c_char_p are subclasses of ctypes._SimpleCData, hence one is not a subclass of the other in any way.



    Also, do I misunderstand it that this problem also applies to the input arguments, or is this only the deal for the returned values?










    share|improve this question
























      2












      2








      2








      Introduction



      I am working on a code generator that would generate functions around ctypes.cdll loaded functions. The generator would take information about the ctypes of the arguments and the return value, and generate something that behaves (and, to some extent, looks) like this:



      func = getattr(dll, 'UglyLongAndUselessCName')
      func.argtypes = [ctypes.c_uint32, ctypes.c_int8, ctypes.c_char_p]
      func.restype = ctypes.c_int16

      def nice_python_name(handle: int, arg1: int, arg2: str) -> int:
      return func(handle, arg1, arg2)


      Notice how python type annotations play nicely with the ctypes data types of the function arguments. Also notice that there is no conversion code between the python types in nice_python_name function and func function. This is what my question is about.



      Getting close to the problem



      The ctypes docs say that if the argtypes attribute of a loaded DLL function is specified using "fundamental data types", then when calling the loaded DLL functions, ctypes will do the conversion to python types for you. This is great, because in this case my generated code will look like the example above - I won't need to explicitly convert ctypes objects to python-typed values for returned values, and the reverse for the arguments.



      However, the docs also say that for "subclasses of the fundamental data types" this trick will not work, and calling a loaded DLL function will require ctypes objects for arguments, and the result will be a ctypes object.



      This is the excerpt from the ctypes docs about it:




      Fundamental data types, when returned as foreign function call results, or, for example, by retrieving structure field members or array items, are transparently converted to native Python types. In other words, if a foreign function has a restype of c_char_p, you will always receive a Python bytes object, not a c_char_p instance.



      Subclasses of fundamental data types do not inherit this behavior. So, if a foreign functions restype is a subclass of c_void_p, you will receive an instance of this subclass from the function call. Of course, you can get the value of the pointer by accessing the value attribute.




      So, I would like to get around this.



      It seems that I need to know if a type is "fundamental" or a "subclass". This will help me define the way the code is generated, i.e. for "fundamental" types the generated code would look similar to the above example, and for "subclasses of fundamental" types it will have the extra conversion from ctypes objects into reasonable python types (or the generator will just throw an exception saying "this is not supported").



      Question:



      How can I distinguish between "fundamental ctypes data types" and "subclasses of fundamental ctypes data types"?



      I looked into the code of ctypes python module and discovered that both c_void_p and c_char_p are subclasses of ctypes._SimpleCData, hence one is not a subclass of the other in any way.



      Also, do I misunderstand it that this problem also applies to the input arguments, or is this only the deal for the returned values?










      share|improve this question














      Introduction



      I am working on a code generator that would generate functions around ctypes.cdll loaded functions. The generator would take information about the ctypes of the arguments and the return value, and generate something that behaves (and, to some extent, looks) like this:



      func = getattr(dll, 'UglyLongAndUselessCName')
      func.argtypes = [ctypes.c_uint32, ctypes.c_int8, ctypes.c_char_p]
      func.restype = ctypes.c_int16

      def nice_python_name(handle: int, arg1: int, arg2: str) -> int:
      return func(handle, arg1, arg2)


      Notice how python type annotations play nicely with the ctypes data types of the function arguments. Also notice that there is no conversion code between the python types in nice_python_name function and func function. This is what my question is about.



      Getting close to the problem



      The ctypes docs say that if the argtypes attribute of a loaded DLL function is specified using "fundamental data types", then when calling the loaded DLL functions, ctypes will do the conversion to python types for you. This is great, because in this case my generated code will look like the example above - I won't need to explicitly convert ctypes objects to python-typed values for returned values, and the reverse for the arguments.



      However, the docs also say that for "subclasses of the fundamental data types" this trick will not work, and calling a loaded DLL function will require ctypes objects for arguments, and the result will be a ctypes object.



      This is the excerpt from the ctypes docs about it:




      Fundamental data types, when returned as foreign function call results, or, for example, by retrieving structure field members or array items, are transparently converted to native Python types. In other words, if a foreign function has a restype of c_char_p, you will always receive a Python bytes object, not a c_char_p instance.



      Subclasses of fundamental data types do not inherit this behavior. So, if a foreign functions restype is a subclass of c_void_p, you will receive an instance of this subclass from the function call. Of course, you can get the value of the pointer by accessing the value attribute.




      So, I would like to get around this.



      It seems that I need to know if a type is "fundamental" or a "subclass". This will help me define the way the code is generated, i.e. for "fundamental" types the generated code would look similar to the above example, and for "subclasses of fundamental" types it will have the extra conversion from ctypes objects into reasonable python types (or the generator will just throw an exception saying "this is not supported").



      Question:



      How can I distinguish between "fundamental ctypes data types" and "subclasses of fundamental ctypes data types"?



      I looked into the code of ctypes python module and discovered that both c_void_p and c_char_p are subclasses of ctypes._SimpleCData, hence one is not a subclass of the other in any way.



      Also, do I misunderstand it that this problem also applies to the input arguments, or is this only the deal for the returned values?







      python parameter-passing ctypes dllimport






      share|improve this question













      share|improve this question











      share|improve this question




      share|improve this question










      asked Mar 7 at 18:49









      astafan8astafan8

      6316




      6316






















          1 Answer
          1






          active

          oldest

          votes


















          1















          ... do I misunderstand it that this problem also applies to the input arguments, or is this only the deal for the returned values?




          It does not apply to input arguments, as the sequence below shows:



          >>> dll=CDLL('msvcrt')
          >>> dll.printf.argtypes = c_char_p,
          >>> dll.printf(b'abc') # Note: 3 is the return value of printf
          abc3
          >>> class LPCSTR(c_char_p): # define a subtype
          ... pass
          ...
          >>> dll.printf.argtypes = LPCSTR,
          >>> dll.printf(b'abc')
          abc3


          Conversions still work for input subtypes; however, output subtypes work differently as your doc quote mentioned:



          >>> dll.ctime.argtypes = c_void_p,
          >>> dll.ctime.restype = c_char_p
          >>> dll.ctime(byref(c_int(5)))
          b'Wed Dec 31 16:00:05 1969n'
          >>> dll.ctime.restype = LPCSTR
          >>> dll.ctime(byref(c_int(5))) # not converted to Python byte string
          LPCSTR(1989707373328)
          >>> x = dll.ctime(byref(c_int(5))) # but can get the value
          >>> x.value
          b'Wed Dec 31 16:00:05 1969n'





          share|improve this answer






















            Your Answer






            StackExchange.ifUsing("editor", function ()
            StackExchange.using("externalEditor", function ()
            StackExchange.using("snippets", function ()
            StackExchange.snippets.init();
            );
            );
            , "code-snippets");

            StackExchange.ready(function()
            var channelOptions =
            tags: "".split(" "),
            id: "1"
            ;
            initTagRenderer("".split(" "), "".split(" "), channelOptions);

            StackExchange.using("externalEditor", function()
            // Have to fire editor after snippets, if snippets enabled
            if (StackExchange.settings.snippets.snippetsEnabled)
            StackExchange.using("snippets", function()
            createEditor();
            );

            else
            createEditor();

            );

            function createEditor()
            StackExchange.prepareEditor(
            heartbeatType: 'answer',
            autoActivateHeartbeat: false,
            convertImagesToLinks: true,
            noModals: true,
            showLowRepImageUploadWarning: true,
            reputationToPostImages: 10,
            bindNavPrevention: true,
            postfix: "",
            imageUploader:
            brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
            contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
            allowUrls: true
            ,
            onDemand: true,
            discardSelector: ".discard-answer"
            ,immediatelyShowMarkdownHelp:true
            );



            );













            draft saved

            draft discarded


















            StackExchange.ready(
            function ()
            StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f55050845%2fdistinguish-between-fundamental-ctypes-data-types-and-subclasses-thereof%23new-answer', 'question_page');

            );

            Post as a guest















            Required, but never shown

























            1 Answer
            1






            active

            oldest

            votes








            1 Answer
            1






            active

            oldest

            votes









            active

            oldest

            votes






            active

            oldest

            votes









            1















            ... do I misunderstand it that this problem also applies to the input arguments, or is this only the deal for the returned values?




            It does not apply to input arguments, as the sequence below shows:



            >>> dll=CDLL('msvcrt')
            >>> dll.printf.argtypes = c_char_p,
            >>> dll.printf(b'abc') # Note: 3 is the return value of printf
            abc3
            >>> class LPCSTR(c_char_p): # define a subtype
            ... pass
            ...
            >>> dll.printf.argtypes = LPCSTR,
            >>> dll.printf(b'abc')
            abc3


            Conversions still work for input subtypes; however, output subtypes work differently as your doc quote mentioned:



            >>> dll.ctime.argtypes = c_void_p,
            >>> dll.ctime.restype = c_char_p
            >>> dll.ctime(byref(c_int(5)))
            b'Wed Dec 31 16:00:05 1969n'
            >>> dll.ctime.restype = LPCSTR
            >>> dll.ctime(byref(c_int(5))) # not converted to Python byte string
            LPCSTR(1989707373328)
            >>> x = dll.ctime(byref(c_int(5))) # but can get the value
            >>> x.value
            b'Wed Dec 31 16:00:05 1969n'





            share|improve this answer



























              1















              ... do I misunderstand it that this problem also applies to the input arguments, or is this only the deal for the returned values?




              It does not apply to input arguments, as the sequence below shows:



              >>> dll=CDLL('msvcrt')
              >>> dll.printf.argtypes = c_char_p,
              >>> dll.printf(b'abc') # Note: 3 is the return value of printf
              abc3
              >>> class LPCSTR(c_char_p): # define a subtype
              ... pass
              ...
              >>> dll.printf.argtypes = LPCSTR,
              >>> dll.printf(b'abc')
              abc3


              Conversions still work for input subtypes; however, output subtypes work differently as your doc quote mentioned:



              >>> dll.ctime.argtypes = c_void_p,
              >>> dll.ctime.restype = c_char_p
              >>> dll.ctime(byref(c_int(5)))
              b'Wed Dec 31 16:00:05 1969n'
              >>> dll.ctime.restype = LPCSTR
              >>> dll.ctime(byref(c_int(5))) # not converted to Python byte string
              LPCSTR(1989707373328)
              >>> x = dll.ctime(byref(c_int(5))) # but can get the value
              >>> x.value
              b'Wed Dec 31 16:00:05 1969n'





              share|improve this answer

























                1












                1








                1








                ... do I misunderstand it that this problem also applies to the input arguments, or is this only the deal for the returned values?




                It does not apply to input arguments, as the sequence below shows:



                >>> dll=CDLL('msvcrt')
                >>> dll.printf.argtypes = c_char_p,
                >>> dll.printf(b'abc') # Note: 3 is the return value of printf
                abc3
                >>> class LPCSTR(c_char_p): # define a subtype
                ... pass
                ...
                >>> dll.printf.argtypes = LPCSTR,
                >>> dll.printf(b'abc')
                abc3


                Conversions still work for input subtypes; however, output subtypes work differently as your doc quote mentioned:



                >>> dll.ctime.argtypes = c_void_p,
                >>> dll.ctime.restype = c_char_p
                >>> dll.ctime(byref(c_int(5)))
                b'Wed Dec 31 16:00:05 1969n'
                >>> dll.ctime.restype = LPCSTR
                >>> dll.ctime(byref(c_int(5))) # not converted to Python byte string
                LPCSTR(1989707373328)
                >>> x = dll.ctime(byref(c_int(5))) # but can get the value
                >>> x.value
                b'Wed Dec 31 16:00:05 1969n'





                share|improve this answer














                ... do I misunderstand it that this problem also applies to the input arguments, or is this only the deal for the returned values?




                It does not apply to input arguments, as the sequence below shows:



                >>> dll=CDLL('msvcrt')
                >>> dll.printf.argtypes = c_char_p,
                >>> dll.printf(b'abc') # Note: 3 is the return value of printf
                abc3
                >>> class LPCSTR(c_char_p): # define a subtype
                ... pass
                ...
                >>> dll.printf.argtypes = LPCSTR,
                >>> dll.printf(b'abc')
                abc3


                Conversions still work for input subtypes; however, output subtypes work differently as your doc quote mentioned:



                >>> dll.ctime.argtypes = c_void_p,
                >>> dll.ctime.restype = c_char_p
                >>> dll.ctime(byref(c_int(5)))
                b'Wed Dec 31 16:00:05 1969n'
                >>> dll.ctime.restype = LPCSTR
                >>> dll.ctime(byref(c_int(5))) # not converted to Python byte string
                LPCSTR(1989707373328)
                >>> x = dll.ctime(byref(c_int(5))) # but can get the value
                >>> x.value
                b'Wed Dec 31 16:00:05 1969n'






                share|improve this answer












                share|improve this answer



                share|improve this answer










                answered Mar 7 at 22:58









                Mark TolonenMark Tolonen

                95.4k12115177




                95.4k12115177





























                    draft saved

                    draft discarded
















































                    Thanks for contributing an answer to Stack Overflow!


                    • Please be sure to answer the question. Provide details and share your research!

                    But avoid


                    • Asking for help, clarification, or responding to other answers.

                    • Making statements based on opinion; back them up with references or personal experience.

                    To learn more, see our tips on writing great answers.




                    draft saved


                    draft discarded














                    StackExchange.ready(
                    function ()
                    StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f55050845%2fdistinguish-between-fundamental-ctypes-data-types-and-subclasses-thereof%23new-answer', 'question_page');

                    );

                    Post as a guest















                    Required, but never shown





















































                    Required, but never shown














                    Required, but never shown












                    Required, but never shown







                    Required, but never shown

































                    Required, but never shown














                    Required, but never shown












                    Required, but never shown







                    Required, but never shown







                    Popular posts from this blog

                    Identity Server 4 is not redirecting to Angular app after login2019 Community Moderator ElectionIdentity Server 4 and dockerIdentityserver implicit flow unauthorized_clientIdentityServer Hybrid Flow - Access Token is null after user successful loginIdentity Server to MVC client : Page Redirect After loginLogin with Steam OpenId(oidc-client-js)Identity Server 4+.NET Core 2.0 + IdentityIdentityServer4 post-login redirect not working in Edge browserCall to IdentityServer4 generates System.NullReferenceException: Object reference not set to an instance of an objectIdentityServer4 without HTTPS not workingHow to get Authorization code from identity server without login form

                    2005 Ahvaz unrest Contents Background Causes Casualties Aftermath See also References Navigation menue"At Least 10 Are Killed by Bombs in Iran""Iran"Archived"Arab-Iranians in Iran to make April 15 'Day of Fury'"State of Mind, State of Order: Reactions to Ethnic Unrest in the Islamic Republic of Iran.10.1111/j.1754-9469.2008.00028.x"Iran hangs Arab separatists"Iran Overview from ArchivedConstitution of the Islamic Republic of Iran"Tehran puzzled by forged 'riots' letter""Iran and its minorities: Down in the second class""Iran: Handling Of Ahvaz Unrest Could End With Televised Confessions""Bombings Rock Iran Ahead of Election""Five die in Iran ethnic clashes""Iran: Need for restraint as anniversary of unrest in Khuzestan approaches"Archived"Iranian Sunni protesters killed in clashes with security forces"Archived

                    Can't initialize raids on a new ASUS Prime B360M-A motherboard2019 Community Moderator ElectionSimilar to RAID config yet more like mirroring solution?Can't get motherboard serial numberWhy does the BIOS entry point start with a WBINVD instruction?UEFI performance Asus Maximus V Extreme