Author: Armin Rigo <ar...@tunes.org>
Branch: 
Changeset: r1620:b3b479ff6ebc
Date: 2015-01-07 18:38 +0100
http://bitbucket.org/cffi/cffi/changeset/b3b479ff6ebc/

Log:    issue #172

        Fix an inconsistency: the define "UNICODE" must be present
        explicitly iff we're declaring TCHAR to be a wchar_t.

diff --git a/cffi/api.py b/cffi/api.py
--- a/cffi/api.py
+++ b/cffi/api.py
@@ -69,6 +69,7 @@
         self._function_caches = []
         self._libraries = []
         self._cdefsources = []
+        self._windows_unicode = None
         if hasattr(backend, 'set_ffi'):
             backend.set_ffi(self)
         for name in backend.__dict__:
@@ -347,6 +348,8 @@
         which requires binary compatibility in the signatures.
         """
         from .verifier import Verifier
+        if self._windows_unicode:
+            self._apply_windows_unicode(kwargs)
         self.verifier = Verifier(self, source, tmpdir, **kwargs)
         lib = self.verifier.load_library()
         self._libraries.append(lib)
@@ -408,6 +411,43 @@
     def from_handle(self, x):
         return self._backend.from_handle(x)
 
+    def set_unicode(self, unicode_enabled):
+        """Windows: if 'unicode_enabled' is True, enable the UNICODE and
+        _UNICODE defines in C, and declare the types like TCHAR and LPTCSTR
+        to be (pointers to) wchar_t.  If 'unicode_enabled' is False,
+        declare these types to be (pointers to) plain 8-bit characters.
+        This is mostly for backward compatibility; you usually want True.
+        """
+        if self._windows_unicode is not None:
+            raise ValueError("set_unicode() can only be called once")
+        if unicode_enabled:
+            self.cdef("typedef wchar_t TBYTE;"
+                      "typedef wchar_t TCHAR;"
+                      "typedef const wchar_t *LPCTSTR;"
+                      "typedef const wchar_t *PCTSTR;"
+                      "typedef wchar_t *LPTSTR;"
+                      "typedef wchar_t *PTSTR;"
+                      "typedef TBYTE *PTBYTE;"
+                      "typedef TCHAR *PTCHAR;")
+        else:
+            self.cdef("typedef char TBYTE;"
+                      "typedef char TCHAR;"
+                      "typedef const char *LPCTSTR;"
+                      "typedef const char *PCTSTR;"
+                      "typedef char *LPTSTR;"
+                      "typedef char *PTSTR;"
+                      "typedef TBYTE *PTBYTE;"
+                      "typedef TCHAR *PTCHAR;")
+        self._windows_unicode = unicode_enabled
+
+    def _apply_windows_unicode(self, kwds):
+        defmacros = kwds.get('define_macros', ())
+        if not isinstance(defmacros, (list, tuple)):
+            raise TypeError("'define_macros' must be a list or tuple")
+        defmacros = list(defmacros) + [('UNICODE', '1'),
+                                       ('_UNICODE', '1')]
+        kwds['define_macros'] = defmacros
+
 
 def _load_backend_lib(backend, name, flags):
     if name is None:
diff --git a/cffi/commontypes.py b/cffi/commontypes.py
--- a/cffi/commontypes.py
+++ b/cffi/commontypes.py
@@ -86,8 +86,6 @@
         "ULONGLONG": "unsigned long long",
         "WCHAR": "wchar_t",
         "SHORT": "short",
-        "TBYTE": "WCHAR",
-        "TCHAR": "WCHAR",
         "UCHAR": "unsigned char",
         "UINT": "unsigned int",
         "UINT8": "unsigned char",
@@ -157,14 +155,12 @@
 
         "LPCVOID": model.const_voidp_type,
         "LPCWSTR": "const WCHAR *",
-        "LPCTSTR": "LPCWSTR",
         "LPDWORD": "DWORD *",
         "LPHANDLE": "HANDLE *",
         "LPINT": "int *",
         "LPLONG": "long *",
         "LPSTR": "CHAR *",
         "LPWSTR": "WCHAR *",
-        "LPTSTR": "LPWSTR",
         "LPVOID": model.voidp_type,
         "LPWORD": "WORD *",
         "LRESULT": "LONG_PTR",
@@ -173,7 +169,6 @@
         "PBYTE": "BYTE *",
         "PCHAR": "CHAR *",
         "PCSTR": "const CHAR *",
-        "PCTSTR": "LPCWSTR",
         "PCWSTR": "const WCHAR *",
         "PDWORD": "DWORD *",
         "PDWORDLONG": "DWORDLONG *",
@@ -200,9 +195,6 @@
         "PSIZE_T": "SIZE_T *",
         "PSSIZE_T": "SSIZE_T *",
         "PSTR": "CHAR *",
-        "PTBYTE": "TBYTE *",
-        "PTCHAR": "TCHAR *",
-        "PTSTR": "LPWSTR",
         "PUCHAR": "UCHAR *",
         "PUHALF_PTR": "UHALF_PTR *",
         "PUINT": "UINT *",
diff --git a/testing/test_verify.py b/testing/test_verify.py
--- a/testing/test_verify.py
+++ b/testing/test_verify.py
@@ -2086,3 +2086,31 @@
     assert str(e.value) == (
         "ctype 'MyStr' not supported as argument or return value "
         "(it is a struct with bit fields)")
+
+def test_verify_extra_arguments():
+    ffi = FFI()
+    ffi.cdef("#define ABA ...")
+    lib = ffi.verify("", define_macros=[('ABA', '42')])
+    assert lib.ABA == 42
+
+def test_implicit_unicode_on_windows():
+    if sys.platform != 'win32':
+        py.test.skip("win32-only test")
+    for with_unicode in [True, False]:
+        ffi = FFI()
+        ffi.set_unicode(with_unicode)
+        ffi.cdef("""
+            DWORD GetModuleFileName(HMODULE hModule, LPTSTR lpFilename,
+                                    DWORD nSize);
+        """)
+        lib = ffi.verify("""
+            #include <windows.h>
+        """, libraries=['Kernel32'])
+        outbuf = ffi.new("TCHAR[]", 200)
+        n = lib.GetModuleFileName(ffi.NULL, outbuf, 500)
+        assert 0 < n < 500
+        for i in range(n):
+            print repr(outbuf[i])
+            assert ord(outbuf[i]) != 0
+        assert ord(outbuf[n]) == 0
+        assert ord(outbuf[0]) < 128     # should be a letter, or '\'
_______________________________________________
pypy-commit mailing list
pypy-commit@python.org
https://mail.python.org/mailman/listinfo/pypy-commit

Reply via email to