Recently a customer came to ask why pywin32 do not work on Maya or MotionBuilder. The answer is very simple, Maya and MotionBuilder are compiled the lastest compiler to get the best performances and the latest technology possible. Maya itself is partially compiler with the Intel C++ compiler and Visual Studio 2012 SP4, whereas MotionBuilder uses Visual Studio 2012 SP4 only. The issue is that pywin32 and many of the Python libraries still use an older compiler, like sometimes the Visual Studio 2005 compiler. Like its name says, nearly 10 years old.
Each Visual Studio compiler version comes with CRT, STL, MFC, ATL libraries which are not binary compatible with others. They can eventually be loaded in memory concurrently, but cannot 'exchange' (or manage) memory blocks allocated by another version. Doing that would most of the time result in a crash. For that reason, you need to recompile these libraries for both products using their 'native' compiler. You cannot get an already compiled package from someone else, if the package is not of the right compiler version.
In this article, I'll describe the steps I used to recompile the pywin32 library for MotionBuilder 2015. Note that I did not try to port pywin32 to Visual Studio 2012, but just to recompile it as much I could in a simple way. (These steps would also work for Maya 2015, you would only need to change the last 2 lines of the last script)
One last comment - I used Windows 8.1 for building the package, if you have a previous version of Windows and a previous version than the Microsoft SDK 8 - some changes may be required. Based on comments I received so far from Pierre-Marc Simard ( EIDOS Montreal ), I tried to include some of the required changes in the notes below. Pierre-Marc was very keen to try and reports all the differences he saw on his system. One thing he said, was that he had to run the build few times to resolve some errors magically. I'll try this later next week,and will report differences I can see. But Windows 8.x and SDK 8 sounds quite easy.
Downloads
First, you need to download and install Python 2.7.3 x64 on your machine - that is the python version MotionBuilder is using. But unlike Maya, MoBu does not provide a command line version of its VS2012 python version, so this is why we need to install Python. Use the default 'C:\Python27' folder to install. You can get the x64 build from there.
Next, get the pywin32 source code from http://sourceforge.net/projects/pywin32/?source=navbar, and unzip the source into a folder of your choice. I used 'C:\temp\pywin32-219' and used the latest version at the time of this post. Download source from here.
Missing headers
To build pywin32, you need couple of additional headers which may not be present on your system.
a- The Outlook 2010: MAPI Header Files - Mapix.h. Download the zip file, and copy all except mapi.h and mspst.h in "C:\Program Files (x86)\Windows Kits\8.0\Include\um"
b- The MFCMAPI headers. I downloaded them from http://mfcmapi.codeplex.com/SourceControl/latest, and copied EdkGuid.h and EdkMdb.h in "C:\Program Files (x86)\Windows Kits\8.0\Include\um"
Code changes required to build on VS2012
Now the few things to edit before running the build.
If you are on Windows 8 or later, go in 'C:\temp\pywin32-219\com\win32comext\axdebug\src\stdafx.h', and comment out the __MIDL___MIDL_itf_dbgprop_0000_0001 and __MIDL___MIDL_itf_dbgprop_0000_0002 enums.
#if defined(__REQUIRED_RPCNDR_H_VERSION__) // for some strange reason, these no longer exist in dbgprop.h !?!? // enum __MIDL___MIDL_itf_dbgprop_0000_0001 // { DBGPROP_ATTRIB_NO_ATTRIB = 0, // DBGPROP_ATTRIB_VALUE_IS_INVALID = 0x8, // DBGPROP_ATTRIB_VALUE_IS_EXPANDABLE = 0x10, // DBGPROP_ATTRIB_VALUE_READONLY = 0x800, // DBGPROP_ATTRIB_ACCESS_PUBLIC = 0x1000, // DBGPROP_ATTRIB_ACCESS_PRIVATE = 0x2000, // DBGPROP_ATTRIB_ACCESS_PROTECTED = 0x4000, // DBGPROP_ATTRIB_ACCESS_FINAL = 0x8000, // DBGPROP_ATTRIB_STORAGE_GLOBAL = 0x10000, // DBGPROP_ATTRIB_STORAGE_STATIC = 0x20000, // DBGPROP_ATTRIB_STORAGE_FIELD = 0x40000, // DBGPROP_ATTRIB_STORAGE_VIRTUAL = 0x80000, // DBGPROP_ATTRIB_TYPE_IS_CONSTANT = 0x100000, // DBGPROP_ATTRIB_TYPE_IS_SYNCHRONIZED = 0x200000, // DBGPROP_ATTRIB_TYPE_IS_VOLATILE = 0x400000, // DBGPROP_ATTRIB_HAS_EXTENDED_ATTRIBS = 0x800000 // }; // typedef DWORD DBGPROP_ATTRIB_FLAGS; // enum __MIDL___MIDL_itf_dbgprop_0000_0002 // { DBGPROP_INFO_NAME = 0x1, // DBGPROP_INFO_TYPE = 0x2, // DBGPROP_INFO_VALUE = 0x4, // DBGPROP_INFO_FULLNAME = 0x20, // DBGPROP_INFO_ATTRIBUTES = 0x8, // DBGPROP_INFO_DEBUGPROP = 0x10, // DBGPROP_INFO_AUTOEXPAND = 0x8000000 // }; // typedef DWORD DBGPROP_INFO_FLAGS; enum { EX_DBGPROP_INFO_ID =0x0100, EX_DBGPROP_INFO_NTYPE =0x0200, EX_DBGPROP_INFO_NVALUE =0x0400, EX_DBGPROP_INFO_LOCKBYTES =0x0800, EX_DBGPROP_INFO_DEBUGEXTPROP =0x1000 }; #endif
Next, go in 'C:\temp\pywin32-219\com\win32comext\mapi\src\PyIMAPISession.cpp', line #778 and change
unsigned long connection;
to (Windows 8 or later only)
ULONG_PTR connection;
Next, go in 'C:\temp\pywin32-219\com\win32comext\mapi\src\PyIMAPITable.cpp', line #701 and change
_result = (HRESULT )_swig_self->Advise(_arg0,_arg1,_arg2);
to (Windows 8 or later)
_result = (HRESULT )_swig_self->Advise(_arg0,_arg1,reinterpret_cast<ULONG_PTR *>(_arg2));
to (previous Windows versions)
_result = (HRESULT )_swig_self->Advise(_arg0,_arg1,reinterpret_cast<unsigned long *>(_arg2));
and line #1284, from
_result = (HRESULT )_swig_self->CreateBookmark(_arg0);
to
_result = (HRESULT )_swig_self->CreateBookmark(reinterpret_cast<BookMark *>(_arg0));
Preparing build for VS2012
Last but not least, pywin32 is not ready for Visual Studio 2012 build, so you need to modify the setup.py file
Next, go in 'C:\temp\pywin32-219\setup.py', line #587-588 and change
if os.path.isfile(os.path.join(sdk_dir, "include", "activdbg.h")): kw.setdefault('extra_compile_args', []).append("/DHAVE_SDK_ACTIVDBG")
to (be careful on the indentation)
#if os.path.isfile(os.path.join(sdk_dir, "include", "activdbg.h")): kw.setdefault('extra_compile_args', []).append("/DHAVE_SDK_ACTIVDBG")
line #1062-1065, from
vckey = _winreg.OpenKey(_winreg.HKEY_LOCAL_MACHINE, product_key, 0, access) val, val_typ = _winreg.QueryValueEx(vckey, "ProductDir") mfc_dir = os.path.join(val, "redist", plat_dir, mfc_dir)
to (be careful on the indentation)
#vckey = _winreg.OpenKey(_winreg.HKEY_LOCAL_MACHINE, product_key, # 0, access) #val, val_typ = _winreg.QueryValueEx(vckey, "ProductDir") #mfc_dir = os.path.join(val, "redist", plat_dir, mfc_dir) mfc_dir =r'C:\Program Files (x86)\Microsoft Visual Studio 11.0\VC\redist\x64\Microsoft.VC110.MFC'
line #1973-2047, from
WinExt_win32com('shell', libraries='shell32', pch_header="shell_pch.h", windows_h_version = 0x600, sources=(""" %(shell)s/PyIActiveDesktop.cpp %(shell)s/PyIApplicationDestinations.cpp %(shell)s/PyIApplicationDocumentLists.cpp %(shell)s/PyIAsyncOperation.cpp %(shell)s/PyIBrowserFrameOptions.cpp %(shell)s/PyICategorizer.cpp %(shell)s/PyICategoryProvider.cpp %(shell)s/PyIColumnProvider.cpp %(shell)s/PyIContextMenu.cpp %(shell)s/PyIContextMenu2.cpp %(shell)s/PyIContextMenu3.cpp %(shell)s/PyICopyHook.cpp %(shell)s/PyICurrentItem.cpp %(shell)s/PyICustomDestinationList.cpp %(shell)s/PyIDefaultExtractIconInit.cpp %(shell)s/PyIDeskBand.cpp %(shell)s/PyIDisplayItem.cpp %(shell)s/PyIDockingWindow.cpp %(shell)s/PyIDropTargetHelper.cpp %(shell)s/PyIEnumExplorerCommand.cpp %(shell)s/PyIEnumIDList.cpp %(shell)s/PyIEnumObjects.cpp %(shell)s/PyIEnumResources.cpp %(shell)s/PyIEnumShellItems.cpp %(shell)s/PyIEmptyVolumeCache.cpp %(shell)s/PyIEmptyVolumeCacheCallBack.cpp %(shell)s/PyIExplorerBrowser.cpp %(shell)s/PyIExplorerBrowserEvents.cpp %(shell)s/PyIExplorerCommand.cpp %(shell)s/PyIExplorerCommandProvider.cpp %(shell)s/PyIExplorerPaneVisibility.cpp %(shell)s/PyIExtractIcon.cpp %(shell)s/PyIExtractIconW.cpp %(shell)s/PyIExtractImage.cpp %(shell)s/PyIFileOperation.cpp %(shell)s/PyIFileOperationProgressSink.cpp %(shell)s/PyIIdentityName.cpp %(shell)s/PyIInputObject.cpp %(shell)s/PyIKnownFolder.cpp %(shell)s/PyIKnownFolderManager.cpp %(shell)s/PyINameSpaceTreeControl.cpp %(shell)s/PyIObjectArray.cpp %(shell)s/PyIObjectCollection.cpp %(shell)s/PyIPersistFolder.cpp %(shell)s/PyIPersistFolder2.cpp %(shell)s/PyIQueryAssociations.cpp %(shell)s/PyIRelatedItem.cpp %(shell)s/PyIShellBrowser.cpp %(shell)s/PyIShellExtInit.cpp %(shell)s/PyIShellFolder.cpp %(shell)s/PyIShellFolder2.cpp %(shell)s/PyIShellIcon.cpp %(shell)s/PyIShellIconOverlay.cpp %(shell)s/PyIShellIconOverlayIdentifier.cpp %(shell)s/PyIShellIconOverlayManager.cpp %(shell)s/PyIShellItem.cpp %(shell)s/PyIShellItem2.cpp %(shell)s/PyIShellItemArray.cpp %(shell)s/PyIShellItemResources.cpp %(shell)s/PyIShellLibrary.cpp %(shell)s/PyIShellLink.cpp %(shell)s/PyIShellLinkDataList.cpp %(shell)s/PyIShellView.cpp %(shell)s/PyITaskbarList.cpp %(shell)s/PyITransferAdviseSink.cpp %(shell)s/PyITransferDestination.cpp %(shell)s/PyITransferMediumItem.cpp %(shell)s/PyITransferSource.cpp %(shell)s/PyIUniformResourceLocator.cpp %(shell)s/shell.cpp """ % dirs).split()),
to (be careful on the indentation)
# WinExt_win32com('shell', libraries='shell32', pch_header="shell_pch.h", # windows_h_version = 0x600, # sources=(""" # %(shell)s/PyIActiveDesktop.cpp # %(shell)s/PyIApplicationDestinations.cpp # %(shell)s/PyIApplicationDocumentLists.cpp # %(shell)s/PyIAsyncOperation.cpp # %(shell)s/PyIBrowserFrameOptions.cpp # %(shell)s/PyICategorizer.cpp # %(shell)s/PyICategoryProvider.cpp # %(shell)s/PyIColumnProvider.cpp # %(shell)s/PyIContextMenu.cpp # %(shell)s/PyIContextMenu2.cpp # %(shell)s/PyIContextMenu3.cpp # %(shell)s/PyICopyHook.cpp # %(shell)s/PyICurrentItem.cpp # %(shell)s/PyICustomDestinationList.cpp # %(shell)s/PyIDefaultExtractIconInit.cpp # %(shell)s/PyIDeskBand.cpp # %(shell)s/PyIDisplayItem.cpp # %(shell)s/PyIDockingWindow.cpp # %(shell)s/PyIDropTargetHelper.cpp # %(shell)s/PyIEnumExplorerCommand.cpp # %(shell)s/PyIEnumIDList.cpp # %(shell)s/PyIEnumObjects.cpp # %(shell)s/PyIEnumResources.cpp # %(shell)s/PyIEnumShellItems.cpp # %(shell)s/PyIEmptyVolumeCache.cpp # %(shell)s/PyIEmptyVolumeCacheCallBack.cpp # %(shell)s/PyIExplorerBrowser.cpp # %(shell)s/PyIExplorerBrowserEvents.cpp # %(shell)s/PyIExplorerCommand.cpp # %(shell)s/PyIExplorerCommandProvider.cpp # %(shell)s/PyIExplorerPaneVisibility.cpp # %(shell)s/PyIExtractIcon.cpp # %(shell)s/PyIExtractIconW.cpp # %(shell)s/PyIExtractImage.cpp # %(shell)s/PyIFileOperation.cpp # %(shell)s/PyIFileOperationProgressSink.cpp # %(shell)s/PyIIdentityName.cpp # %(shell)s/PyIInputObject.cpp # %(shell)s/PyIKnownFolder.cpp # %(shell)s/PyIKnownFolderManager.cpp # %(shell)s/PyINameSpaceTreeControl.cpp # %(shell)s/PyIObjectArray.cpp # %(shell)s/PyIObjectCollection.cpp # %(shell)s/PyIPersistFolder.cpp # %(shell)s/PyIPersistFolder2.cpp # %(shell)s/PyIQueryAssociations.cpp # %(shell)s/PyIRelatedItem.cpp # %(shell)s/PyIShellBrowser.cpp # %(shell)s/PyIShellExtInit.cpp # %(shell)s/PyIShellFolder.cpp # %(shell)s/PyIShellFolder2.cpp # %(shell)s/PyIShellIcon.cpp # %(shell)s/PyIShellIconOverlay.cpp # %(shell)s/PyIShellIconOverlayIdentifier.cpp # %(shell)s/PyIShellIconOverlayManager.cpp # %(shell)s/PyIShellItem.cpp # %(shell)s/PyIShellItem2.cpp # %(shell)s/PyIShellItemArray.cpp # %(shell)s/PyIShellItemResources.cpp # %(shell)s/PyIShellLibrary.cpp # %(shell)s/PyIShellLink.cpp # %(shell)s/PyIShellLinkDataList.cpp # %(shell)s/PyIShellView.cpp # %(shell)s/PyITaskbarList.cpp # %(shell)s/PyITransferAdviseSink.cpp # %(shell)s/PyITransferDestination.cpp # %(shell)s/PyITransferMediumItem.cpp # %(shell)s/PyITransferSource.cpp # %(shell)s/PyIUniformResourceLocator.cpp # %(shell)s/shell.cpp # """ % dirs).split()),
Building
Run a VS2012 x64 Native Tool command prompt as Administrator, and execute the following script (for sure make edits as appropriate)
@echo off set MOBUPYWIN32BUILD=%~dp0 set MOBUPYWIN32BUILD=%MOBUPYWIN32BUILD:~0,-1% if exist v:\nul subst v: /d subst v: "%MOBUPYWIN32BUILD%" v: set PYWIN32_VERSION=pywin32-219 set MAYA_LOCATION=C:\Program Files\Autodesk\Maya2015 if exist m:\nul subst m: /d subst m: "%MAYA_LOCATION%" set MAYA_LOCATION=m: set MOBU_LOCATION=C:\Program Files\Autodesk\MotionBuilder 2015 if exist n:\nul subst n: /d subst n: "%MOBU_LOCATION%" set MOBU_LOCATION=n: set MSVC_VERSION=2012 set MSVC_DIR=C:\Program Files (x86)\Microsoft Visual Studio 11.0 rem if [%LIBPATH%]==[] call "%MSVC_DIR%\VC\vcvarsall" amd64 set VS90COMNTOOLS=%VS110COMNTOOLS% set VS100COMNTOOLS=%VS110COMNTOOLS% set PATH=%PATH%;C:\Program Files (x86)\Microsoft Visual Studio 11.0\VC call vcvarsall.bat x86_amd64 set INCLUDE=%INCLUDE%;%MOBU_LOCATION%\OpenRealitySDK\include\python-2.7.3\include set LIB=%LIB%;%MOBU_LOCATION%\OpenRealitySDK\lib\x64 set PYWIN32DIR=v:\%PYWIN32_VERSION% cd %PYWIN32DIR% %MAYA_LOCATION%\bin\mayapy.exe setup.py -q build --plat-name=win-amd64 rem C:\Python27\Python setup.py -q build --plat-name=win-amd64 C:\Python27\Python setup.py -q install xcopy "C:\Python27\Lib\site-packages\*.*" n:\bin\x64\python\site-packages /s /v
Testing
To test, start MotionBuilder 2015, open the Python Editor and copy paste the following script
import win32com.client o = win32com.client.Dispatch("Excel.Application") o.Visible = 1 o.Workbooks.Add() o.Cells(1,1).Value = "Hello"
If Excel is showing, you are all set :)
Thanks for this Cyrille!
I built pywin32 for Maya and Mobu, well over a year but in a more rough manner. This looks like a much better approach than I took modifying flags within manifest files and such.
Posted by: Randall Hess | October 01, 2014 at 06:29 AM