diff --git a/Pythonwin/win32util.cpp b/Pythonwin/win32util.cpp index 159b4d5fa..294301f7d 100644 --- a/Pythonwin/win32util.cpp +++ b/Pythonwin/win32util.cpp @@ -1137,8 +1137,8 @@ CString GetReprText(PyObject *objectUse) PyObject *s; CString csRet; s = PyObject_Str(objectUse); - if (s) { - csRet = CString(PyUnicode_AsUnicode(s)); + if (s) if (TmpWCHAR ts=s) { + csRet = CString(ts); Py_DECREF(s); return csRet; } @@ -1152,7 +1152,12 @@ CString GetReprText(PyObject *objectUse) // repr() should always return a unicode string, but for hysterical raisens we check if it is bytes. if (PyUnicode_Check(s)) - csRet = CString(PyUnicode_AS_UNICODE(s)); + if (TmpWCHAR ts=s) + csRet = ts; + else { + PyErr_Clear(); + csRet = L"??? wide string allocation error ???"; + } else if (PyBytes_Check(s)) csRet = CString(PyBytes_AS_STRING(s)); else diff --git a/Pythonwin/win32virt.cpp b/Pythonwin/win32virt.cpp index 63dbdefa8..2f46c8435 100644 --- a/Pythonwin/win32virt.cpp +++ b/Pythonwin/win32virt.cpp @@ -117,11 +117,9 @@ BOOL CVirtualHelper::do_call(PyObject *args) if (obRepr) { if (PyBytes_Check(obRepr)) szRepr = PyBytes_AS_STRING(obRepr); - else if (PyUnicode_Check(obRepr)) - szRepr = W2A(PyUnicode_AS_UNICODE(obRepr)); + else if (TmpWCHAR tmpw=obRepr) + szRepr = W2A(tmpw); } - else - PyErr_Clear(); LPTSTR HandlerName = csHandlerName.GetBuffer(csHandlerName.GetLength()); snprintf(msg, sizeof(msg) / sizeof(msg[0]), "%s() virtual handler (%s) raised an exception", diff --git a/com/win32com/src/extensions/PySTGMEDIUM.cpp b/com/win32com/src/extensions/PySTGMEDIUM.cpp index ebeda1c75..501b53d3e 100644 --- a/com/win32com/src/extensions/PySTGMEDIUM.cpp +++ b/com/win32com/src/extensions/PySTGMEDIUM.cpp @@ -50,6 +50,7 @@ PyObject *PySet(PyObject *self, PyObject *args) } case TYMED_HGLOBAL: { const void *buf = NULL; + TmpWCHAR tmpw; Py_ssize_t cb = 0; PyWinBufferView pybuf; // In py3k, unicode objects don't support the buffer @@ -62,8 +63,8 @@ PyObject *PySet(PyObject *self, PyObject *args) buf = (void *)PyBytes_AS_STRING(ob); } else if (PyUnicode_Check(ob)) { - cb = PyUnicode_GET_DATA_SIZE(ob) + sizeof(Py_UNICODE); - buf = (void *)PyUnicode_AS_UNICODE(ob); + buf = tmpw = ob; if (!tmpw) return NULL; + cb = (tmpw.length + 1) * sizeof(WCHAR); } else { if (!pybuf.init(ob)) diff --git a/isapi/src/PyExtensionObjects.cpp b/isapi/src/PyExtensionObjects.cpp index ea3020102..3351979dc 100644 --- a/isapi/src/PyExtensionObjects.cpp +++ b/isapi/src/PyExtensionObjects.cpp @@ -25,10 +25,12 @@ //#define PY_SSIZE_T_CLEAN // defined by isapi\src\StdAfx.h #include "stdafx.h" +#include "pywintypes.h" #include "Utils.h" #include "PyExtensionObjects.h" #include "PythonEng.h" + // Asynch IO callbacks are a little tricky, as we never know how many // callbacks a single connection might make (often each callback will trigger // another IO request.) So we keep the Python objects used by the callback @@ -174,7 +176,7 @@ PyObject *PyVERSION_INFO::getattro(PyObject *self, PyObject *obname) PyVERSION_INFO *me = (PyVERSION_INFO *)self; if (!me->m_pvi) return PyErr_Format(PyExc_RuntimeError, "VERSION_INFO structure no longer exists"); - TCHAR *name = PYISAPI_ATTR_CONVERT(obname); + TmpWCHAR name = obname; if (!name) return NULL; if (_tcscmp(name, _T("ExtensionDesc")) == 0) { return PyBytes_FromString(me->m_pvi->lpszExtensionDesc); } @@ -184,7 +186,7 @@ PyObject *PyVERSION_INFO::getattro(PyObject *self, PyObject *obname) int PyVERSION_INFO::setattro(PyObject *self, PyObject *obname, PyObject *v) { PyVERSION_INFO *me = (PyVERSION_INFO *)self; - TCHAR *name = PYISAPI_ATTR_CONVERT(obname); + TmpWCHAR name = obname; if (!name) return -1; if (!me->m_pvi) { PyErr_Format(PyExc_RuntimeError, "VERSION_INFO structure no longer exists"); return -1; @@ -343,7 +345,7 @@ PyECB::~PyECB() PyObject *PyECB::getattro(PyObject *self, PyObject *obname) { - TCHAR *name = PYISAPI_ATTR_CONVERT(obname); + TmpWCHAR name = obname; if (!name) return NULL; if (_tcscmp(name, _T("softspace")) == 0) // help 'print' semantics. return PyLong_FromLong(1); @@ -383,7 +385,7 @@ int PyECB::setattro(PyObject *self, PyObject *obname, PyObject *v) PyErr_SetString(PyExc_AttributeError, "can't delete ECB attributes"); return -1; } - TCHAR *name = PYISAPI_ATTR_CONVERT(obname); + TmpWCHAR name = obname; if (!name) return -1; if (_tcscmp(name, _T("HttpStatusCode")) == 0) { PyECB *pecb = (PyECB *)self; @@ -681,8 +683,9 @@ PyObject *PyECB::GetAnonymousToken(PyObject *self, PyObject *args) Py_END_ALLOW_THREADS } else if (PyUnicode_Check(obStr)) { + TmpWCHAR tmpw = obStr; if (!tmpw) return NULL; Py_BEGIN_ALLOW_THREADS bRes = ecb->ServerSupportFunction(ecb->ConnID, HSE_REQ_GET_UNICODE_ANONYMOUS_TOKEN, - PyUnicode_AS_UNICODE(obStr), (DWORD *)&handle, NULL); + tmpw, (DWORD *)&handle, NULL); Py_END_ALLOW_THREADS } else diff --git a/isapi/src/PyFilterObjects.cpp b/isapi/src/PyFilterObjects.cpp index 36fbbba44..312d69de8 100644 --- a/isapi/src/PyFilterObjects.cpp +++ b/isapi/src/PyFilterObjects.cpp @@ -25,6 +25,7 @@ //#define PY_SSIZE_T_CLEAN // defined by isapi\src\StdAfx.h #include "stdafx.h" +#include "pywintypes.h" #include "Utils.h" #include "pyFilterObjects.h" @@ -68,7 +69,7 @@ PyObject *PyFILTER_VERSION::getattro(PyObject *self, PyObject *obname) PyFILTER_VERSION *me = (PyFILTER_VERSION *)self; if (!me->m_pfv) return PyErr_Format(PyExc_RuntimeError, "FILTER_VERSION structure no longer exists"); - TCHAR *name = PYISAPI_ATTR_CONVERT(obname); + TmpWCHAR name = obname; if (!name) return NULL; // @prop int|ServerFilterVersion|(read-only) if (_tcscmp(name, _T("ServerFilterVersion")) == 0) { return PyLong_FromLong(me->m_pfv->dwServerFilterVersion); @@ -85,7 +86,7 @@ PyObject *PyFILTER_VERSION::getattro(PyObject *self, PyObject *obname) if (_tcscmp(name, _T("FilterDesc")) == 0) { return PyBytes_FromString(me->m_pfv->lpszFilterDesc); } - return PyErr_Format(PyExc_AttributeError, "PyFILTER_VERSION has no attribute '%s'", name); + return PyErr_Format(PyExc_AttributeError, "PyFILTER_VERSION has no attribute '%S'", obname); } int PyFILTER_VERSION::setattro(PyObject *self, PyObject *obname, PyObject *v) @@ -99,7 +100,7 @@ int PyFILTER_VERSION::setattro(PyObject *self, PyObject *obname, PyObject *v) PyErr_SetString(PyExc_AttributeError, "can't delete FILTER_VERSION attributes"); return -1; } - TCHAR *name = PYISAPI_ATTR_CONVERT(obname); + TmpWCHAR name = obname; if (!name) return -1; if (_tcscmp(name, _T("FilterVersion")) == 0) { if (!PyLong_Check(v)) { PyErr_Format(PyExc_ValueError, "FilterVersion must be an int (got %s)", v->ob_type->tp_name); @@ -415,7 +416,7 @@ PyHFC::~PyHFC() PyObject *PyHFC::getattro(PyObject *self, PyObject *obname) { - TCHAR *name = PYISAPI_ATTR_CONVERT(obname); + TmpWCHAR name = obname; if (!name) return NULL; // other manual attributes. if (_tcscmp(name, _T("FilterContext")) == 0) { @@ -434,7 +435,7 @@ PyObject *PyHFC::getattro(PyObject *self, PyObject *obname) int PyHFC::setattro(PyObject *self, PyObject *obname, PyObject *v) { - TCHAR *name = PYISAPI_ATTR_CONVERT(obname); + TmpWCHAR name = obname; if (!name) return -1; if (v == NULL) { PyErr_SetString(PyExc_AttributeError, "can't delete ECB attributes"); return -1; @@ -536,7 +537,7 @@ PyObject *PyURL_MAP::getattro(PyObject *self, PyObject *obname) if (!pMap) return NULL; // @prop string|URL| - TCHAR *name = PYISAPI_ATTR_CONVERT(obname); + TmpWCHAR name = obname; if (!name) return NULL; if (_tcscmp(name, _T("URL")) == 0) { return PyBytes_FromString(pMap->pszURL); } @@ -552,7 +553,7 @@ int PyURL_MAP::setattro(PyObject *self, PyObject *obname, PyObject *v) HTTP_FILTER_URL_MAP *pMap = ((PyURL_MAP *)self)->GetURLMap(); if (!pMap) return NULL; - TCHAR *name = PYISAPI_ATTR_CONVERT(obname); + TmpWCHAR name = obname; if (!name) return -1; if (_tcscmp(name, _T("PhysicalPath")) == 0) { if (!PyBytes_Check(v)) { PyErr_Format(PyExc_TypeError, "PhysicalPath must be a string"); @@ -779,7 +780,7 @@ PyObject *PyRAW_DATA::getattro(PyObject *self, PyObject *obname) if (!pRD) return NULL; // @prop string|InData| - TCHAR *name = PYISAPI_ATTR_CONVERT(obname); + TmpWCHAR name = obname; if (!name) return NULL; if (_tcscmp(name, _T("InData")) == 0) { if (pRD->pvInData == NULL) { Py_INCREF(Py_None); @@ -799,7 +800,7 @@ int PyRAW_DATA::setattro(PyObject *self, PyObject *obname, PyObject *v) if (!pRD || !pFC) return NULL; - TCHAR *name = PYISAPI_ATTR_CONVERT(obname); + TmpWCHAR name = obname; if (!name) return -1; if (_tcscmp(name, _T("InData")) == 0) { if (!PyBytes_Check(v)) { PyErr_Format(PyExc_TypeError, "InData must be a string (got %s)", v->ob_type->tp_name); @@ -885,7 +886,7 @@ PyObject *PyAUTHENT::getattro(PyObject *self, PyObject *obname) HTTP_FILTER_AUTHENT *pAE = ((PyAUTHENT *)self)->GetAUTHENT(); if (!pAE) return NULL; - TCHAR *name = PYISAPI_ATTR_CONVERT(obname); + TmpWCHAR name = obname; if (!name) return NULL; // @prop string|User| if (_tcscmp(name, _T("User")) == 0) { if (pAE->pszUser == NULL) { @@ -913,7 +914,7 @@ int PyAUTHENT::setattro(PyObject *self, PyObject *obname, PyObject *v) if (!pAE || !pFC) return NULL; - TCHAR *name = PYISAPI_ATTR_CONVERT(obname); + TmpWCHAR name = obname; if (!name) return -1; if (_tcscmp(name, _T("User")) == 0) { if (!PyBytes_Check(v)) { PyErr_Format(PyExc_TypeError, "User must be a string (got %s)", v->ob_type->tp_name); @@ -998,7 +999,7 @@ PyObject *PyFILTER_LOG::getattro(PyObject *self, PyObject *obname) HTTP_FILTER_LOG *pLog = ((PyFILTER_LOG *)self)->GetFilterLog(); if (!pLog) return NULL; - TCHAR *name = PYISAPI_ATTR_CONVERT(obname); + TmpWCHAR name = obname; if (!name) return NULL; // @prop string|ClientHostName| if (_tcscmp(name, _T("ClientHostName")) == 0) return PyBytes_FromString(pLog->pszClientHostName); @@ -1063,7 +1064,7 @@ int PyFILTER_LOG::setattro(PyObject *self, PyObject *obname, PyObject *v) HTTP_FILTER_LOG *pLog = ((PyFILTER_LOG *)self)->GetFilterLog(); if (!pLog || !pFC) return NULL; - TCHAR *name = PYISAPI_ATTR_CONVERT(obname); + TmpWCHAR name = obname; if (!name) return -1; CHECK_SET_FILTER_LOG_STRING(ClientHostName) CHECK_SET_FILTER_LOG_STRING(ClientUserName) CHECK_SET_FILTER_LOG_STRING(ServerName) diff --git a/isapi/src/PythonEng.h b/isapi/src/PythonEng.h index e7ff1383d..4e9c3064b 100644 --- a/isapi/src/PythonEng.h +++ b/isapi/src/PythonEng.h @@ -79,6 +79,7 @@ class CPythonHandler { void ExtensionError(CControlBlock *pcb, const char *errmsg); void FilterError(CFilterContext *pfc, const char *errmsg); +#ifndef __PYWINTYPES_H__ class CEnterLeavePython { public: CEnterLeavePython() : state(PyGILState_Ensure()) { ; } @@ -87,5 +88,6 @@ class CEnterLeavePython { protected: PyGILState_STATE state; }; +#endif #endif // __PythonEngine_H \ No newline at end of file diff --git a/isapi/src/StdAfx.h b/isapi/src/StdAfx.h index 4be84b3fe..e0d093dbf 100644 --- a/isapi/src/StdAfx.h +++ b/isapi/src/StdAfx.h @@ -54,7 +54,7 @@ // Macros to handle PyObject layout changes in Py3k #define PYISAPI_OBJECT_HEAD PyVarObject_HEAD_INIT(NULL, 0) -#define PYISAPI_ATTR_CONVERT PyUnicode_AsUnicode +////#define PYISAPI_ATTR_CONVERT PyUnicode_AsUnicode // removed in Py3.12+ // A helper that on py3k takes a str or unicode as input and returns a // string - exactly how the 's#' PyArg_ParseTuple format string does... diff --git a/win32/src/PyUnicode.cpp b/win32/src/PyUnicode.cpp index a67c07291..5dbaf8e7a 100644 --- a/win32/src/PyUnicode.cpp +++ b/win32/src/PyUnicode.cpp @@ -34,8 +34,8 @@ BOOL PyWinObject_AsPfnAllocatedWCHAR(PyObject *stringObject, void *(*pfnAllocato } else if (PyUnicode_Check(stringObject)) { // copy the value, including embedded NULLs - WCHAR *v = (WCHAR *)PyUnicode_AS_UNICODE(stringObject); - Py_ssize_t cch = PyUnicode_GET_SIZE(stringObject); + TmpWCHAR v = stringObject; if (!v) return FALSE; + Py_ssize_t cch = v.length; *ppResult = (WCHAR *)pfnAllocator((cch + 1) * sizeof(WCHAR)); if (*ppResult) memcpy(*ppResult, v, (cch + 1) * sizeof(WCHAR)); @@ -102,11 +102,7 @@ BOOL PyWinObject_AsChars(PyObject *stringObject, char **pResult, BOOL bNoneOK /* // Convert the string if a WIDE string. if (PyUnicode_Check(stringObject)) { // PyUnicode_EncodeMBCS was removed in Py 3.11. - PyObject *unicode = PyUnicode_FromWideChar(PyUnicode_AS_UNICODE(stringObject), -1); - if (unicode == NULL) - return FALSE; - stringObject = tempObject = PyUnicode_EncodeCodePage(CP_ACP, unicode, NULL); - Py_DECREF(unicode); + stringObject = tempObject = PyUnicode_AsMBCSString(stringObject); if (!stringObject) return FALSE; } @@ -184,22 +180,11 @@ BOOL PyWinObject_AsBstr(PyObject *stringObject, BSTR *pResult, BOOL bNoneOK /*= // sane b/w compat reason to support that any more. if (PyUnicode_Check(stringObject)) { // copy the value, including embedded NULLs - Py_ssize_t nchars = PyUnicode_GET_SIZE(stringObject); - *pResult = SysAllocStringLen(NULL, nchars); - if (*pResult) { -#define PUAWC_TYPE PyObject * - if (PyUnicode_AsWideChar((PUAWC_TYPE)stringObject, *pResult, nchars) == -1) { - rc = FALSE; - } - else { - // The SysAllocStringLen docs indicate that nchars+1 bytes are allocated, - // and that normally a \0 is appened by the function. It also states - // the \0 is not necessary! While it seems to work fine without it, - // we do copy it, as the previous code, which used SysAllocStringLen - // with a non-NULL arg is documented clearly as appending the \0. - (*pResult)[nchars] = 0; - } - } + // Py3.12+: only conversion yields the correct number of wide chars (incl. surrogate pairs). + // For simplicity we use a temp buffer. + TmpWCHAR tw = stringObject; if (!tw) return FALSE; + // SysAllocStringLen allocates length+1 wchars (and puts a \0 at end); like PyUnicode_AsWideCharString + *pResult = SysAllocStringLen(tw, tw.length); } else if (stringObject == Py_None) { if (bNoneOK) { @@ -228,7 +213,7 @@ void PyWinObject_FreeBstr(BSTR str) { SysFreeString(str); } // String conversions // Convert a Python object to a WCHAR - allow embedded NULLs, None, etc. -// Must be freed with PyWinObject_FreeWCHAR +// Must be freed with PyWinObject_FreeWCHAR / PyMem_Free BOOL PyWinObject_AsWCHAR(PyObject *stringObject, WCHAR **pResult, BOOL bNoneOK /*= FALSE*/, DWORD *pResultLen /*= NULL*/) { @@ -236,15 +221,11 @@ BOOL PyWinObject_AsWCHAR(PyObject *stringObject, WCHAR **pResult, BOOL bNoneOK / Py_ssize_t resultLen = 0; // Do NOT accept 'bytes' for any 'WCHAR' API. if (PyUnicode_Check(stringObject)) { - resultLen = PyUnicode_GET_SIZE(stringObject); - size_t cb = sizeof(WCHAR) * (resultLen + 1); - *pResult = (WCHAR *)PyMem_Malloc(cb); + *pResult = PyUnicode_AsWideCharString(stringObject, &resultLen); if (*pResult == NULL) { - PyErr_SetString(PyExc_MemoryError, "Allocating WCHAR array"); + PyErr_SetString(PyExc_MemoryError, "Getting WCHAR string"); return FALSE; } - // copy the value, including embedded NULLs - memcpy(*pResult, PyUnicode_AsUnicode(stringObject), cb); } else if (stringObject == Py_None) { if (bNoneOK) { diff --git a/win32/src/PyWinTypes.h b/win32/src/PyWinTypes.h index 350be14f8..261efeded 100644 --- a/win32/src/PyWinTypes.h +++ b/win32/src/PyWinTypes.h @@ -167,19 +167,35 @@ PYWINTYPES_EXPORT void PyWinObject_FreeChars(char *pResult); // Automatically freed WCHAR that can be used anywhere WCHAR * is required class TmpWCHAR { public: - WCHAR *tmp; + WCHAR *tmp; // (NULL after conversion error) + Py_ssize_t length; // only set after successful auto-conversion; w/o trailing \0 TmpWCHAR() { tmp = NULL; } TmpWCHAR(WCHAR *t) { tmp = t; } + TmpWCHAR(PyObject *ob) : tmp(NULL) { *this = ob; } + WCHAR *operator=(PyObject *ob) { + if (tmp) + PyMem_Free(tmp); + if (ob == NULL) + tmp = NULL; // (exception already has been set in this case) + else + tmp = PyUnicode_AsWideCharString(ob, &length); + return tmp; + } WCHAR *operator=(WCHAR *t) { - PyWinObject_FreeWCHAR(tmp); + if (tmp) + PyMem_Free(tmp); tmp = t; return t; } WCHAR **operator&() { return &tmp; } boolean operator==(WCHAR *t) { return tmp == t; } operator WCHAR *() { return tmp; } - ~TmpWCHAR() { PyWinObject_FreeWCHAR(tmp); } + ~TmpWCHAR() { if (tmp) PyMem_Free(tmp); } + private: + // Block unwanted copy construction + TmpWCHAR(const TmpWCHAR& o); // = delete; + const TmpWCHAR& operator=(const TmpWCHAR& o); // = delete; }; // More string helpers - how many do we need? diff --git a/win32/src/PythonService.cpp b/win32/src/PythonService.cpp index 2a65f8989..274f80776 100644 --- a/win32/src/PythonService.cpp +++ b/win32/src/PythonService.cpp @@ -1463,9 +1463,9 @@ int _tmain(int argc, TCHAR **argv) // now get the handle to the DLL, and call the main function. if (PyBytes_Check(f)) hmod = GetModuleHandleA(PyBytes_AsString(f)); - else if (PyUnicode_Check(f)) - hmod = GetModuleHandleW(PyUnicode_AsUnicode(f)); - else { + else if (TmpWCHAR tw=f) { + hmod = GetModuleHandleW(tw); + } else { PyErr_SetString(PyExc_TypeError, "servicemanager.__file__ is not a string or unicode !"); goto failed; } diff --git a/win32/src/_win32sysloader.cpp b/win32/src/_win32sysloader.cpp index cd4cdaacb..c19a6dbb0 100644 --- a/win32/src/_win32sysloader.cpp +++ b/win32/src/_win32sysloader.cpp @@ -26,8 +26,9 @@ static PyObject *PyGetModuleFilename(PyObject *self, PyObject *args) TCHAR *modName = PyUnicode_AsWideCharString(nameobj, NULL); if (!modName) return NULL; - + HINSTANCE hinst = GetModuleHandle(modName); + PyMem_Free(modName); if (hinst == NULL) { Py_INCREF(Py_None); return Py_None; @@ -38,7 +39,7 @@ static PyObject *PyGetModuleFilename(PyObject *self, PyObject *args) return Py_None; } - return PyUnicode_FromUnicode(buf, wcslen(buf)); + return PyUnicode_FromWideChar(buf, wcslen(buf)); } static PyObject *PyLoadModule(PyObject *self, PyObject *args) @@ -61,6 +62,7 @@ static PyObject *PyLoadModule(PyObject *self, PyObject *args) LOAD_LIBRARY_SEARCH_DEFAULT_DIRS | LOAD_LIBRARY_SEARCH_DLL_LOAD_DIR); #endif + PyMem_Free(modName); if (hinst == NULL) { Py_INCREF(Py_None); return Py_None; @@ -71,7 +73,7 @@ static PyObject *PyLoadModule(PyObject *self, PyObject *args) return Py_None; } - return PyUnicode_FromUnicode(buf, wcslen(buf)); + return PyUnicode_FromWideChar(buf, wcslen(buf)); } static struct PyMethodDef functions[] = { diff --git a/win32/src/odbc.cpp b/win32/src/odbc.cpp index 656f512bc..e15fde0ff 100644 --- a/win32/src/odbc.cpp +++ b/win32/src/odbc.cpp @@ -817,8 +817,8 @@ static int ibindString(cursorObject *cur, int column, PyObject *item) static int ibindUnicode(cursorObject *cur, int column, PyObject *item) { - const WCHAR *wval = (WCHAR *)PyUnicode_AsUnicode(item); - Py_ssize_t nchars = PyUnicode_GetSize(item) + 1; + TmpWCHAR wval = item; if (!wval) return 0; + Py_ssize_t nchars = wval.length + 1; Py_ssize_t nbytes = nchars * sizeof(WCHAR); InputBinding *ib = initInputBinding(cur, nbytes); diff --git a/win32/src/win32apimodule.cpp b/win32/src/win32apimodule.cpp index a952ca48e..299579999 100644 --- a/win32/src/win32apimodule.cpp +++ b/win32/src/win32apimodule.cpp @@ -1396,13 +1396,14 @@ static PyObject *PyVkKeyScan(PyObject *self, PyObject *args) PyW32_END_ALLOW_THREADS } else if (PyUnicode_Check(obkey)) { - if (PyUnicode_GET_SIZE(obkey) != 1) { + if (PyUnicode_GetLength(obkey) != 1) { PyErr_SetString(PyExc_TypeError, "must be a unicode string of length 1"); return NULL; } + TmpWCHAR ts(obkey); if (!ts) return NULL; PyW32_BEGIN_ALLOW_THREADS // @pyseeapi VkKeyScanW - ret = VkKeyScanW(PyUnicode_AS_UNICODE(obkey)[0]); + ret = VkKeyScanW(ts[0]); PyW32_END_ALLOW_THREADS } else { @@ -1440,13 +1441,14 @@ static PyObject *PyVkKeyScanEx(PyObject *self, PyObject *args) PyW32_END_ALLOW_THREADS } else if (PyUnicode_Check(obkey)) { - if (PyUnicode_GET_SIZE(obkey) != 1) { + if (PyUnicode_GetLength(obkey) != 1) { PyErr_SetString(PyExc_TypeError, "must be a unicode string of length 1"); return NULL; } + TmpWCHAR ts(obkey); if (!ts) return NULL; PyW32_BEGIN_ALLOW_THREADS // @pyseeapi VkKeyScanExW - ret = VkKeyScanExW(PyUnicode_AS_UNICODE(obkey)[0], hkl); + ret = VkKeyScanExW(ts[0], hkl); PyW32_END_ALLOW_THREADS } else { @@ -1543,7 +1545,7 @@ static PyObject *PyGetModuleFileNameW(PyObject *self, PyObject *args) break; } if (reqdsize < bufsize) { - ret = PyUnicode_FromUnicode(buf, reqdsize); + ret = PyUnicode_FromWideChar(buf, reqdsize); break; } reqdsize++; @@ -2099,21 +2101,13 @@ static PyObject *PyGetLongPathNameW(PyObject *self, PyObject *args) else { // retry with a buffer that is big enough. Now we know the // size and that it is big, avoid double-handling. - Py_UNICODE *buf; + TmpWCHAR buf = PyMem_New(WCHAR, length); // The length is the buffer needed, which includes the NULL. - // PyUnicode_FromUnicode adds one. - obLongPathNameW = PyUnicode_FromUnicode(NULL, length - 1); - if (!obLongPathNameW) { - PyWinObject_FreeWCHAR(fileName); - return NULL; - } - buf = PyUnicode_AS_UNICODE(obLongPathNameW); + // PyUnicode_FromWideChar adds one. PyW32_BEGIN_ALLOW_THREADS DWORD length2 = (*pfnGetLongPathNameW)(fileName, buf, length); - PyW32_END_ALLOW_THREADS if (length2 == 0) - { - Py_DECREF(obLongPathNameW); - obLongPathNameW = NULL; - } + PyW32_END_ALLOW_THREADS + if (length2) + obLongPathNameW = PyUnicode_FromWideChar(buf, -1); // On success, it is the number of chars copied *not* including // the NULL. Check this is true. assert(length2 + 1 == length); diff --git a/win32/src/win32clipboardmodule.cpp b/win32/src/win32clipboardmodule.cpp index ed8b5af04..2dde670ca 100644 --- a/win32/src/win32clipboardmodule.cpp +++ b/win32/src/win32clipboardmodule.cpp @@ -840,12 +840,13 @@ static PyObject *py_set_clipboard_data(PyObject *self, PyObject *args) PyErr_Clear(); const void *buf = NULL; + TmpWCHAR tmpw; Py_ssize_t bufSize = 0; PyWinBufferView pybuf; // In py3k, unicode no longer supports buffer interface if (PyUnicode_Check(obhandle)) { - bufSize = PyUnicode_GET_DATA_SIZE(obhandle) + sizeof(Py_UNICODE); - buf = (void *)PyUnicode_AS_UNICODE(obhandle); + buf = tmpw = obhandle; if (!tmpw) return NULL; + bufSize = (tmpw.length + 1) * sizeof(WCHAR); } else { if (!pybuf.init(obhandle)) diff --git a/win32/src/win32consolemodule.cpp b/win32/src/win32consolemodule.cpp index 1235e3efd..b8c844441 100644 --- a/win32/src/win32consolemodule.cpp +++ b/win32/src/win32consolemodule.cpp @@ -106,7 +106,7 @@ BOOL PyWinObject_AsUSHORTArray(PyObject *obushorts, USHORT **pushorts, DWORD *it // structmember framework provided a format code for this BOOL PyWinObject_AsSingleWCHAR(PyObject *obchar, WCHAR *onechar) { - if (!PyUnicode_Check(obchar) || (PyUnicode_GET_SIZE(obchar) != 1)) { + if (!PyUnicode_Check(obchar) || (PyUnicode_GetLength(obchar) != 1)) { PyErr_SetString(PyExc_ValueError, "Object must be a single unicode character"); return FALSE; } diff --git a/win32/src/win32file.i b/win32/src/win32file.i index db47e66bd..2a64ec463 100644 --- a/win32/src/win32file.i +++ b/win32/src/win32file.i @@ -5320,8 +5320,7 @@ static PyObject *py_GetFullPathName(PyObject *self, PyObject *args, PyObject *kw if (!PyWinObject_AsHANDLE(obtrans, &htrans)) return NULL; - WCHAR *wpathin; - if (wpathin=PyUnicode_AsUnicode(obpathin)){ + if (TmpWCHAR wpathin=obpathin) { if (htrans) CHECK_PFN(GetFullPathNameTransactedW); WCHAR *wpathret=NULL, *wfilepart, *wpathsave=NULL; diff --git a/win32/src/win32gui.i b/win32/src/win32gui.i index ae48fe21a..94d689886 100644 --- a/win32/src/win32gui.i +++ b/win32/src/win32gui.i @@ -861,6 +861,7 @@ public: static PyObject *PySetDialogProc(PyObject *self, PyObject *args); WNDCLASS m_WNDCLASS; PyObject *m_obMenuName, *m_obClassName, *m_obWndProc; + TmpWCHAR m_MenuName, m_ClassName; }; #define PyWNDCLASS_Check(ob) ((ob)->ob_type == &PyWNDCLASSType) @@ -1001,7 +1002,7 @@ PyObject *PyWNDCLASS::getattro(PyObject *self, PyObject *obname) return PyObject_GenericGetAttr(self, obname); } -int SetTCHAR(PyObject *v, PyObject **m, LPCTSTR *ret) +int _SetTCHAR(PyObject *v, PyObject **m, LPCTSTR *ret, TmpWCHAR &tws) { if (!PyUnicode_Check(v)) { PyErr_SetString(PyExc_TypeError, "Object must be a Unicode"); @@ -1010,7 +1011,9 @@ int SetTCHAR(PyObject *v, PyObject **m, LPCTSTR *ret) Py_XDECREF(*m); *m = v; Py_INCREF(v); - *ret = PyUnicode_AsUnicode(v); + *ret = tws = v; + if (!tws) + return -1; return 0; } @@ -1025,10 +1028,10 @@ int PyWNDCLASS::setattro(PyObject *self, PyObject *obname, PyObject *v) return -1; PyWNDCLASS *pW = (PyWNDCLASS *)self; if (strcmp("lpszMenuName", name)==0) { - return SetTCHAR(v, &pW->m_obMenuName, &pW->m_WNDCLASS.lpszMenuName); + return _SetTCHAR(v, &pW->m_obMenuName, &pW->m_WNDCLASS.lpszMenuName, pW->m_MenuName); } if (strcmp("lpszClassName", name)==0) { - return SetTCHAR(v, &pW->m_obClassName, &pW->m_WNDCLASS.lpszClassName); + return _SetTCHAR(v, &pW->m_obClassName, &pW->m_WNDCLASS.lpszClassName, pW->m_ClassName); } if (strcmp("lpfnWndProc", name)==0) { if (!PyCallable_Check(v) && !PyDict_Check(v)) { diff --git a/win32/src/win32process.i b/win32/src/win32process.i index d8f633cfc..60db9376b 100644 --- a/win32/src/win32process.i +++ b/win32/src/win32process.i @@ -502,6 +502,7 @@ static BOOL CreateEnvironmentString(PyObject *env, LPVOID *ppRet, BOOL *pRetIsUn LPVOID result = NULL; WCHAR *pUCur; char *pACur; + TmpWCHAR tw; keys = PyMapping_Keys(env); vals = PyMapping_Values(env); @@ -517,7 +518,8 @@ static BOOL CreateEnvironmentString(PyObject *env, LPVOID *ppRet, BOOL *pRetIsUn bufLen += PyBytes_Size(key) + 1; } else if (PyUnicode_Check(key)) { bIsUnicode = TRUE; - bufLen += PyUnicode_GET_SIZE(key) + 1; + tw = key; if (!tw) goto done; + bufLen += wcslen(tw) + 1; // PyUnicode_GetLength() and tw.length (incl \0 's) may be different } else { PyErr_SetString(PyExc_TypeError, "dictionary must have keys and values as strings or unicode objects."); goto done; @@ -528,7 +530,8 @@ static BOOL CreateEnvironmentString(PyObject *env, LPVOID *ppRet, BOOL *pRetIsUn PyErr_SetString(PyExc_TypeError, "All dictionary items must be strings, or all must be unicode"); goto done; } - bufLen += PyUnicode_GET_SIZE(key) + 1; + tw = key; if (!tw) goto done; + bufLen += wcslen(tw) + 1; } else { if (!PyBytes_Check(key)) { @@ -544,7 +547,8 @@ static BOOL CreateEnvironmentString(PyObject *env, LPVOID *ppRet, BOOL *pRetIsUn PyErr_SetString(PyExc_TypeError, "All dictionary items must be strings, or all must be unicode"); goto done; } - bufLen += PyUnicode_GET_SIZE(val) + 2; // For the '=' and '\0' + tw = val; if (!tw) goto done; + bufLen += wcslen(tw) + 2; // For the '=' and '\0' } else { if (!PyBytes_Check(val)) {