Running ctypes in Python 3

Ball python, Photo credit: Micheal McConville

I’ve been teaching myself Python lately and I’m working through a few different books to do so. One of them is Gray Hat Python by Justin Seitz. I feared it might be a little dated, but it looked like a fun way to learn.

From the very first, “Hello World!” I was already unable to get my code to run. Here’s the example:

from ctypes import *

msvcrt = cdll.msvcrt
message_string = "Hello world!\n"
msvcrt.printf("Testing: %s", message_string)

All my console printed was:

T

Hm.

It didn’t work in Eclipse, and it didn’t work with the command line (I’m on my Windows 10 machine). There were no errors thrown, and the correct function was clearly being accessed, but something was causing the function to stop after the first character. Some quality time with Google led me to several other people with this problem, people who were obviously following the same book I was and equally stumped. Unfortunately all the answers given either didn’t work for me or they were just too far over my head for me to practically sort out.

Well after banging my head against this for hours, I finally found a solution! As always seems to be the case, the problem was simple: printf in this instance works with Python 2.x and it expects strings to be encoded as bytes. By contrast, in Python 3, the version I have installed, literal strings are in unicode. I needed to find a way to get the string and the function to to speak the same encoding language. But the code solution given in the post in which I learned this discrepancy still didn’t work, nor did a few others I tried. Frustrated, and at this point having wasted 2 or 3 hours, I decided to do once last round of searches before calling it a night. That’s when I stumbled upon this post in a Python mailing list archive. Simply changing printf() to wprintf() fixed my problem! I now have a couple of different ways to get around this issue in the future!

So, for anyone else working through Gray Hat Python with Python 3, the final working solution is:

from ctypes import *

msvcrt = cdll.msvcrt
message_string = "Hello world!\n"
msvcrt.wprintf("Testing: %s", message_string)

Happy coding!