2

on windows, what is the difference among the following?

import msvcrt as x

vs

x = ctypes.cdll.msvcrt

vs

x = ctypes.CDLL(find_library('c'))

vs

x = ctypes.CDLL(ctypes.util.find_msvcrt())

i believe the doc say the last two are equivalent. but the first two are never (clearly) documented, and seem strictly better. for instance, when running python from some other context that uses a different msvcr*.dll (eg, matlab), replacing the third with the second solved this bug.

user1441998
  • 459
  • 4
  • 14
  • `import msvcrt` imports a Python extension module that's built into the Python DLL, pythonXY.dll. This module wraps a few useful CRT functions such as `open_osfhandle`, `get_osfhandle`, and `setmode`. – Eryk Sun Jun 11 '15 at 20:17
  • `ctypes.cdll.msvcrt` loads the Windows private CRT, msvcrt.dll, which is accessed using a ctypes `CDLL` instance. It's highly discouraged to link with this CRT, but that doesn't stop people from doing it -- notably by MinGW. – Eryk Sun Jun 11 '15 at 20:20
  • 1
    `find_library('c')` or `find_library('m')` indirectly call `find_msvcrt`, which infers the name of the CRT for the version of Visual Studio that was used to build the interpreter such as "msvcr90.dll" or "msvcr100.dll". The future of this API on Windows is up in the air for Python 3.5+. It depends on how things work out with the new universal CRT that Visual Studio 2015 introduces. If ucrtbase.dll stops exporting by name, loading it dynamically will be pointless. You'll have to instead use one of the `api-ms-win-crt-*` DLLs. – Eryk Sun Jun 11 '15 at 20:30
  • thanks @eryksun, you can consolidate these into an answer i'll accept. where is this stuff documented? why doesn't "the module built into the python dll" just include everything in "the windows private crt"? what does "private" mean here? why is linking it discouraged? is there a better way to fix the bug mentioned? – user1441998 Jun 11 '15 at 20:40
  • Linking with msvcrt.dll is discouraged because the Windows team at Microsoft wants it to be their playground, to be free to change its internal structures and APIs around to suit their needs. Yeah, that's a pipe dream. – Eryk Sun Jun 11 '15 at 20:51
  • 1
    The Python `msvcrt` module doesn't use msvcrt.dll. It's just exposing certain useful functions from Python's linked CRT, which is msvcr90.dll for Python 2.7, msvcr100.dll for Python 3.4, and several api-ms-win-crt DLLs (forwarded to ucrtbase.dll) for Python 3.5. – Eryk Sun Jun 11 '15 at 20:59
  • what is the diff btw `msvcrt.dll` and `msvcr[90|100].dll`? i get you're saying `msvcrt.dll` is officially just for ms, not for us. but as far as the api's they expose, what is the diff? why doesn't the python `msvcrt` module expose everything you'd get from `ctypes.CDLL(find_library('c'))`? to summarize what i think you're saying -- options 1,3,4 are similar and access whatever `msvcr*.dll` was used to build `python.exe` (option 1 is just a subset), and option 2 accesses a nominally off-limits dll that currently happens to have almost exactly the same content and structure. is that right? – user1441998 Jun 11 '15 at 21:21
  • 1
    The layout of a `FILE` (the high-level stdio structure that tracks the state and buffering of an open file; Python 3 only uses stdio `FILE` pointers for the REPL shell) or low-level `ioinfo` structure can vary. The latter structure binds a text/binary mode file descriptor to a Windows file handle. The mapping between CRT file descriptors and Windows file handles is unique to each CRT in the process. Additionally each CRT uses its own heap for `malloc` and `free` (wrapping Windows `HeapAlloc` and `HeapFree`), so allocating memory with one and freeing with another is an error. – Eryk Sun Jun 11 '15 at 22:10
  • `msvcrt.dll` is the CRT used by Windows components, but also by applications built with Visual Studio 6 or earlier. `msvcr90.dll` is the CRT belonging to applications built with Visual Studio 2008, `msvcr100.dll` is the CRT belonging to applications built with Visual Studio 2010. – Harry Johnston Jun 12 '15 at 00:17
  • @HarryJohnston, the context is the OP is using a library that calls `find_msvcrt` to get the name of the CRT DLL, based on the version of Visual Studio that was used to build the Python interpreter. Even though it's embedded in an application that lacks the VC90 manifest, python27.dll has its own manifest as resource ID 2, so it can statically load msvcr90.dll. However, trying to load msvcr90.dll via ctypes (i.e. `LoadLibrary`) fails. I instructed the OP how to use `CreateActCtx` and `ActivateActCtx` to use a manifest dynamically. But apparently it's unnecessary since msvcrt.dll suffices. – Eryk Sun Jun 12 '15 at 01:34
  • @eryksun, your method works, thanks for all the help. where is this stuff documented? can you indicate if my above summary of what you've written is accurate? also, is there any justification for why `ctypes.cdll.msvcrt` and `find_library('c')` work the way they do? imho, they should both implement your method and return the dll in the manifest -- i can see no reason for the current behavior. – user1441998 Jun 13 '15 at 00:43
  • python.exe is a console application that's linked to the Python DLL. .py scripts are associated with python.exe, so a script that uses ctypes runs in the context of the python.exe manifest (resource ID 1). MATLAB instead loads python27.dll within its own process. In this case the manifest that's embedded in python27.dll (resource ID 2) is used to create a temporary activation context to find dependent assemblies such as the VC90 CRT. But calling `LoadLibraryW(L"msvcr90.dll")` again, even though it's already loaded, requires a new activation context. – Eryk Sun Jun 13 '15 at 01:06

0 Answers0