├── test ├── relative_import │ ├── __init__.py │ ├── sys.py │ └── x │ │ └── __init__.py ├── test_2+2.py ├── test_noZipFile.py ├── test_sys_path.py ├── setup_noZipFile.py ├── checkTestModule.py ├── test_win32com_shell.py ├── test_xml_xpath.py ├── test_relative_import.py ├── test_pysvn.py ├── reinstall.cmd ├── test_EasyDialogs.py ├── setup_win32com_shell.py └── test.py ├── py2exe ├── resources │ ├── __init__.py │ ├── VersionInfo.py │ └── StringTables.py ├── samples │ ├── advanced │ │ ├── icon.ico │ │ ├── test_wmi.py │ │ ├── test_wx.py │ │ ├── MyService.py │ │ └── setup.py │ ├── simple │ │ ├── hello.py │ │ ├── test_wx.py │ │ └── setup.py │ ├── pywin32 │ │ ├── com_server │ │ │ ├── test_interp.vbs │ │ │ ├── setup.py │ │ │ ├── test_interp.py │ │ │ └── README.txt │ │ ├── isapi │ │ │ ├── README.txt │ │ │ └── setup.py │ │ └── com_typelib │ │ │ ├── build_gen │ │ │ └── word │ │ │ │ ├── setup.py │ │ │ │ └── docmaker.py │ │ │ ├── pre_gen │ │ │ └── wscript │ │ │ │ ├── setup.py │ │ │ │ └── show_info.py │ │ │ └── README.txt │ ├── singlefile │ │ ├── comserver │ │ │ ├── test.py │ │ │ ├── setup_client.py │ │ │ └── setup.py │ │ └── gui │ │ │ ├── test_wx.py │ │ │ └── setup.py │ ├── user_access_control │ │ ├── hello.py │ │ ├── setup.py │ │ └── README.txt │ └── extending │ │ ├── test_wx.py │ │ └── setup.py ├── boot_ctypes_com_server.py ├── __init__.py ├── boot_common.py ├── boot_com_servers.py └── boot_service.py ├── docs ├── py2exe.jpg ├── html.cmd ├── updateweb.cmd ├── LICENSE.txt ├── default.css └── py2exe.txt ├── source ├── icon1.ico ├── MyLoadLibrary.h ├── Python-version.h ├── resource.h ├── icon.rc ├── actctx.c ├── actctx.h ├── Python-dynload.h ├── run.c ├── import-tab.c ├── _memimporter.c ├── Python-dynload.c ├── run_w.c ├── MemoryModule.h ├── import-tab.h ├── mktab.py ├── MyLoadLibrary.c ├── run_ctypes_dll.c ├── run_isapi.c ├── run_dll.c └── start.c ├── sandbox └── test │ ├── hello.py │ ├── setup.cfg │ ├── setup_all.py │ ├── test_wx.py │ └── test_interp.vbs ├── upload └── updateweb.cmd ├── MANIFEST.in ├── README.txt ├── zipextimporter.py ├── ANNOUNCE └── ChangeLog /test/relative_import/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /test/relative_import/sys.py: -------------------------------------------------------------------------------- 1 | maxint = 12 2 | -------------------------------------------------------------------------------- /py2exe/resources/__init__.py: -------------------------------------------------------------------------------- 1 | # package to build resources. 2 | -------------------------------------------------------------------------------- /test/test_2+2.py: -------------------------------------------------------------------------------- 1 | if __name__ == "__main__": 2 | print 2+2 3 | -------------------------------------------------------------------------------- /test/test_noZipFile.py: -------------------------------------------------------------------------------- 1 | if __name__ == "__main__": 2 | print 2+2 3 | -------------------------------------------------------------------------------- /docs/py2exe.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/goatpig/py2exe/HEAD/docs/py2exe.jpg -------------------------------------------------------------------------------- /source/icon1.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/goatpig/py2exe/HEAD/source/icon1.ico -------------------------------------------------------------------------------- /sandbox/test/hello.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/goatpig/py2exe/HEAD/sandbox/test/hello.py -------------------------------------------------------------------------------- /docs/html.cmd: -------------------------------------------------------------------------------- 1 | rst2html.py --stylesheet-path=default.css --link-stylesheet py2exe.txt index.html 2 | -------------------------------------------------------------------------------- /docs/updateweb.cmd: -------------------------------------------------------------------------------- 1 | scp index.html default.css LICENSE.txt py2exe.jpg jretz@py2exe.org:~/py2exe.org/old 2 | -------------------------------------------------------------------------------- /test/test_sys_path.py: -------------------------------------------------------------------------------- 1 | import sys 2 | 3 | if __name__ == "__main__": 4 | print 1 < len(sys.path) < 5 5 | -------------------------------------------------------------------------------- /py2exe/resources/VersionInfo.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/goatpig/py2exe/HEAD/py2exe/resources/VersionInfo.py -------------------------------------------------------------------------------- /py2exe/samples/advanced/icon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/goatpig/py2exe/HEAD/py2exe/samples/advanced/icon.ico -------------------------------------------------------------------------------- /sandbox/test/setup.cfg: -------------------------------------------------------------------------------- 1 | [py2exe] 2 | packages = encodings 3 | includes = win32com.server.policy 4 | excludes = pywin 5 | -------------------------------------------------------------------------------- /test/relative_import/x/__init__.py: -------------------------------------------------------------------------------- 1 | from __future__ import absolute_import 2 | 3 | import sys as a 4 | from .. import sys as b 5 | 6 | def foo(): pass 7 | -------------------------------------------------------------------------------- /test/setup_noZipFile.py: -------------------------------------------------------------------------------- 1 | from distutils.core import setup 2 | import py2exe 3 | 4 | setup( 5 | console=['%s'], 6 | zipfile=None, 7 | ) 8 | -------------------------------------------------------------------------------- /test/checkTestModule.py: -------------------------------------------------------------------------------- 1 | import sys 2 | 3 | try: 4 | __import__(sys.argv[1]) 5 | except Exception, details: 6 | print details 7 | sys.exit(1) 8 | sys.exit(0) 9 | -------------------------------------------------------------------------------- /py2exe/samples/advanced/test_wmi.py: -------------------------------------------------------------------------------- 1 | import wmi # Tim Golden's wmi module. 2 | 3 | computer = wmi.WMI() 4 | 5 | for item in computer.Win32_Process()[:2]: 6 | print item 7 | -------------------------------------------------------------------------------- /test/test_win32com_shell.py: -------------------------------------------------------------------------------- 1 | from win32com.shell import shellcon, shell 2 | 3 | if __name__ == "__main__": 4 | print shell.SHGetFolderPath(0, shellcon.CSIDL_DESKTOP, 0, 0) 5 | -------------------------------------------------------------------------------- /test/test_xml_xpath.py: -------------------------------------------------------------------------------- 1 | # This tests http://sourceforge.net/project/showfiles.php?group_id=6473 2 | 3 | import xml.xpath 4 | 5 | if __name__ == "__main__": 6 | print xml.xpath.Init() 7 | -------------------------------------------------------------------------------- /test/test_relative_import.py: -------------------------------------------------------------------------------- 1 | import relative_import.x 2 | import relative_import.x.module 3 | 4 | if __name__ == "__main__": 5 | print relative_import.x.a.maxint 6 | print relative_import.x.b.maxint 7 | -------------------------------------------------------------------------------- /upload/updateweb.cmd: -------------------------------------------------------------------------------- 1 | scp ..\py2exe-samples-0.3.1.zip py2exe-0.3.1.win32-py1.5.exe py2exe-0.3.1.win32-py2.0.exe py2exe-0.3.1.win32-py2.1.exe py2exe-0.3.1.win32-py2.2.exe py2exe-0.3.1.zip ..\LICENSE.txt theller@starship.python.net:~/public_html/py2exe 2 | -------------------------------------------------------------------------------- /MANIFEST.in: -------------------------------------------------------------------------------- 1 | include MANIFEST.in ANNOUNCE 2 | recursive-include py2exe *.h *.c *.ico *.rc *.py *.txt *.vbs 3 | recursive-include source *.h *.c *.ico *.rc *.py *.txt 4 | recursive-include test *.h *.c *.ico *.rc *.py *.txt 5 | recursive-include docs *.txt *.css *.html *.py 6 | -------------------------------------------------------------------------------- /py2exe/samples/simple/hello.py: -------------------------------------------------------------------------------- 1 | import sys 2 | 3 | print "Hello from py2exe" 4 | 5 | print "frozen", repr(getattr(sys, "frozen", None)) 6 | 7 | print "sys.path", sys.path 8 | print "sys.executable", sys.executable 9 | print "sys.prefix", sys.prefix 10 | print "sys.argv", sys.argv 11 | 12 | -------------------------------------------------------------------------------- /source/MyLoadLibrary.h: -------------------------------------------------------------------------------- 1 | #ifndef GENERALLOADLIBRARY_H 2 | #define GENERALLOADLIBRARY_H 3 | 4 | HMODULE MyLoadLibrary(LPCSTR, void *, void *); 5 | 6 | HMODULE MyGetModuleHandle(LPCSTR); 7 | 8 | BOOL MyFreeLibrary(HMODULE); 9 | 10 | FARPROC MyGetProcAddress(HMODULE, LPCSTR); 11 | 12 | 13 | #endif 14 | -------------------------------------------------------------------------------- /sandbox/test/setup_all.py: -------------------------------------------------------------------------------- 1 | from distutils.core import setup 2 | import py2exe 3 | 4 | setup(#name="name", 5 | windows=["test_wx.py"], 6 | ## service=["a.b.c.d"], 7 | com_server = ["win32com.servers.interp"], 8 | console=["hello.py"], 9 | zipfile="application", 10 | ) 11 | -------------------------------------------------------------------------------- /test/test_pysvn.py: -------------------------------------------------------------------------------- 1 | import pysvn 2 | 3 | if __name__ == "__main__": 4 | # the py2exe wrapper for this test doesn't pick up the svn 5 | # lib installed with pysvn so it can report a different 6 | # version number, so just make sure we can get the version 7 | # number and that the major version is the same 8 | print pysvn.version[0] 9 | -------------------------------------------------------------------------------- /sandbox/test/test_wx.py: -------------------------------------------------------------------------------- 1 | import sys 2 | print "PATH", sys.path 3 | 4 | from wxPython.wx import * 5 | 6 | class MyApp(wxApp): 7 | def OnInit(self): 8 | frame = wxFrame(NULL, -1, "Hello from wxPython") 9 | frame.Show(true) 10 | self.SetTopWindow(frame) 11 | return true 12 | 13 | app = MyApp(0) 14 | app.MainLoop() 15 | -------------------------------------------------------------------------------- /test/reinstall.cmd: -------------------------------------------------------------------------------- 1 | "C:\Python23\Removepy2exe.exe" -u "C:\Python23\py2exe-wininst.log" 2 | "C:\Python24\Removepy2exe.exe" -u "C:\Python24\py2exe-wininst.log" 3 | "C:\Python25\Removepy2exe.exe" -u "C:\Python25\py2exe-wininst.log" 4 | 5 | for %%f in (..\dist\py2exe*.exe) do ( 6 | "%%f" 7 | ) 8 | 9 | for %%f in (..\dist\py2exe*.msi) do ( 10 | "%%f" 11 | ) 12 | -------------------------------------------------------------------------------- /test/test_EasyDialogs.py: -------------------------------------------------------------------------------- 1 | import sys 2 | import time 3 | 4 | import EasyDialogs 5 | 6 | if __name__ == "__main__": 7 | progressBar = EasyDialogs.ProgressBar('Testing py2exe', 100, 'Testing, testing, 1-2-3...') 8 | for i in range(100): 9 | time.sleep(0.001) 10 | progressBar.inc() 11 | 12 | print progressBar.curval 13 | sys.exit(progressBar.curval) 14 | -------------------------------------------------------------------------------- /sandbox/test/test_interp.vbs: -------------------------------------------------------------------------------- 1 | ' A VBScript test harness for our test interpreter 2 | ' Running under cscript.exe is more useful than wscript.exe 3 | ' eg: cscript.exe test_interp.vbs 4 | 5 | set interp = CreateObject("Python.Interpreter") 6 | interp.Exec("import sys") 7 | WScript.Echo "This Python object is being hosted in " & interp.Eval("sys.executable") 8 | WScript.Echo "Path is " & interp.Eval("str(sys.path)") -------------------------------------------------------------------------------- /py2exe/samples/pywin32/com_server/test_interp.vbs: -------------------------------------------------------------------------------- 1 | rem A VBScript program that uses the py2exe created COM object. 2 | rem Register the object (see README.txt), then execute: 3 | rem cscript.exe test_interp.vbs 4 | set interp = CreateObject("Python.Interpreter") 5 | interp.Exec "import sys" 6 | 7 | WScript.Echo("The COM object is being hosted in " & interp.Eval("sys.executable")) 8 | WScript.Echo("Path is:" & interp.Eval("str(sys.path)")) 9 | -------------------------------------------------------------------------------- /py2exe/samples/singlefile/comserver/test.py: -------------------------------------------------------------------------------- 1 | import sys 2 | from win32com.client import Dispatch 3 | 4 | d = Dispatch("Python.Interpreter") 5 | print "2 + 5 =", d.Eval("2 + 5") 6 | d.Exec("print 'hi via COM'") 7 | 8 | d.Exec("import sys") 9 | 10 | print "COM server sys.version", d.Eval("sys.version") 11 | print "Client sys.version", sys.version 12 | 13 | print "COM server sys.path", d.Eval("sys.path") 14 | print "Client sys.path", sys.path 15 | -------------------------------------------------------------------------------- /source/Python-version.h: -------------------------------------------------------------------------------- 1 | #include 2 | #if (PY_VERSION_HEX < 0x02050000) 3 | # define PYTHON_API_VERSION 1012 4 | typedef int Py_ssize_t; 5 | #else 6 | # define PYTHON_API_VERSION 1013 7 | /* The check for _WIN64 must come first, because on win64 both _WIN64 and 8 | * _WIN32 are defined! 9 | */ 10 | # if defined (_WIN64) 11 | typedef __int64 Py_ssize_t; 12 | # elif defined (_WIN32) 13 | typedef int Py_ssize_t; 14 | # endif 15 | #endif 16 | -------------------------------------------------------------------------------- /py2exe/samples/pywin32/com_server/setup.py: -------------------------------------------------------------------------------- 1 | # setup_interp.py 2 | # A distutils setup script for the "interp" sample. 3 | 4 | from distutils.core import setup 5 | import py2exe 6 | 7 | # Don't pull in all this MFC stuff used by the makepy UI. 8 | py2exe_options = dict(excludes="pywin,pywin.dialogs,pywin.dialogs.list,win32ui") 9 | 10 | setup(name="win32com 'interp' sample", 11 | com_server=["win32com.servers.interp"], 12 | options = dict(py2exe=py2exe_options) 13 | ) 14 | -------------------------------------------------------------------------------- /py2exe/samples/pywin32/com_server/test_interp.py: -------------------------------------------------------------------------------- 1 | # A Python program that uses our binaries! 2 | # (Note that this is *not* transformed into a .exe - its an example consumer 3 | # of our object, not part of our object) 4 | 5 | from win32com.client import Dispatch 6 | import pprint 7 | 8 | interp = Dispatch("Python.Interpreter") 9 | interp.Exec("import sys") 10 | 11 | print "The COM object is being hosted in ", interp.Eval("sys.executable") 12 | print "Path is:", interp.Eval("sys.path") 13 | -------------------------------------------------------------------------------- /py2exe/samples/pywin32/isapi/README.txt: -------------------------------------------------------------------------------- 1 | A pywin32 ISAPI sample. 2 | 3 | This builds the pywin32 isapi 'redirector' sample (see 4 | site-packages\isapi\samples) into a py2exe distribution. Execute: 5 | 6 | setup.py py2exe 7 | 8 | and in the 'dist' directory you will find 'redirector.exe' (used to 9 | register/unregister the ISAPI extension), and 'redirector.dll' (the ISAPI 10 | filter and extension loaded by IIS.) 11 | 12 | See the pywin32 sample for more details about how to use the sample. 13 | -------------------------------------------------------------------------------- /py2exe/samples/pywin32/isapi/setup.py: -------------------------------------------------------------------------------- 1 | # setup_interp.py 2 | # A distutils setup script for the ISAPI "redirector" sample. 3 | import os 4 | from distutils.core import setup 5 | import py2exe 6 | 7 | # Find the ISAPI sample - the redirector. 8 | import isapi 9 | script = os.path.join(isapi.__path__[0], "samples", "redirector.py") 10 | 11 | setup(name="ISAPI sample", 12 | # The ISAPI dll. 13 | isapi = [script], 14 | # command-line installation tool. 15 | console=[script], 16 | ) 17 | -------------------------------------------------------------------------------- /source/resource.h: -------------------------------------------------------------------------------- 1 | //{{NO_DEPENDENCIES}} 2 | // Microsoft Developer Studio generated include file. 3 | // Used by icon.rc 4 | // 5 | #define IDI_ICON1 101 6 | 7 | // Next default values for new objects 8 | // 9 | #ifdef APSTUDIO_INVOKED 10 | #ifndef APSTUDIO_READONLY_SYMBOLS 11 | #define _APS_NEXT_RESOURCE_VALUE 103 12 | #define _APS_NEXT_COMMAND_VALUE 40001 13 | #define _APS_NEXT_CONTROL_VALUE 1000 14 | #define _APS_NEXT_SYMED_VALUE 101 15 | #endif 16 | #endif 17 | -------------------------------------------------------------------------------- /py2exe/samples/pywin32/com_typelib/build_gen/word/setup.py: -------------------------------------------------------------------------------- 1 | # Execute this as 'setup.py py2exe' to create a .exe from docmaker.py 2 | from distutils.core import setup 3 | import py2exe 4 | 5 | py2exe_options = dict( 6 | typelibs = [ 7 | # typelib for 'Word.Application.8' - execute 8 | # 'win32com/client/makepy.py -i' to find a typelib. 9 | ('{00020905-0000-0000-C000-000000000046}', 0, 8, 1), 10 | ] 11 | ) 12 | 13 | setup(name="SpamBayes", 14 | console=["docmaker.py"], 15 | options = {"py2exe" : py2exe_options}, 16 | ) 17 | -------------------------------------------------------------------------------- /py2exe/samples/pywin32/com_typelib/pre_gen/wscript/setup.py: -------------------------------------------------------------------------------- 1 | # Execute this as 'setup.py py2exe' to create a .exe from docmaker.py 2 | from distutils.core import setup 3 | import py2exe 4 | 5 | py2exe_options = dict( 6 | typelibs = [ 7 | # typelib for 'Windows Script Host Object Model', which we 8 | # have pre-generated into wsh-typelib-stubs.py 9 | ('{F935DC20-1CF0-11D0-ADB9-00C04FD58A0B}', 0, 1, 0, 'wsh-typelib-stubs.py'), 10 | ] 11 | ) 12 | 13 | setup(name="SpamBayes", 14 | console=["show_info.py"], 15 | options = {"py2exe" : py2exe_options}, 16 | ) 17 | -------------------------------------------------------------------------------- /py2exe/samples/pywin32/com_typelib/pre_gen/wscript/show_info.py: -------------------------------------------------------------------------------- 1 | # Print some simple information using the WScript.Network object. 2 | import sys 3 | from win32com.client.gencache import EnsureDispatch 4 | 5 | ob = EnsureDispatch('WScript.Network') 6 | 7 | # For the sake of ensuring the correct module is used... 8 | mod = sys.modules[ob.__module__] 9 | print "The module hosting the object is", mod 10 | 11 | # Now use the object. 12 | print "About this computer:" 13 | print "Domain =", ob.UserDomain 14 | print "Computer Name =", ob.ComputerName 15 | print "User Name =", ob.UserName 16 | 17 | 18 | -------------------------------------------------------------------------------- /py2exe/samples/pywin32/com_server/README.txt: -------------------------------------------------------------------------------- 1 | This is a sample of a COM object ('server') implemented in Python. 2 | 3 | This builds the pywin32 sample COM object 'interp' - see the win32com\servers 4 | directory. 5 | 6 | Execute: 7 | 8 | setup.py py2exe 9 | 10 | And in the dist directory you will find interp.exe and inter.dll. 11 | 12 | You can register the objects with 'interp.exe /regserver' or 13 | 'regsvr32 interp.dll'. 'interp.exe /unregister' and 'regsvr32 /u interp.dll' 14 | will unregister the objects. 15 | 16 | Once registered, test the object using 'test_interp.py' or 'test_interp.vbs' -------------------------------------------------------------------------------- /test/setup_win32com_shell.py: -------------------------------------------------------------------------------- 1 | import sys 2 | 3 | # ModuleFinder can't handle runtime changes to __path__, but win32com uses them 4 | 5 | try: 6 | import modulefinder 7 | import win32com 8 | for p in win32com.__path__[1:]: 9 | modulefinder.AddPackagePath("win32com", p) 10 | for extra in ["win32com.shell"]: #,"win32com.mapi" 11 | __import__(extra) 12 | m = sys.modules[extra] 13 | for p in m.__path__[1:]: 14 | modulefinder.AddPackagePath(extra, p) 15 | except ImportError: 16 | # no build path setup, no worries. 17 | pass 18 | 19 | from distutils.core import setup 20 | import py2exe 21 | 22 | setup( 23 | console=['%s'], 24 | ) 25 | -------------------------------------------------------------------------------- /py2exe/samples/singlefile/comserver/setup_client.py: -------------------------------------------------------------------------------- 1 | # This setup script builds a single-file Python inprocess COM server. 2 | # 3 | from distutils.core import setup 4 | import py2exe 5 | import sys 6 | 7 | # If run without args, build executables, in quiet mode. 8 | if len(sys.argv) == 1: 9 | sys.argv.append("py2exe") 10 | sys.argv.append("-q") 11 | 12 | ################################################################ 13 | # pywin32 COM pulls in a lot of stuff which we don't want or need. 14 | 15 | excludes = ["pywin", "pywin.debugger", "pywin.debugger.dbgcon", 16 | "pywin.dialogs", "pywin.dialogs.list", "win32com.server"] 17 | 18 | options = { 19 | "bundle_files": 1, # create singlefile exe 20 | "compressed": 1, # compress the library archive 21 | "excludes": excludes, 22 | "dll_excludes": ["w9xpopen.exe"] # we don't need this 23 | } 24 | 25 | setup( 26 | options = {"py2exe": options}, 27 | zipfile = None, # append zip-archive to the executable. 28 | console = ["test.py"] 29 | ) 30 | -------------------------------------------------------------------------------- /py2exe/samples/user_access_control/hello.py: -------------------------------------------------------------------------------- 1 | import sys 2 | import optparse 3 | 4 | def main(): 5 | parser = optparse.OptionParser() 6 | # Main point here is showing that writing to stderr 7 | # currently forces py2exe to write a .log file next 8 | # to the executable, but that might not always work. 9 | # README.txt relies on that to demonstrate different 10 | # behaviour for the different manifest values, so 11 | # if this changes, be sure to also ensure README.txt 12 | # stays accurate. 13 | parser.add_option("-e", "--write-err", 14 | action="store", 15 | help="a message to write to stderr.") 16 | 17 | parser.add_option("-o", "--write-out", 18 | action="store", 19 | help="a message to write to stdout.") 20 | 21 | opts, args = parser.parse_args() 22 | if opts.write_err: 23 | sys.stderr.write(opts.write_err + "\n") 24 | if opts.write_out: 25 | sys.stderr.write(opts.write_out+ "\n") 26 | 27 | if __name__=='__main__': 28 | main() 29 | -------------------------------------------------------------------------------- /py2exe/samples/simple/test_wx.py: -------------------------------------------------------------------------------- 1 | from wxPython.wx import * 2 | 3 | class MyFrame(wxFrame): 4 | def __init__(self, parent, ID, title, pos=wxDefaultPosition, 5 | size=(200, 200), style=wxDEFAULT_FRAME_STYLE): 6 | wxFrame.__init__(self, parent, ID, title, pos, size, style) 7 | panel = wxPanel(self, -1) 8 | 9 | button = wxButton(panel, 1003, "Close Me") 10 | button.SetPosition(wxPoint(15, 15)) 11 | EVT_BUTTON(self, 1003, self.OnCloseMe) 12 | EVT_CLOSE(self, self.OnCloseWindow) 13 | 14 | button = wxButton(panel, 1004, "Press Me") 15 | button.SetPosition(wxPoint(15, 45)) 16 | EVT_BUTTON(self, 1004, self.OnPressMe) 17 | 18 | def OnCloseMe(self, event): 19 | self.Close(True) 20 | 21 | def OnPressMe(self, event): 22 | x = 1 / 0 23 | 24 | def OnCloseWindow(self, event): 25 | self.Destroy() 26 | 27 | class MyApp(wxApp): 28 | def OnInit(self): 29 | frame = MyFrame(NULL, -1, "Hello from wxPython") 30 | frame.Show(true) 31 | self.SetTopWindow(frame) 32 | return true 33 | 34 | app = MyApp(0) 35 | app.MainLoop() 36 | -------------------------------------------------------------------------------- /docs/LICENSE.txt: -------------------------------------------------------------------------------- 1 | Copyright (c) 2000-2008 Thomas Heller, Mark Hammond, Jimmy Retzlaff 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining 4 | a copy of this software and associated documentation files (the 5 | "Software"), to deal in the Software without restriction, including 6 | without limitation the rights to use, copy, modify, merge, publish, 7 | distribute, sublicense, and/or sell copies of the Software, and to 8 | permit persons to whom the Software is furnished to do so, subject to 9 | the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be 12 | included in all copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 15 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 16 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 17 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 18 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 19 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 20 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | -------------------------------------------------------------------------------- /py2exe/samples/advanced/test_wx.py: -------------------------------------------------------------------------------- 1 | from wxPython.wx import * 2 | 3 | class MyFrame(wxFrame): 4 | def __init__(self, parent, ID, title, pos=wxDefaultPosition, 5 | size=(200, 200), style=wxDEFAULT_FRAME_STYLE): 6 | wxFrame.__init__(self, parent, ID, title, pos, size, style) 7 | panel = wxPanel(self, -1) 8 | 9 | button = wxButton(panel, 1003, "Close Me") 10 | button.SetPosition(wxPoint(15, 15)) 11 | EVT_BUTTON(self, 1003, self.OnCloseMe) 12 | EVT_CLOSE(self, self.OnCloseWindow) 13 | 14 | button = wxButton(panel, 1004, "Press Me") 15 | button.SetPosition(wxPoint(15, 45)) 16 | EVT_BUTTON(self, 1004, self.OnPressMe) 17 | 18 | def OnCloseMe(self, event): 19 | self.Close(True) 20 | 21 | def OnPressMe(self, event): 22 | # This raises an exception 23 | x = 1 / 0 24 | 25 | def OnCloseWindow(self, event): 26 | self.Destroy() 27 | 28 | class MyApp(wxApp): 29 | def OnInit(self): 30 | frame = MyFrame(NULL, -1, "Hello from wxPython") 31 | frame.Show(true) 32 | self.SetTopWindow(frame) 33 | return true 34 | 35 | app = MyApp(0) 36 | app.MainLoop() 37 | -------------------------------------------------------------------------------- /py2exe/samples/extending/test_wx.py: -------------------------------------------------------------------------------- 1 | from wxPython.wx import * 2 | 3 | class MyFrame(wxFrame): 4 | def __init__(self, parent, ID, title, pos=wxDefaultPosition, 5 | size=(200, 200), style=wxDEFAULT_FRAME_STYLE): 6 | wxFrame.__init__(self, parent, ID, title, pos, size, style) 7 | panel = wxPanel(self, -1) 8 | 9 | button = wxButton(panel, 1003, "Close Me") 10 | button.SetPosition(wxPoint(15, 15)) 11 | EVT_BUTTON(self, 1003, self.OnCloseMe) 12 | EVT_CLOSE(self, self.OnCloseWindow) 13 | 14 | button = wxButton(panel, 1004, "Press Me") 15 | button.SetPosition(wxPoint(15, 45)) 16 | EVT_BUTTON(self, 1004, self.OnPressMe) 17 | 18 | def OnCloseMe(self, event): 19 | self.Close(True) 20 | 21 | def OnPressMe(self, event): 22 | # This raises an exception 23 | x = 1 / 0 24 | 25 | def OnCloseWindow(self, event): 26 | self.Destroy() 27 | 28 | class MyApp(wxApp): 29 | def OnInit(self): 30 | frame = MyFrame(NULL, -1, "Hello from wxPython") 31 | frame.Show(true) 32 | self.SetTopWindow(frame) 33 | return true 34 | 35 | app = MyApp(0) 36 | app.MainLoop() 37 | -------------------------------------------------------------------------------- /docs/default.css: -------------------------------------------------------------------------------- 1 | body, th, td { 2 | font-family: verdana, Arial, sans-serif; 3 | font-size: 70%; 4 | } 5 | 6 | P, DL, table { 7 | margin-left: 2em; 8 | margin-right: 2em; 9 | } 10 | 11 | H1, H2, H3, H4, H5, H6 { 12 | font-family: verdana, Arial, sans-serif; 13 | color: #000080; 14 | } 15 | 16 | H1 { 17 | /* font-size: 145%; */ 18 | font-size: 160%; 19 | } 20 | 21 | H2 { 22 | /* font-size: 130%; */ 23 | font-size: 140%; 24 | } 25 | 26 | H3 { 27 | font-size: 115%; 28 | } 29 | 30 | H4 { 31 | font-size: 100%; 32 | } 33 | 34 | table { 35 | background: #808080; 36 | } 37 | 38 | th { 39 | background: #C0C0E0; 40 | font-weight: bold; 41 | } 42 | 43 | td { 44 | background: #F0F0F0; 45 | } 46 | 47 | pre { 48 | border-style: solid; 49 | border-width: 1px; 50 | 51 | background: #C0C0E0; 52 | 53 | font-family: Courier New, Courier, mono; 54 | font-size: 120%; 55 | 56 | padding-top: 1em; 57 | padding-left: 1em; 58 | padding-bottom: 1em; 59 | 60 | margin-left: 4em; 61 | margin-right: 4em; 62 | } 63 | 64 | tt, code { 65 | font-family: Courier New, Courier, mono; 66 | font-size: 120%; 67 | font-weight: bold; 68 | } 69 | 70 | strong { 71 | /* color: #FF0000; */ 72 | } -------------------------------------------------------------------------------- /py2exe/samples/pywin32/com_typelib/build_gen/word/docmaker.py: -------------------------------------------------------------------------------- 1 | # A test program that generates a word document. 2 | import sys 3 | import os 4 | from win32com.client import gencache 5 | 6 | # When built with py2exe, it assumes 'Word.Application.9' is installed 7 | # on the machine performing the build. The typelibs from the local machine 8 | # will be used to generate makepy files, and those generated files will 9 | # be included in the py2exe library (generally in a .zip file) 10 | 11 | # The resulting application should run without referencing any typelibs on 12 | # the target system. 13 | 14 | # It will create a file: 15 | filename = os.path.abspath( 16 | os.path.join(os.path.dirname(sys.argv[0]), "output.doc")) 17 | 18 | word = gencache.EnsureDispatch("Word.Application.9") 19 | 20 | # For the sake of ensuring the correct module is used... 21 | mod = sys.modules[word.__module__] 22 | print "The module hosting the object is", mod 23 | 24 | 25 | word.Visible = 1 26 | doc = word.Documents.Add() 27 | wrange = doc.Range() 28 | for i in range(10): 29 | wrange.InsertAfter("Hello from py2exe %d\n" % i) 30 | doc.SaveAs(filename) 31 | word.Quit() 32 | print "Done - saved to", os.path.abspath(filename) 33 | -------------------------------------------------------------------------------- /py2exe/samples/simple/setup.py: -------------------------------------------------------------------------------- 1 | # A very simple setup script to create 2 executables. 2 | # 3 | # hello.py is a simple "hello, world" type program, which alse allows 4 | # to explore the environment in which the script runs. 5 | # 6 | # test_wx.py is a simple wxPython program, it will be converted into a 7 | # console-less program. 8 | # 9 | # If you don't have wxPython installed, you should comment out the 10 | # windows = ["test_wx.py"] 11 | # line below. 12 | # 13 | # 14 | # Run the build process by entering 'setup.py py2exe' or 15 | # 'python setup.py py2exe' in a console prompt. 16 | # 17 | # If everything works well, you should find a subdirectory named 'dist' 18 | # containing some files, among them hello.exe and test_wx.exe. 19 | 20 | 21 | from distutils.core import setup 22 | import py2exe 23 | 24 | setup( 25 | # The first three parameters are not required, if at least a 26 | # 'version' is given, then a versioninfo resource is built from 27 | # them and added to the executables. 28 | version = "0.5.0", 29 | description = "py2exe sample script", 30 | name = "py2exe samples", 31 | 32 | # targets to build 33 | windows = ["test_wx.py"], 34 | console = ["hello.py"], 35 | ) 36 | -------------------------------------------------------------------------------- /py2exe/samples/pywin32/com_typelib/README.txt: -------------------------------------------------------------------------------- 1 | Some py2exe samples relating to the use of typelibs and pywin32. 2 | 3 | pywin32's COM support takes advantage of COM typelibs by generating Python 4 | stubs for the objects in these typelibs. This generation is often known as 5 | a 'makepy' process, from the name of the script that performs the generation, 6 | but it is not always necessary to explcitly invoke makepy.py - the use of 7 | win32com.client.gencache will often cause implicit generation of these stubs. 8 | 9 | This directory contains samples showing how to use these techniques with 10 | py2exe apps. It contains the following samples. 11 | 12 | build_gen: contains samples that demonstrate how to build a typelib as py2exe 13 | is run. This means the machine running py2exe must have the 14 | typelibs installed locally, but the target machines need not. 15 | py2exe generates the typelib stubs as it is run. 16 | 17 | There is currently a single sample which assumes MSWord is 18 | installed. Please contribute samples for other common objects! 19 | 20 | pre_gen: contains samples that demonstrate how to package typelib stubs 21 | previously generated. Such stubs will have come from a previous 22 | invocation of makepy, possibly on another computer and possibly 23 | from a source control system. In this case, the computer running 24 | py2exe does *not* need to have the relevant typelibs installed. 25 | -------------------------------------------------------------------------------- /source/icon.rc: -------------------------------------------------------------------------------- 1 | //Microsoft Developer Studio generated resource script. 2 | //Hacked by theller to make it compile with mingw32, too. 3 | #include "resource.h" 4 | 5 | #define APSTUDIO_READONLY_SYMBOLS 6 | ///////////////////////////////////////////////////////////////////////////// 7 | // 8 | // Generated from the TEXTINCLUDE 2 resource. 9 | // 10 | #include 11 | ///////////////////////////////////////////////////////////////////////////// 12 | #undef APSTUDIO_READONLY_SYMBOLS 13 | 14 | ///////////////////////////////////////////////////////////////////////////// 15 | // English (U.S.) resources 16 | 17 | #if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) 18 | #ifdef _WIN32 19 | LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US 20 | #pragma code_page(1252) 21 | #endif //_WIN32 22 | 23 | ///////////////////////////////////////////////////////////////////////////// 24 | // 25 | // Icon 26 | // 27 | 28 | // Icon with lowest ID value placed first to ensure application icon 29 | // remains consistent on all systems. 30 | IDI_ICON1 ICON DISCARDABLE "source\\icon1.ico" 31 | 32 | #ifdef APSTUDIO_INVOKED 33 | ///////////////////////////////////////////////////////////////////////////// 34 | // 35 | // TEXTINCLUDE 36 | // 37 | 38 | 1 TEXTINCLUDE DISCARDABLE 39 | BEGIN 40 | "resource.h\0" 41 | END 42 | 43 | 2 TEXTINCLUDE DISCARDABLE 44 | BEGIN 45 | "#include ""afxres.h""\r\n" 46 | "\0" 47 | END 48 | 49 | #endif // APSTUDIO_INVOKED 50 | 51 | 52 | #endif // English (U.S.) resources 53 | ///////////////////////////////////////////////////////////////////////////// 54 | -------------------------------------------------------------------------------- /source/actctx.c: -------------------------------------------------------------------------------- 1 | #include "actctx.h" 2 | 3 | HANDLE PyWin_DLLhActivationContext=NULL; 4 | PFN_GETCURRENTACTCTX pfnGetCurrentActCtx=NULL; 5 | PFN_ACTIVATEACTCTX pfnActivateActCtx=NULL; 6 | PFN_DEACTIVATEACTCTX pfnDeactivateActCtx=NULL; 7 | PFN_ADDREFACTCTX pfnAddRefActCtx=NULL; 8 | PFN_RELEASEACTCTX pfnReleaseActCtx=NULL; 9 | 10 | void _MyLoadActCtxPointers() 11 | { 12 | HINSTANCE hKernel32 = GetModuleHandleW(L"kernel32.dll"); 13 | if (hKernel32) 14 | pfnGetCurrentActCtx = (PFN_GETCURRENTACTCTX) GetProcAddress(hKernel32, "GetCurrentActCtx"); 15 | // If we can't load GetCurrentActCtx (ie, pre XP) , don't bother with the rest. 16 | if (pfnGetCurrentActCtx) { 17 | pfnActivateActCtx = (PFN_ACTIVATEACTCTX) GetProcAddress(hKernel32, "ActivateActCtx"); 18 | pfnDeactivateActCtx = (PFN_DEACTIVATEACTCTX) GetProcAddress(hKernel32, "DeactivateActCtx"); 19 | pfnAddRefActCtx = (PFN_ADDREFACTCTX) GetProcAddress(hKernel32, "AddRefActCtx"); 20 | pfnReleaseActCtx = (PFN_RELEASEACTCTX) GetProcAddress(hKernel32, "ReleaseActCtx"); 21 | } 22 | } 23 | 24 | ULONG_PTR _My_ActivateActCtx() 25 | { 26 | ULONG_PTR ret = 0; 27 | if (PyWin_DLLhActivationContext && pfnActivateActCtx) 28 | if (!(*pfnActivateActCtx)(PyWin_DLLhActivationContext, &ret)) { 29 | OutputDebugString("py2exe failed to activate the activation context before loading a DLL\n"); 30 | ret = 0; // no promise the failing function didn't change it! 31 | } 32 | return ret; 33 | } 34 | 35 | void _My_DeactivateActCtx(ULONG_PTR cookie) 36 | { 37 | if (cookie && pfnDeactivateActCtx) 38 | if (!(*pfnDeactivateActCtx)(0, cookie)) 39 | OutputDebugString("py2exe failed to de-activate the activation context\n"); 40 | } 41 | -------------------------------------------------------------------------------- /py2exe/samples/user_access_control/setup.py: -------------------------------------------------------------------------------- 1 | # A simple setup script to create various executables with 2 | # different User Access Control flags in the manifest. 3 | 4 | # Run the build process by entering 'setup.py py2exe' or 5 | # 'python setup.py py2exe' in a console prompt. 6 | # 7 | # If everything works well, you should find a subdirectory named 'dist' 8 | # containing lots of executables 9 | 10 | from distutils.core import setup 11 | import py2exe 12 | 13 | # The targets to build 14 | 15 | # create a target that says nothing about UAC - On Python 2.6+, this 16 | # should be identical to "asInvoker" below. However, for 2.5 and 17 | # earlier it will force the app into compatibility mode (as no 18 | # manifest will exist at all in the target.) 19 | t1 = dict(script="hello.py", 20 | dest_base="not_specified") 21 | # targets with different values for requestedExecutionLevel 22 | t2 = dict(script="hello.py", 23 | dest_base="as_invoker", 24 | uac_info="asInvoker") 25 | t3 = dict(script="hello.py", 26 | dest_base="highest_available", 27 | uac_info="highestAvailable") 28 | t4 = dict(script="hello.py", 29 | dest_base="require_admin", 30 | uac_info="requireAdministrator") 31 | console = [t1, t2, t3, t4] 32 | 33 | # hack to make windows copies of them all too, but 34 | # with '_w' on the tail of the executable. 35 | windows = [t1.copy(), t2.copy(), t3.copy(), t4.copy()] 36 | for t in windows: 37 | t['dest_base'] += "_w" 38 | 39 | setup( 40 | version = "0.5.0", 41 | description = "py2exe user-access-control sample script", 42 | name = "py2exe samples", 43 | # targets to build 44 | windows = windows, 45 | console = console, 46 | ) 47 | -------------------------------------------------------------------------------- /py2exe/samples/singlefile/gui/test_wx.py: -------------------------------------------------------------------------------- 1 | import sys 2 | import wx 3 | 4 | # By default the executables created by py2exe write output to stderr 5 | # into a logfile and display a messagebox at program end when there 6 | # has been any output. This logger silently overrides the default 7 | # behaviour by silently swallowing everything. 8 | 9 | if hasattr(sys, "frozen"): 10 | class logger: 11 | def write(self, text): 12 | pass # silently ignore everything 13 | 14 | sys.stdout = sys.stderr = logger() 15 | 16 | class MyFrame(wx.Frame): 17 | def __init__(self, parent, ID, title, pos=wx.DefaultPosition, 18 | size=(200, 200), style=wx.DEFAULT_FRAME_STYLE): 19 | wx.Frame.__init__(self, parent, ID, title, pos, size, style) 20 | panel = wx.Panel(self, -1) 21 | 22 | button = wx.Button(panel, 1003, "Close Me") 23 | button.SetPosition(wx.Point(15, 15)) 24 | wx.EVT_BUTTON(self, 1003, self.OnCloseMe) 25 | wx.EVT_CLOSE(self, self.OnCloseWindow) 26 | 27 | button = wx.Button(panel, 1004, "Press Me") 28 | button.SetPosition(wx.Point(15, 45)) 29 | wx.EVT_BUTTON(self, 1004, self.OnPressMe) 30 | 31 | def OnCloseMe(self, event): 32 | self.Close(True) 33 | 34 | def OnPressMe(self, event): 35 | # This raises an exception 36 | x = 1 / 0 37 | 38 | def OnCloseWindow(self, event): 39 | self.Destroy() 40 | 41 | class MyApp(wx.App): 42 | def OnInit(self): 43 | frame = MyFrame(None, -1, "Hello from wxPython") 44 | frame.Show(True) 45 | self.SetTopWindow(frame) 46 | return True 47 | 48 | if __name__ == "__main__": 49 | app = MyApp(0) 50 | app.MainLoop() 51 | -------------------------------------------------------------------------------- /source/actctx.h: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #include 6 | // Windows "Activation Context" work: 7 | // Our .pyd extension modules are generally built without a manifest (ie, 8 | // those included with Python and those built with a default distutils. 9 | // This requires we perform some "activation context" magic when loading our 10 | // extensions. In summary: 11 | // * As our DLL loads we save the context being used. 12 | // * Before loading our extensions we re-activate our saved context. 13 | // * After extension load is complete we restore the old context. 14 | // As an added complication, this magic only works on XP or later - we simply 15 | // use the existence (or not) of the relevant function pointers from kernel32. 16 | // See bug 4566 (http://python.org/sf/4566) for more details. 17 | #ifdef __cplusplus 18 | extern "C" { 19 | #endif 20 | 21 | typedef BOOL (WINAPI * PFN_GETCURRENTACTCTX)(HANDLE *); 22 | typedef BOOL (WINAPI * PFN_ACTIVATEACTCTX)(HANDLE, ULONG_PTR *); 23 | typedef BOOL (WINAPI * PFN_DEACTIVATEACTCTX)(DWORD, ULONG_PTR); 24 | typedef BOOL (WINAPI * PFN_ADDREFACTCTX)(HANDLE); 25 | typedef BOOL (WINAPI * PFN_RELEASEACTCTX)(HANDLE); 26 | 27 | // locals and function pointers for this activation context magic. 28 | extern HANDLE PyWin_DLLhActivationContext; 29 | extern PFN_GETCURRENTACTCTX pfnGetCurrentActCtx; 30 | extern PFN_ACTIVATEACTCTX pfnActivateActCtx; 31 | extern PFN_DEACTIVATEACTCTX pfnDeactivateActCtx; 32 | extern PFN_ADDREFACTCTX pfnAddRefActCtx; 33 | extern PFN_RELEASEACTCTX pfnReleaseActCtx; 34 | 35 | void _MyLoadActCtxPointers(); 36 | ULONG_PTR _My_ActivateActCtx(); 37 | void _My_DeactivateActCtx(ULONG_PTR cookie); 38 | 39 | #ifdef __cplusplus 40 | } 41 | #endif 42 | -------------------------------------------------------------------------------- /source/Python-dynload.h: -------------------------------------------------------------------------------- 1 | /* **************** Python-dynload.h **************** */ 2 | #include "Python-version.h" 3 | 4 | typedef void *PyObject; 5 | typedef void *PyCodeObject; 6 | 7 | typedef PyObject *(*PyCFunction)(PyObject *, PyObject *); 8 | 9 | typedef 10 | enum {PyGILState_LOCKED, PyGILState_UNLOCKED} 11 | PyGILState_STATE; 12 | 13 | typedef struct { 14 | char *ml_name; 15 | PyCFunction ml_meth; 16 | int ml_flags; 17 | char *ml_doc; 18 | } PyMethodDef; 19 | 20 | struct IMPORT { 21 | char *name; 22 | void (*proc)(); 23 | }; 24 | extern int _load_python(char *dllname, char *dllbytes); 25 | extern struct IMPORT imports[]; 26 | 27 | #include "import-tab.h" 28 | 29 | extern void Py_XINCREF(PyObject *); 30 | #define snprintf _snprintf 31 | #define Py_DECREF(x) Py_XDECREF(x) 32 | #define Py_INCREF(x) Py_XINCREF(x) 33 | 34 | extern void Py_XDECREF(PyObject *ob); 35 | 36 | #define METH_OLDARGS 0x0000 37 | #define METH_VARARGS 0x0001 38 | #define METH_KEYWORDS 0x0002 39 | /* METH_NOARGS and METH_O must not be combined with the flags above. */ 40 | #define METH_NOARGS 0x0004 41 | #define METH_O 0x0008 42 | 43 | /* METH_CLASS and METH_STATIC are a little different; these control 44 | the construction of methods for a class. These cannot be used for 45 | functions in modules. */ 46 | #define METH_CLASS 0x0010 47 | #define METH_STATIC 0x0020 48 | 49 | #define PyCFunction_New(ML, SELF) PyCFunction_NewEx((ML), (SELF), NULL) 50 | 51 | #define PyInt_Check(op) PyObject_IsInstance(op, &PyInt_Type) /* ??? */ 52 | #define Py_None (&_Py_NoneStruct) 53 | 54 | #define DL_EXPORT(x) x 55 | 56 | #define Py_InitModule3(name, methods, doc) \ 57 | Py_InitModule4(name, methods, doc, (PyObject *)NULL, \ 58 | PYTHON_API_VERSION) 59 | -------------------------------------------------------------------------------- /py2exe/samples/singlefile/comserver/setup.py: -------------------------------------------------------------------------------- 1 | # This setup script builds a single-file Python inprocess COM server. 2 | # 3 | from distutils.core import setup 4 | import py2exe 5 | import sys 6 | 7 | # If run without args, build executables, in quiet mode. 8 | if len(sys.argv) == 1: 9 | sys.argv.append("py2exe") 10 | sys.argv.append("-q") 11 | 12 | class Target: 13 | def __init__(self, **kw): 14 | self.__dict__.update(kw) 15 | # for the versioninfo resources 16 | self.version = "0.6.0" 17 | self.company_name = "No Company" 18 | self.copyright = "no copyright" 19 | self.name = "py2exe sample files" 20 | 21 | ################################################################ 22 | # a COM server dll, modules is required 23 | # 24 | 25 | interp = Target( 26 | description = "Python Interpreter as COM server module", 27 | # what to build. For COM servers, the module name (not the 28 | # filename) must be specified! 29 | modules = ["win32com.servers.interp"], 30 | # we only want the inproc server. 31 | create_exe = False, 32 | ) 33 | 34 | ################################################################ 35 | # pywin32 COM pulls in a lot of stuff which we don't want or need. 36 | 37 | excludes = ["pywin", "pywin.debugger", "pywin.debugger.dbgcon", 38 | "pywin.dialogs", "pywin.dialogs.list", "win32com.client"] 39 | 40 | options = { 41 | "bundle_files": 1, 42 | "ascii": 1, # to make a smaller executable, don't include the encodings 43 | "compressed": 1, # compress the library archive 44 | "excludes": excludes, # COM stuff we don't want 45 | } 46 | 47 | setup( 48 | options = {"py2exe": options}, 49 | zipfile = None, # append zip-archive to the executable. 50 | com_server = [interp], 51 | ) 52 | -------------------------------------------------------------------------------- /source/run.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2000-2013 Thomas Heller 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining 5 | * a copy of this software and associated documentation files (the 6 | * "Software"), to deal in the Software without restriction, including 7 | * without limitation the rights to use, copy, modify, merge, publish, 8 | * distribute, sublicense, and/or sell copies of the Software, and to 9 | * permit persons to whom the Software is furnished to do so, subject to 10 | * the following conditions: 11 | * 12 | * The above copyright notice and this permission notice shall be 13 | * included in all copies or substantial portions of the Software. 14 | * 15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 16 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 17 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 18 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 19 | * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 20 | * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 21 | * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 22 | */ 23 | 24 | #include 25 | #include 26 | 27 | void SystemError(int error, char *msg) 28 | { 29 | char Buffer[1024]; 30 | 31 | if (msg) 32 | fprintf(stderr, msg); 33 | if (error) { 34 | LPVOID lpMsgBuf; 35 | FormatMessage( 36 | FORMAT_MESSAGE_ALLOCATE_BUFFER | 37 | FORMAT_MESSAGE_FROM_SYSTEM, 38 | NULL, 39 | error, 40 | MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), 41 | (LPSTR)&lpMsgBuf, 42 | 0, 43 | NULL 44 | ); 45 | strncpy(Buffer, lpMsgBuf, sizeof(Buffer)); 46 | LocalFree(lpMsgBuf); 47 | fprintf(stderr, Buffer); 48 | } 49 | } 50 | 51 | extern int init(char *); 52 | extern int start(int argc, char **argv); 53 | extern void init_memimporter(void); 54 | 55 | int main (int argc, char **argv) 56 | { 57 | int result; 58 | result = init("console_exe"); 59 | if (result) 60 | return result; 61 | init_memimporter(); 62 | return start(argc, argv); 63 | } 64 | -------------------------------------------------------------------------------- /source/import-tab.c: -------------------------------------------------------------------------------- 1 | { "Py_Initialize", NULL }, 2 | { "PyRun_SimpleString", NULL }, 3 | { "Py_Finalize", NULL }, 4 | { "Py_GetPath", NULL }, 5 | { "Py_SetPythonHome", NULL }, 6 | { "Py_SetProgramName", NULL }, 7 | { "PyMarshal_ReadObjectFromString", NULL }, 8 | { "PyObject_CallFunction", NULL }, 9 | { "PyString_AsStringAndSize", NULL }, 10 | { "PyString_AsString", NULL }, 11 | { "PyArg_ParseTuple", NULL }, 12 | { "PyErr_Format", NULL }, 13 | { "PyImport_ImportModule", NULL }, 14 | { "PyInt_FromLong", NULL }, 15 | { "PyInt_AsLong", NULL }, 16 | { "PyLong_FromVoidPtr", NULL }, 17 | #ifdef _DEBUG 18 | { "Py_InitModule4TraceRefs", NULL }, 19 | #else 20 | # if defined (_WIN64) 21 | { "Py_InitModule4_64", NULL }, 22 | # else 23 | { "Py_InitModule4", NULL }, 24 | # endif 25 | #endif 26 | { "PyTuple_New", NULL }, 27 | { "PyTuple_SetItem", NULL }, 28 | { "Py_IsInitialized", NULL }, 29 | { "PyObject_SetAttrString", NULL }, 30 | { "PyCFunction_NewEx", NULL }, 31 | { "PyObject_GetAttrString", NULL }, 32 | { "Py_BuildValue", NULL }, 33 | { "PyObject_Call", NULL }, 34 | { "PySys_WriteStderr", NULL }, 35 | { "PyErr_Occurred", NULL }, 36 | { "PyErr_Clear", NULL }, 37 | { "PyObject_IsInstance", NULL }, 38 | { "PyInt_Type", NULL }, 39 | { "_Py_NoneStruct", NULL }, 40 | { "PyExc_ImportError", NULL }, 41 | { "_Py_PackageContext", NULL }, 42 | { "PyGILState_Ensure", NULL }, 43 | { "PyGILState_Release", NULL }, 44 | { "PySys_SetObject", NULL }, 45 | { "PySys_GetObject", NULL }, 46 | { "PyString_FromString", NULL }, 47 | { "Py_FdIsInteractive", NULL }, 48 | { "PyRun_InteractiveLoop", NULL }, 49 | { "PySys_SetArgv", NULL }, 50 | { "PyImport_AddModule", NULL }, 51 | { "PyModule_GetDict", NULL }, 52 | { "PySequence_Length", NULL }, 53 | { "PySequence_GetItem", NULL }, 54 | { "PyEval_EvalCode", NULL }, 55 | { "PyErr_Print", NULL }, 56 | { "PyBool_FromLong", NULL }, 57 | { "Py_VerboseFlag", NULL }, 58 | { "Py_NoSiteFlag", NULL }, 59 | { "Py_OptimizeFlag", NULL }, 60 | { "Py_IgnoreEnvironmentFlag", NULL }, 61 | { "PyObject_Str", NULL }, 62 | { "PyList_New", NULL }, 63 | { "PyList_SetItem", NULL }, 64 | { "PyList_Append", NULL }, 65 | -------------------------------------------------------------------------------- /py2exe/samples/advanced/MyService.py: -------------------------------------------------------------------------------- 1 | # 2 | # A sample service to be 'compiled' into an exe-file with py2exe. 3 | # 4 | # See also 5 | # setup.py - the distutils' setup script 6 | # setup.cfg - the distutils' config file for this 7 | # README.txt - detailed usage notes 8 | # 9 | # A minimal service, doing nothing else than 10 | # - write 'start' and 'stop' entries into the NT event log 11 | # - when started, waits to be stopped again. 12 | # 13 | import win32serviceutil 14 | import win32service 15 | import win32event 16 | import win32evtlogutil 17 | 18 | class MyService(win32serviceutil.ServiceFramework): 19 | _svc_name_ = "MyService" 20 | _svc_display_name_ = "My Service" 21 | _svc_deps_ = ["EventLog"] 22 | def __init__(self, args): 23 | win32serviceutil.ServiceFramework.__init__(self, args) 24 | self.hWaitStop = win32event.CreateEvent(None, 0, 0, None) 25 | 26 | def SvcStop(self): 27 | self.ReportServiceStatus(win32service.SERVICE_STOP_PENDING) 28 | win32event.SetEvent(self.hWaitStop) 29 | 30 | def SvcDoRun(self): 31 | import servicemanager 32 | # Write a 'started' event to the event log... 33 | win32evtlogutil.ReportEvent(self._svc_name_, 34 | servicemanager.PYS_SERVICE_STARTED, 35 | 0, # category 36 | servicemanager.EVENTLOG_INFORMATION_TYPE, 37 | (self._svc_name_, '')) 38 | 39 | # wait for beeing stopped... 40 | win32event.WaitForSingleObject(self.hWaitStop, win32event.INFINITE) 41 | 42 | # and write a 'stopped' event to the event log. 43 | win32evtlogutil.ReportEvent(self._svc_name_, 44 | servicemanager.PYS_SERVICE_STOPPED, 45 | 0, # category 46 | servicemanager.EVENTLOG_INFORMATION_TYPE, 47 | (self._svc_name_, '')) 48 | 49 | 50 | if __name__ == '__main__': 51 | # Note that this code will not be run in the 'frozen' exe-file!!! 52 | win32serviceutil.HandleCommandLine(MyService) 53 | -------------------------------------------------------------------------------- /README.txt: -------------------------------------------------------------------------------- 1 | Modified by goatpig to support: 2 | 3 | 1) Running frozen exe from unicode paths 4 | 2) Display icons fed to py2exe through setup.py icon_resources in explorer 5 | 3) Parse unicode arguments, pass utf8 to python 6 | 4) Turned off .exe.log stderr write out 7 | 8 | 9 | ======================================== 10 | 11 | Uses the zipimport mechanism, so it requires Python 2.3 or later. The 12 | zipimport mechanism is able to handle the early imports of the 13 | warnings and also the encodings module which is done by Python. 14 | 15 | Creates a single directory, which must be deployed completely. 16 | 17 | (Most of this is based on ideas of Mark Hammond, he also implemented 18 | most if the code:) Can create any number of console and gui 19 | executables in this directory, plus optionally windows service exes, 20 | plus optionally exe and dll com servers. The com servers can expose 21 | one or more com object classes. 22 | 23 | All pure Python files are contained in a single zip archive, which is 24 | shared by all the executables. The zip archive may also be used by 25 | programs embedding Python. Since extension modules cannot be imported 26 | from zipfiles, a simple pure Python loader is included in the zipfile 27 | which loads the extension from the file system (without requiring that 28 | the directory is in sys.path). 29 | 30 | The executables run with only a single sys.path entry containing the 31 | absolute filename of the zipfile archive. Absolute filenames are 32 | constructed at runtime from the directory containing the executable, 33 | and the zipfile name specified at build time. 34 | 35 | The way has changed how build targets are specified in the setup 36 | script. py2exe installs it own Distribution subclass, which enables 37 | additional keyword arguments to the setup function: 38 | 39 | console = [...] # list of scripts to convert into console executables 40 | windows = [...] # list of scripts to convert into gui executables 41 | com_servers = [...] # list of fully qualified class names to build into the exe com server 42 | service = [...] # list of fully qualified class names to build into a service executable 43 | isapi = [...], # list of script names to build into an ISAPI extension. 44 | zipfile = "xxx.zip" # filename of the zipfile containing the pure Python modules 45 | 46 | All of the above arguments are optional. The zipfile name defaults to 47 | 'library.zip'. 48 | -------------------------------------------------------------------------------- /source/_memimporter.c: -------------------------------------------------------------------------------- 1 | /* 2 | For the _memimporter compiled into py2exe exe-stubs we need "Python-dynload.h". 3 | For the standalone .pyd we need 4 | */ 5 | 6 | #ifdef STANDALONE 7 | # include 8 | # include "Python-version.h" 9 | #else 10 | # include "Python-dynload.h" 11 | # include 12 | #endif 13 | #include 14 | 15 | static char module_doc[] = 16 | "Importer which can load extension modules from memory"; 17 | 18 | #include "MyLoadLibrary.h" 19 | #include "actctx.h" 20 | 21 | static PyObject * 22 | import_module(PyObject *self, PyObject *args) 23 | { 24 | char *initfuncname; 25 | char *modname; 26 | char *pathname; 27 | HMODULE hmem; 28 | FARPROC do_init; 29 | 30 | char *oldcontext; 31 | ULONG_PTR cookie = 0; 32 | PyObject *findproc; 33 | /* code, initfuncname, fqmodulename, path */ 34 | if (!PyArg_ParseTuple(args, "sssO:import_module", 35 | &modname, &pathname, 36 | &initfuncname, 37 | &findproc)) 38 | return NULL; 39 | 40 | cookie = _My_ActivateActCtx();//try some windows manifest magic... 41 | hmem = MyLoadLibrary(pathname, NULL, findproc); 42 | _My_DeactivateActCtx(cookie); 43 | 44 | if (!hmem) { 45 | PyErr_Format(PyExc_ImportError, 46 | "MemoryLoadLibrary failed loading %s", pathname); 47 | return NULL; 48 | } 49 | do_init = MyGetProcAddress(hmem, initfuncname); 50 | if (!do_init) { 51 | MyFreeLibrary(hmem); 52 | PyErr_Format(PyExc_ImportError, 53 | "Could not find function %s", initfuncname); 54 | return NULL; 55 | } 56 | 57 | oldcontext = _Py_PackageContext; 58 | _Py_PackageContext = modname; 59 | do_init(); 60 | _Py_PackageContext = oldcontext; 61 | if (PyErr_Occurred()) 62 | return NULL; 63 | /* Retrieve from sys.modules */ 64 | return PyImport_ImportModule(modname); 65 | } 66 | 67 | static PyObject * 68 | get_verbose_flag(PyObject *self, PyObject *args) 69 | { 70 | return PyInt_FromLong(Py_VerboseFlag); 71 | } 72 | 73 | static PyMethodDef methods[] = { 74 | { "import_module", import_module, METH_VARARGS, 75 | "import_module(modname, pathname, initfuncname, finder) -> module" }, 76 | { "get_verbose_flag", get_verbose_flag, METH_NOARGS, 77 | "Return the Py_Verbose flag" }, 78 | // { "set_find_proc", set_find_proc, METH_VARARGS }, 79 | { NULL, NULL }, /* Sentinel */ 80 | }; 81 | 82 | DL_EXPORT(void) 83 | init_memimporter(void) 84 | { 85 | Py_InitModule3("_memimporter", methods, module_doc); 86 | } 87 | -------------------------------------------------------------------------------- /py2exe/samples/user_access_control/README.txt: -------------------------------------------------------------------------------- 1 | This is a sample for how to control Vista's user-access-control for your 2 | py2exe created programs. 3 | 4 | Execute 'python setup.py py2exe' to create various executables, all with 5 | different manifest values. Each of these may behave slightly differently 6 | when executed under Vista. 7 | 8 | Important: 9 | ---------- 10 | 11 | There is an important difference between Python 2.6 versus 12 | earlier versions. 13 | 14 | Python 2.5 and before created executables will not have a manifest 15 | by default, meaning a backwards compatibility virtualization mode 16 | may be used by default. However, if you specify any value for 'uac_info' 17 | this virtualization will be disabled as it will cause a manifest to be 18 | created for the executable. 19 | 20 | To demonstrate on Vista: 21 | 22 | * Using an elevated process, create a temp directory under "C:\Program Files" 23 | and copy the generated 'dist' directory to that temp dir. 24 | 25 | * From a non-elevated command-prompt, execute: 26 | c:\Program Files\temp\not_specified.exe -e foo 27 | 28 | You will see an error dialog due to 'foo' being written to stderr. The 29 | error dialog will tell you the log file was written to the 30 | "C:\Program Files\temp" directory, but that log file will not exist 31 | in that directory - instead, it will be in the 32 | "C:\Users\{username}\AppData\Local\VirtualStore\Program Files (x86)\temp" 33 | directory - Windows has virtualized the file-system. Similar things will 34 | be able to be demonstrated with the registry. 35 | 36 | * From a non-elevated command-prompt, execute: 37 | c:\Program Files\temp\as_invoker.exe -e foo 38 | 39 | You will see an error dialog, but it will be slightly different - it 40 | will relate to a failure to open the log file in the "c:\Program Files\temp" 41 | directory. In this case, Windows has *not* virtualized the file-system but 42 | your process does not have permission to write in that directory, so it 43 | fails to write a log file at all. 44 | 45 | * From a non-elevated command-prompt, execute: 46 | c:\Program Files\temp\admin_required.exe -e foo 47 | 48 | You will be prompted to elevate the process, then a log file will be 49 | written to "C:\Program Files\temp" as the permissions exists in the 50 | elevated process. 51 | 52 | NOTE: For Python 2.6 and later there is always a manifest, so virtualization 53 | is always disabled. In other words, in Python 2.6, not_specified.exe will 54 | work exactly like as_invoker.exe does for all versions. 55 | -------------------------------------------------------------------------------- /source/Python-dynload.c: -------------------------------------------------------------------------------- 1 | /* **************** Python-dynload.c **************** */ 2 | #include "Python-dynload.h" 3 | #include "MemoryModule.h" 4 | #include 5 | 6 | struct IMPORT imports[] = { 7 | #include "import-tab.c" 8 | { NULL, NULL }, /* sentinel */ 9 | }; 10 | 11 | void Py_XDECREF(PyObject *ob) 12 | { 13 | static PyObject *tup; 14 | if (tup == NULL) 15 | tup = PyTuple_New(1); 16 | /* Let the tuple take the refcount */ 17 | PyTuple_SetItem(tup, 0, ob); 18 | /* and overwrite it */ 19 | PyTuple_SetItem(tup, 0, PyInt_FromLong(0)); 20 | } 21 | 22 | void Py_XINCREF(PyObject *ob) 23 | { 24 | if (ob) 25 | Py_BuildValue("O", ob); 26 | } 27 | 28 | int _load_python_FromFile(char *dllname) 29 | { 30 | int i; 31 | struct IMPORT *p = imports; 32 | HMODULE hmod; 33 | 34 | 35 | // In some cases (eg, ISAPI filters), Python may already be 36 | // in our process. If so, we don't want it to try and 37 | // load a new one! (Actually, we probably should not even attempt 38 | // to load an 'embedded' Python should GetModuleHandle work - but 39 | // that is less clear than this straight-forward case) 40 | // Get the basename of the DLL. 41 | char *dllbase = dllname + strlen(dllname); 42 | while (dllbase != dllname && *dllbase != '\\') 43 | dllbase--; 44 | if (*dllbase=='\\') 45 | ++dllbase; 46 | hmod = GetModuleHandle(dllbase); 47 | if (hmod == NULL) 48 | { 49 | wchar_t *dllnamew = (wchar_t*)malloc((strlen(dllname)+1)*sizeof(wchar_t)); 50 | MultiByteToWideChar(CP_UTF8, 0, dllname, -1, dllnamew, strlen(dllname)+1); 51 | hmod = LoadLibraryW(dllnamew); 52 | free(dllnamew); 53 | } 54 | if (hmod == NULL) { 55 | return 0; 56 | } 57 | for (i = 0; p->name; ++i, ++p) { 58 | p->proc = (void (*)())GetProcAddress(hmod, p->name); 59 | if (p->proc == NULL) { 60 | OutputDebugString("undef symbol"); 61 | fprintf(stderr, "undefined symbol %s -> exit(-1)\n", p->name); 62 | return 0; 63 | } 64 | } 65 | return 1; 66 | } 67 | 68 | int _load_python(char *dllname, char *bytes) 69 | { 70 | int i; 71 | struct IMPORT *p = imports; 72 | HMODULE hmod; 73 | 74 | if (!bytes) 75 | return _load_python_FromFile(dllname); 76 | 77 | hmod = MemoryLoadLibrary(dllname, bytes); 78 | if (hmod == NULL) { 79 | return 0; 80 | } 81 | for (i = 0; p->name; ++i, ++p) { 82 | p->proc = (void (*)())MemoryGetProcAddress(hmod, p->name); 83 | if (p->proc == NULL) { 84 | OutputDebugString("undef symbol"); 85 | fprintf(stderr, "undefined symbol %s -> exit(-1)\n", p->name); 86 | return 0; 87 | } 88 | } 89 | return 1; 90 | } 91 | 92 | -------------------------------------------------------------------------------- /py2exe/samples/singlefile/gui/setup.py: -------------------------------------------------------------------------------- 1 | # Requires wxPython. This sample demonstrates: 2 | # 3 | # - single file exe using wxPython as GUI. 4 | 5 | from distutils.core import setup 6 | import py2exe 7 | import sys 8 | 9 | # If run without args, build executables, in quiet mode. 10 | if len(sys.argv) == 1: 11 | sys.argv.append("py2exe") 12 | sys.argv.append("-q") 13 | 14 | class Target: 15 | def __init__(self, **kw): 16 | self.__dict__.update(kw) 17 | # for the versioninfo resources 18 | self.version = "0.6.1" 19 | self.company_name = "No Company" 20 | self.copyright = "no copyright" 21 | self.name = "py2exe sample files" 22 | 23 | ################################################################ 24 | # A program using wxPython 25 | 26 | # The manifest will be inserted as resource into test_wx.exe. This 27 | # gives the controls the Windows XP appearance (if run on XP ;-) 28 | # 29 | # Another option would be to store it in a file named 30 | # test_wx.exe.manifest, and copy it with the data_files option into 31 | # the dist-dir. 32 | # 33 | manifest_template = ''' 34 | 35 | 36 | 42 | %(prog)s Program 43 | 44 | 45 | 53 | 54 | 55 | 56 | ''' 57 | 58 | RT_MANIFEST = 24 59 | 60 | test_wx = Target( 61 | # used for the versioninfo resource 62 | description = "A sample GUI app", 63 | 64 | # what to build 65 | script = "test_wx.py", 66 | other_resources = [(RT_MANIFEST, 1, manifest_template % dict(prog="test_wx"))], 67 | ## icon_resources = [(1, "icon.ico")], 68 | dest_base = "test_wx") 69 | 70 | ################################################################ 71 | 72 | setup( 73 | options = {"py2exe": {"compressed": 1, 74 | "optimize": 2, 75 | "ascii": 1, 76 | "bundle_files": 1, 77 | "dll_excludes": "MSVCP90.dll mswsock.dll powrprof.dll".split(), 78 | }, 79 | }, 80 | zipfile = None, 81 | windows = [test_wx], 82 | ) 83 | -------------------------------------------------------------------------------- /source/run_w.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2000-2013 Thomas Heller, Mark Hammond 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining 5 | * a copy of this software and associated documentation files (the 6 | * "Software"), to deal in the Software without restriction, including 7 | * without limitation the rights to use, copy, modify, merge, publish, 8 | * distribute, sublicense, and/or sell copies of the Software, and to 9 | * permit persons to whom the Software is furnished to do so, subject to 10 | * the following conditions: 11 | * 12 | * The above copyright notice and this permission notice shall be 13 | * included in all copies or substantial portions of the Software. 14 | * 15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 16 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 17 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 18 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 19 | * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 20 | * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 21 | * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 22 | */ 23 | 24 | #include 25 | #include 26 | #include "Python-dynload.h" 27 | 28 | void SystemError(int error, char *msg) 29 | { 30 | char Buffer[1024]; 31 | int n; 32 | 33 | if (error) { 34 | LPVOID lpMsgBuf; 35 | FormatMessage( 36 | FORMAT_MESSAGE_ALLOCATE_BUFFER | 37 | FORMAT_MESSAGE_FROM_SYSTEM, 38 | NULL, 39 | error, 40 | MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), 41 | (LPSTR)&lpMsgBuf, 42 | 0, 43 | NULL 44 | ); 45 | strncpy(Buffer, lpMsgBuf, sizeof(Buffer)); 46 | LocalFree(lpMsgBuf); 47 | } else 48 | Buffer[0] = '\0'; 49 | n = lstrlen(Buffer); 50 | _snprintf(Buffer+n, sizeof(Buffer)-n, msg); 51 | MessageBox(GetFocus(), Buffer, NULL, MB_OK | MB_ICONSTOP); 52 | } 53 | 54 | extern int init(char *); 55 | extern int start(int argc, char **argv); 56 | extern void init_memimporter(void); 57 | 58 | static PyObject *Py_MessageBox(PyObject *self, PyObject *args) 59 | { 60 | HWND hwnd; 61 | char *message; 62 | char *title = NULL; 63 | int flags = MB_OK; 64 | 65 | if (!PyArg_ParseTuple(args, "is|zi", &hwnd, &message, &title, &flags)) 66 | return NULL; 67 | return PyInt_FromLong(MessageBox(hwnd, message, title, flags)); 68 | } 69 | 70 | PyMethodDef method[] = { 71 | { "_MessageBox", Py_MessageBox, METH_VARARGS } 72 | }; 73 | 74 | int WINAPI 75 | WinMain(HINSTANCE hInst, HINSTANCE hPrevInst, 76 | LPSTR lpCmdLine, int nCmdShow) 77 | { 78 | int result; 79 | PyObject *mod; 80 | 81 | result = init("windows_exe"); 82 | if (result) 83 | return result; 84 | 85 | init_memimporter(); 86 | mod = PyImport_ImportModule("sys"); 87 | if (mod) 88 | PyObject_SetAttrString(mod, 89 | "_MessageBox", 90 | PyCFunction_New(&method[0], NULL)); 91 | 92 | return start(__argc, __argv); 93 | } 94 | -------------------------------------------------------------------------------- /py2exe/boot_ctypes_com_server.py: -------------------------------------------------------------------------------- 1 | # This support script is executed as the entry point for ctypes com servers. 2 | # XXX Currently, this is always run as part of a dll. 3 | 4 | import sys 5 | import _ctypes 6 | 7 | if 1: 8 | ################################################################ 9 | # XXX Remove later! 10 | import ctypes 11 | class LOGGER: 12 | def __init__(self): 13 | self.softspace = None 14 | def write(self, text): 15 | if isinstance(text, unicode): 16 | ctypes.windll.kernel32.OutputDebugStringW(text) 17 | else: 18 | ctypes.windll.kernel32.OutputDebugStringA(text) 19 | sys.stderr = sys.stdout = LOGGER() 20 | ## sys.stderr.write("PATH is %s\n" % sys.path) 21 | 22 | ################################################################ 23 | # tell the win32 COM registering/unregistering code that we're inside 24 | # of an EXE/DLL 25 | 26 | if not hasattr(sys, "frozen"): 27 | # standard exes have none. 28 | sys.frozen = _ctypes.frozen = 1 29 | else: 30 | # com DLLs already have sys.frozen set to 'dll' 31 | _ctypes.frozen = sys.frozen 32 | 33 | # Add some extra imports here, just to avoid putting them as "hidden imports" 34 | # anywhere else - this script has the best idea about what it needs. 35 | # (and hidden imports are currently disabled :) 36 | #... 37 | 38 | # We assume that py2exe has magically set com_module_names 39 | # to the module names that expose the COM objects we host. 40 | # Note that here all the COM modules for the app are imported - hence any 41 | # environment changes (such as sys.stderr redirection) will happen now. 42 | try: 43 | com_module_names 44 | except NameError: 45 | print "This script is designed to be run from inside py2exe % s" % str(details) 46 | sys.exit(1) 47 | 48 | com_modules = [] 49 | for name in com_module_names: 50 | __import__(name) 51 | com_modules.append(sys.modules[name]) 52 | 53 | def get_classes(module): 54 | return [ob 55 | for ob in module.__dict__.itervalues() 56 | if hasattr(ob, "_reg_progid_") 57 | ] 58 | 59 | def build_class_map(): 60 | # Set _clsid_to_class in comtypes.server.inprocserver. 61 | # 62 | # This avoids the need to have registry entries pointing to the 63 | # COM server class. 64 | classmap = {} 65 | for mod in com_modules: 66 | # dump each class 67 | for cls in get_classes(mod): 68 | classmap[cls._reg_clsid_] = cls 69 | import comtypes.server.inprocserver 70 | comtypes.server.inprocserver._clsid_to_class = classmap 71 | build_class_map() 72 | del build_class_map 73 | 74 | def DllRegisterServer(): 75 | # Enumerate each module implementing an object 76 | from comtypes.server.register import register 77 | for mod in com_modules: 78 | # register each class 79 | for cls in get_classes(mod): 80 | register(cls) 81 | 82 | 83 | def DllUnregisterServer(): 84 | # Enumerate each module implementing an object 85 | from comtypes.server.register import unregister 86 | for mod in com_modules: 87 | # unregister each class 88 | for cls in get_classes(mod): 89 | unregister(cls) 90 | -------------------------------------------------------------------------------- /source/MemoryModule.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Memory DLL loading code 3 | * Version 0.0.3 4 | * 5 | * Copyright (c) 2004-2013 by Joachim Bauch / mail@joachim-bauch.de 6 | * http://www.joachim-bauch.de 7 | * 8 | * The contents of this file are subject to the Mozilla Public License Version 9 | * 2.0 (the "License"); you may not use this file except in compliance with 10 | * the License. You may obtain a copy of the License at 11 | * http://www.mozilla.org/MPL/ 12 | * 13 | * Software distributed under the License is distributed on an "AS IS" basis, 14 | * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License 15 | * for the specific language governing rights and limitations under the 16 | * License. 17 | * 18 | * The Original Code is MemoryModule.h 19 | * 20 | * The Initial Developer of the Original Code is Joachim Bauch. 21 | * 22 | * Portions created by Joachim Bauch are Copyright (C) 2004-2013 23 | * Joachim Bauch. All Rights Reserved. 24 | * 25 | */ 26 | 27 | #ifndef __MEMORY_MODULE_HEADER 28 | #define __MEMORY_MODULE_HEADER 29 | 30 | #include 31 | 32 | typedef void *HMEMORYMODULE; 33 | 34 | typedef void *HMEMORYRSRC; 35 | 36 | typedef void *HCUSTOMMODULE; 37 | 38 | #ifdef __cplusplus 39 | extern "C" { 40 | #endif 41 | 42 | typedef HCUSTOMMODULE (*CustomLoadLibraryFunc)(LPCSTR, void *); 43 | typedef FARPROC (*CustomGetProcAddressFunc)(HCUSTOMMODULE, LPCSTR, void *); 44 | typedef void (*CustomFreeLibraryFunc)(HCUSTOMMODULE, void *); 45 | 46 | /** 47 | * Load DLL from memory location. 48 | * 49 | * All dependencies are resolved using default LoadLibrary/GetProcAddress 50 | * calls through the Windows API. 51 | */ 52 | HMEMORYMODULE MemoryLoadLibrary(const void *); 53 | 54 | /** 55 | * Load DLL from memory location using custom dependency resolvers. 56 | * 57 | * Dependencies will be resolved using passed callback methods. 58 | */ 59 | HMEMORYMODULE MemoryLoadLibraryEx(const void *, 60 | CustomLoadLibraryFunc, 61 | CustomGetProcAddressFunc, 62 | CustomFreeLibraryFunc, 63 | void *); 64 | 65 | /** 66 | * Get address of exported method. 67 | */ 68 | FARPROC MemoryGetProcAddress(HMEMORYMODULE, LPCSTR); 69 | 70 | /** 71 | * Free previously loaded DLL. 72 | */ 73 | void MemoryFreeLibrary(HMEMORYMODULE); 74 | 75 | /** 76 | * Find the location of a resource with the specified type and name. 77 | */ 78 | HMEMORYRSRC MemoryFindResource(HMEMORYMODULE, LPCTSTR, LPCTSTR); 79 | 80 | /** 81 | * Find the location of a resource with the specified type, name and language. 82 | */ 83 | HMEMORYRSRC MemoryFindResourceEx(HMEMORYMODULE, LPCTSTR, LPCTSTR, WORD); 84 | 85 | /** 86 | * Get the size of the resource in bytes. 87 | */ 88 | DWORD MemorySizeofResource(HMEMORYMODULE, HMEMORYRSRC); 89 | 90 | /** 91 | * Get a pointer to the contents of the resource. 92 | */ 93 | LPVOID MemoryLoadResource(HMEMORYMODULE, HMEMORYRSRC); 94 | 95 | /** 96 | * Load a string resource. 97 | */ 98 | int MemoryLoadString(HMEMORYMODULE, UINT, LPTSTR, int); 99 | 100 | /** 101 | * Load a string resource with a given language. 102 | */ 103 | int MemoryLoadStringEx(HMEMORYMODULE, UINT, LPTSTR, int, WORD); 104 | 105 | #ifdef __cplusplus 106 | } 107 | #endif 108 | 109 | #endif // __MEMORY_MODULE_HEADER 110 | -------------------------------------------------------------------------------- /py2exe/__init__.py: -------------------------------------------------------------------------------- 1 | """ 2 | builds windows executables from Python scripts 3 | 4 | New keywords for distutils' setup function specify what to build: 5 | 6 | console 7 | list of scripts to convert into console exes 8 | 9 | windows 10 | list of scripts to convert into gui exes 11 | 12 | service 13 | list of module names containing win32 service classes 14 | 15 | com_server 16 | list of module names containing com server classes 17 | 18 | ctypes_com_server 19 | list of module names containing com server classes 20 | 21 | zipfile 22 | name of shared zipfile to generate, may specify a subdirectory, 23 | defaults to 'library.zip' 24 | 25 | 26 | py2exe options, to be specified in the options keyword to the setup function: 27 | 28 | unbuffered - if true, use unbuffered binary stdout and stderr 29 | optimize - string or int (0, 1, or 2) 30 | 31 | includes - list of module names to include 32 | packages - list of packages to include with subpackages 33 | ignores - list of modules to ignore if they are not found 34 | excludes - list of module names to exclude 35 | dll_excludes - list of dlls to exclude 36 | 37 | dist_dir - directory where to build the final files 38 | typelibs - list of gen_py generated typelibs to include (XXX more text needed) 39 | 40 | Items in the console, windows, service or com_server list can also be 41 | dictionaries to further customize the build process. The following 42 | keys in the dictionary are recognized, most are optional: 43 | 44 | modules (SERVICE, COM) - list of module names (required) 45 | script (EXE) - list of python scripts (required) 46 | dest_base - directory and basename for the executable 47 | if a directory is contained, must be the same for all targets 48 | create_exe (COM) - boolean, if false, don't build a server exe 49 | create_dll (COM) - boolean, if false, don't build a server dll 50 | bitmap_resources - list of 2-tuples (id, pathname) 51 | icon_resources - list of 2-tuples (id, pathname) 52 | other_resources - list of 3-tuples (resource_type, id, datastring) 53 | """ 54 | # py2exe/__init__.py 55 | 56 | # 'import py2exe' imports this package, and two magic things happen: 57 | # 58 | # - the 'py2exe.build_exe' submodule is imported and installed as 59 | # 'distutils.commands.py2exe' command 60 | # 61 | # - the default distutils Distribution class is replaced by the 62 | # special one contained in this module. 63 | # 64 | 65 | __version__ = "0.6.10.a1" 66 | 67 | import distutils.dist, distutils.core, distutils.command, build_exe, sys 68 | 69 | class Distribution(distutils.dist.Distribution): 70 | 71 | def __init__(self, attrs): 72 | self.ctypes_com_server = attrs.pop("ctypes_com_server", []) 73 | self.com_server = attrs.pop("com_server", []) 74 | self.service = attrs.pop("service", []) 75 | self.windows = attrs.pop("windows", []) 76 | self.console = attrs.pop("console", []) 77 | self.isapi = attrs.pop("isapi", []) 78 | self.zipfile = attrs.pop("zipfile", "library.zip") 79 | 80 | distutils.dist.Distribution.__init__(self, attrs) 81 | 82 | distutils.core.Distribution = Distribution 83 | 84 | distutils.command.__all__.append('py2exe') 85 | 86 | sys.modules['distutils.command.py2exe'] = build_exe 87 | -------------------------------------------------------------------------------- /py2exe/boot_common.py: -------------------------------------------------------------------------------- 1 | # Common py2exe boot script - executed for all target types. 2 | 3 | # When we are a windows_exe we have no console, and writing to 4 | # sys.stderr or sys.stdout will sooner or later raise an exception, 5 | # and tracebacks will be lost anyway (see explanation below). 6 | # 7 | # We assume that output to sys.stdout can go to the bitsink, but we 8 | # *want* to see tracebacks. So we redirect sys.stdout into an object 9 | # with a write method doing nothing, and sys.stderr into a logfile 10 | # having the same name as the executable, with '.log' appended. 11 | # 12 | # We only open the logfile if something is written to sys.stderr. 13 | # 14 | # If the logfile cannot be opened for *any* reason, we have no choice 15 | # but silently ignore the error. 16 | # 17 | # It remains to be seen if the 'a' flag for opening the logfile is a 18 | # good choice, or 'w' would be better. 19 | # 20 | # More elaborate explanation on why this is needed: 21 | # 22 | # The sys.stdout and sys.stderr that GUI programs get (from Windows) are 23 | # more than useless. This is not a py2exe problem, pythonw.exe behaves 24 | # in the same way. 25 | # 26 | # To demonstrate, run this program with pythonw.exe: 27 | # 28 | # import sys 29 | # sys.stderr = open("out.log", "w") 30 | # for i in range(10000): 31 | # print i 32 | # 33 | # and open the 'out.log' file. It contains this: 34 | # 35 | # Traceback (most recent call last): 36 | # File "out.py", line 6, in ? 37 | # print i 38 | # IOError: [Errno 9] Bad file descriptor 39 | # 40 | # In other words, after printing a certain number of bytes to the 41 | # system-supplied sys.stdout (or sys.stderr) an exception will be raised. 42 | # 43 | 44 | import sys 45 | if sys.frozen == "windows_exe": 46 | class Stderr(object): 47 | softspace = 0 48 | _file = None 49 | _error = None 50 | def write(self, text, alert=sys._MessageBox, fname=sys.executable + '.log'): 51 | if self._file is None and self._error is None: 52 | try: 53 | self._file = open(fname, 'a') 54 | except Exception, details: 55 | self._error = details 56 | import atexit 57 | atexit.register(alert, 0, 58 | "The logfile '%s' could not be opened:\n %s" % \ 59 | (fname, details), 60 | "Errors occurred") 61 | else: 62 | import atexit 63 | atexit.register(alert, 0, 64 | "See the logfile '%s' for details" % fname, 65 | "Errors occurred") 66 | if self._file is not None: 67 | self._file.write(text) 68 | self._file.flush() 69 | def flush(self): 70 | if self._file is not None: 71 | self._file.flush() 72 | #sys.stderr = Stderr() 73 | del sys._MessageBox 74 | del Stderr 75 | 76 | class Blackhole(object): 77 | softspace = 0 78 | def write(self, text): 79 | pass 80 | def flush(self): 81 | pass 82 | sys.stdout = Blackhole() 83 | del Blackhole 84 | del sys 85 | 86 | # Disable linecache.getline() which is called by 87 | # traceback.extract_stack() when an exception occurs to try and read 88 | # the filenames embedded in the packaged python code. This is really 89 | # annoying on windows when the d: or e: on our build box refers to 90 | # someone elses removable or network drive so the getline() call 91 | # causes it to ask them to insert a disk in that drive. 92 | import linecache 93 | def fake_getline(filename, lineno, module_globals=None): 94 | return '' 95 | linecache.orig_getline = linecache.getline 96 | linecache.getline = fake_getline 97 | 98 | del linecache, fake_getline 99 | -------------------------------------------------------------------------------- /source/import-tab.h: -------------------------------------------------------------------------------- 1 | #define Py_Initialize ((void(*)(void))imports[0].proc) 2 | #define PyRun_SimpleString ((int(*)(char *))imports[1].proc) 3 | #define Py_Finalize ((void(*)(void))imports[2].proc) 4 | #define Py_GetPath ((char *(*)(void))imports[3].proc) 5 | #define Py_SetPythonHome ((void(*)(char *))imports[4].proc) 6 | #define Py_SetProgramName ((void(*)(char *))imports[5].proc) 7 | #define PyMarshal_ReadObjectFromString ((PyObject *(*)(char *, Py_ssize_t))imports[6].proc) 8 | #define PyObject_CallFunction ((PyObject *(*)(PyObject *, char *, ...))imports[7].proc) 9 | #define PyString_AsStringAndSize ((int(*)(PyObject *, char **, Py_ssize_t *))imports[8].proc) 10 | #define PyString_AsString ((char *(*)(PyObject *))imports[9].proc) 11 | #define PyArg_ParseTuple ((int(*)(PyObject *, char *, ...))imports[10].proc) 12 | #define PyErr_Format ((PyObject *(*)(PyObject *, const char *, ...))imports[11].proc) 13 | #define PyImport_ImportModule ((PyObject *(*)(char *))imports[12].proc) 14 | #define PyInt_FromLong ((PyObject *(*)(long))imports[13].proc) 15 | #define PyInt_AsLong ((long(*)(PyObject *))imports[14].proc) 16 | #define PyLong_FromVoidPtr ((PyObject *(*)(void *))imports[15].proc) 17 | #define Py_InitModule4 ((PyObject *(*)(char *, PyMethodDef *, char *, PyObject *, int))imports[16].proc) 18 | #define PyTuple_New ((PyObject *(*)(Py_ssize_t))imports[17].proc) 19 | #define PyTuple_SetItem ((int(*)(PyObject*, Py_ssize_t, PyObject *))imports[18].proc) 20 | #define Py_IsInitialized ((int(*)(void))imports[19].proc) 21 | #define PyObject_SetAttrString ((int(*)(PyObject *, char *, PyObject *))imports[20].proc) 22 | #define PyCFunction_NewEx ((PyObject *(*)(PyMethodDef *, PyObject *, PyObject *))imports[21].proc) 23 | #define PyObject_GetAttrString ((PyObject *(*)(PyObject *, char *))imports[22].proc) 24 | #define Py_BuildValue ((PyObject *(*)(char *, ...))imports[23].proc) 25 | #define PyObject_Call ((PyObject *(*)(PyObject *, PyObject *, PyObject *))imports[24].proc) 26 | #define PySys_WriteStderr ((void(*)(const char *, ...))imports[25].proc) 27 | #define PyErr_Occurred ((PyObject *(*)(void))imports[26].proc) 28 | #define PyErr_Clear ((void(*)(void))imports[27].proc) 29 | #define PyObject_IsInstance ((int(*)(PyObject *, PyObject *))imports[28].proc) 30 | #define PyInt_Type (*(PyObject(*))imports[29].proc) 31 | #define _Py_NoneStruct (*(PyObject(*))imports[30].proc) 32 | #define PyExc_ImportError (*(PyObject *(*))imports[31].proc) 33 | #define _Py_PackageContext (*(char *(*))imports[32].proc) 34 | #define PyGILState_Ensure ((PyGILState_STATE(*)(void))imports[33].proc) 35 | #define PyGILState_Release ((void(*)(PyGILState_STATE))imports[34].proc) 36 | #define PySys_SetObject ((void(*)(char *, PyObject *))imports[35].proc) 37 | #define PySys_GetObject ((PyObject *(*)(char *))imports[36].proc) 38 | #define PyString_FromString ((PyObject *(*)(char *))imports[37].proc) 39 | #define Py_FdIsInteractive ((int(*)(FILE *, char *))imports[38].proc) 40 | #define PyRun_InteractiveLoop ((int(*)(FILE *, char *))imports[39].proc) 41 | #define PySys_SetArgv ((void(*)(int, char **))imports[40].proc) 42 | #define PyImport_AddModule ((PyObject *(*)(char *))imports[41].proc) 43 | #define PyModule_GetDict ((PyObject *(*)(PyObject *))imports[42].proc) 44 | #define PySequence_Length ((Py_ssize_t(*)(PyObject *))imports[43].proc) 45 | #define PySequence_GetItem ((PyObject *(*)(PyObject *, Py_ssize_t))imports[44].proc) 46 | #define PyEval_EvalCode ((PyObject *(*)(PyCodeObject *, PyObject *, PyObject *))imports[45].proc) 47 | #define PyErr_Print ((void(*)(void))imports[46].proc) 48 | #define PyBool_FromLong ((PyObject *(*)(long))imports[47].proc) 49 | #define Py_VerboseFlag (*(int(*))imports[48].proc) 50 | #define Py_NoSiteFlag (*(int(*))imports[49].proc) 51 | #define Py_OptimizeFlag (*(int(*))imports[50].proc) 52 | #define Py_IgnoreEnvironmentFlag (*(int(*))imports[51].proc) 53 | #define PyObject_Str ((PyObject *(*)(PyObject *))imports[52].proc) 54 | #define PyList_New ((PyObject *(*)(Py_ssize_t))imports[53].proc) 55 | #define PyList_SetItem ((int(*)(PyObject *, Py_ssize_t, PyObject *))imports[54].proc) 56 | #define PyList_Append ((int(*)(PyObject *, PyObject *))imports[55].proc) 57 | -------------------------------------------------------------------------------- /zipextimporter.py: -------------------------------------------------------------------------------- 1 | r"""zipextimporter - an importer which can import extension modules from zipfiles 2 | 3 | This file and also _memimporter.pyd is part of the py2exe package. 4 | 5 | Overview 6 | ======== 7 | 8 | zipextimporter.py contains the ZipExtImporter class which allows to 9 | load Python binary extension modules contained in a zip.archive, 10 | without unpacking them to the file system. 11 | 12 | Call the zipextimporter.install() function to install the import hook, 13 | add a zip-file containing .pyd or .dll extension modules to sys.path, 14 | and import them. 15 | 16 | It uses the _memimporter extension which uses code from Joachim 17 | Bauch's MemoryModule library. This library emulates the win32 api 18 | function LoadLibrary. 19 | 20 | Sample usage 21 | ============ 22 | 23 | You have to prepare a zip-archive 'lib.zip' containing 24 | your Python's _socket.pyd for this example to work. 25 | 26 | >>> import zipextimporter 27 | >>> zipextimporter.install() 28 | >>> import sys 29 | >>> sys.path.insert(0, "lib.zip") 30 | >>> import _socket 31 | >>> print _socket 32 | 33 | >>> _socket.__file__ 34 | 'lib.zip\\_socket.pyd' 35 | >>> _socket.__loader__ 36 | 37 | >>> # Reloading also works correctly: 38 | >>> _socket is reload(_socket) 39 | True 40 | >>> 41 | 42 | """ 43 | import imp, sys 44 | import zipimport 45 | import _memimporter 46 | 47 | class ZipExtensionImporter(zipimport.zipimporter): 48 | _suffixes = [s[0] for s in imp.get_suffixes() if s[2] == imp.C_EXTENSION] 49 | 50 | def find_module(self, fullname, path=None): 51 | result = zipimport.zipimporter.find_module(self, fullname, path) 52 | if result: 53 | return result 54 | if fullname in ("pywintypes", "pythoncom"): 55 | fullname = fullname + "%d%d" % sys.version_info[:2] 56 | fullname = fullname.replace(".", "\\") + ".dll" 57 | if fullname in self._files: 58 | return self 59 | else: 60 | fullname = fullname.replace(".", "\\") 61 | for s in self._suffixes: 62 | if (fullname + s) in self._files: 63 | return self 64 | return None 65 | 66 | def load_module(self, fullname): 67 | verbose = _memimporter.get_verbose_flag() 68 | if fullname in sys.modules: 69 | mod = sys.modules[fullname] 70 | if verbose: 71 | sys.stderr.write("import %s # previously loaded from zipfile %s\n" % (fullname, self.archive)) 72 | return mod 73 | try: 74 | return zipimport.zipimporter.load_module(self, fullname) 75 | except zipimport.ZipImportError: 76 | pass 77 | initname = "init" + fullname.split(".")[-1] # name of initfunction 78 | filename = fullname.replace(".", "\\") 79 | if filename in ("pywintypes", "pythoncom"): 80 | filename = filename + "%d%d" % sys.version_info[:2] 81 | suffixes = ('.dll',) 82 | else: 83 | suffixes = self._suffixes 84 | for s in suffixes: 85 | path = filename + s 86 | if path in self._files: 87 | if verbose: 88 | sys.stderr.write("# found %s in zipfile %s\n" % (path, self.archive)) 89 | mod = _memimporter.import_module(fullname, path, initname, self.get_data) 90 | mod.__file__ = "%s\\%s" % (self.archive, path) 91 | mod.__loader__ = self 92 | if verbose: 93 | sys.stderr.write("import %s # loaded from zipfile %s\n" % (fullname, mod.__file__)) 94 | return mod 95 | raise zipimport.ZipImportError("can't find module %s" % fullname) 96 | 97 | def __repr__(self): 98 | return "<%s object %r>" % (self.__class__.__name__, self.archive) 99 | 100 | def install(): 101 | "Install the zipextimporter" 102 | sys.path_hooks.insert(0, ZipExtensionImporter) 103 | sys.path_importer_cache.clear() 104 | 105 | ##if __name__ == "__main__": 106 | ## import doctest 107 | ## doctest.testmod() 108 | -------------------------------------------------------------------------------- /py2exe/resources/StringTables.py: -------------------------------------------------------------------------------- 1 | ## 2 | ## Copyright (c) 2000-2013 Thomas Heller 3 | ## 4 | ## Permission is hereby granted, free of charge, to any person obtaining 5 | ## a copy of this software and associated documentation files (the 6 | ## "Software"), to deal in the Software without restriction, including 7 | ## without limitation the rights to use, copy, modify, merge, publish, 8 | ## distribute, sublicense, and/or sell copies of the Software, and to 9 | ## permit persons to whom the Software is furnished to do so, subject to 10 | ## the following conditions: 11 | ## 12 | ## The above copyright notice and this permission notice shall be 13 | ## included in all copies or substantial portions of the Software. 14 | ## 15 | ## THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 16 | ## EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 17 | ## MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 18 | ## NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 19 | ## LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 20 | ## OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 21 | ## WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 22 | ## 23 | 24 | # String Tables. 25 | # See Knowledge Base, Q200893 26 | # 27 | # 28 | # $Id: StringTables.py 738 2013-09-07 10:11:45Z theller $ 29 | # 30 | # $Log$ 31 | # Revision 1.1 2003/08/29 12:30:52 mhammond 32 | # New py2exe now uses the old resource functions :) 33 | # 34 | # Revision 1.1 2002/01/29 09:30:55 theller 35 | # version 0.3.0 36 | # 37 | # 38 | # 39 | 40 | RT_STRING = 6 # win32 resource type 41 | 42 | _use_unicode = 0 43 | 44 | try: 45 | _use_unicode = unicode 46 | except NameError: 47 | try: 48 | import pywintypes 49 | except ImportError: 50 | raise ImportError("Could not import StringTables, no unicode available") 51 | 52 | if _use_unicode: 53 | 54 | def w32_uc(text): 55 | """convert a string into unicode, then encode it into UTF-16 56 | little endian, ready to use for win32 apis""" 57 | return unicode(text, "unicode-escape").encode("utf-16-le") 58 | 59 | else: 60 | def w32_uc(text): 61 | return pywintypes.Unicode(text).raw 62 | 63 | class StringTable: 64 | 65 | """Collects (id, string) pairs and allows to build Win32 66 | StringTable resources from them.""" 67 | 68 | def __init__(self): 69 | self.strings = {} 70 | 71 | def add_string(self, id, text): 72 | self.strings[id] = text 73 | 74 | def sections(self): 75 | ids = self.strings.keys() 76 | ids.sort() 77 | sections = {} 78 | 79 | for id in ids: 80 | sectnum = id / 16 + 1 81 | ## Sigh. 1.5 doesn't have setdefault! 82 | ## table = sections.setdefault(sectnum, {}) 83 | table = sections.get(sectnum) 84 | if table is None: 85 | table = sections[sectnum] = {} 86 | table[id % 16] = self.strings[id] 87 | 88 | return sections 89 | 90 | def binary(self): 91 | import struct 92 | sections = [] 93 | for key, sect in self.sections().iteritems(): 94 | data = "" 95 | for i in range(16): 96 | ustr = w32_uc(sect.get(i, "")) 97 | fmt = "h%ds" % len(ustr) 98 | data = data + struct.pack(fmt, len(ustr)/2, ustr) 99 | sections.append((key, data)) 100 | return sections 101 | 102 | 103 | if __name__ == '__main__': 104 | st = StringTable() 105 | st.add_string(32, "Hallo") 106 | st.add_string(33, "Hallo1") 107 | st.add_string(34, "Hallo2") 108 | st.add_string(35, "Hallo3") 109 | st.add_string(1023, "__service__.VCULogService") 110 | st.add_string(1024, "__service__.VCULogService") 111 | st.add_string(1025, "__service__.VCULogService") 112 | st.add_string(1026, "__service__.VCULogService") 113 | 114 | import sys 115 | sys.path.append("c:/tmp") 116 | from hexdump import hexdump 117 | 118 | for sectnum, data in st.binary(): 119 | print "ID", sectnum 120 | hexdump(data) 121 | -------------------------------------------------------------------------------- /source/mktab.py: -------------------------------------------------------------------------------- 1 | # A script to generate helper files for dynamic linking to the Python dll 2 | # 3 | decls = ''' 4 | void, Py_Initialize, (void) 5 | int, PyRun_SimpleString, (char *) 6 | void, Py_Finalize, (void) 7 | char *, Py_GetPath, (void) 8 | void, Py_SetPythonHome, (char *) 9 | void, Py_SetProgramName, (char *) 10 | PyObject *, PyMarshal_ReadObjectFromString, (char *, Py_ssize_t) 11 | PyObject *, PyObject_CallFunction, (PyObject *, char *, ...) 12 | int, PyString_AsStringAndSize, (PyObject *, char **, Py_ssize_t *) 13 | char *, PyString_AsString, (PyObject *) 14 | int, PyArg_ParseTuple, (PyObject *, char *, ...) 15 | PyObject *, PyErr_Format, (PyObject *, const char *, ...) 16 | PyObject *, PyImport_ImportModule, (char *) 17 | PyObject *, PyInt_FromLong, (long) 18 | long, PyInt_AsLong, (PyObject *) 19 | PyObject *, PyLong_FromVoidPtr, (void *) 20 | PyObject *, Py_InitModule4, (char *, PyMethodDef *, char *, PyObject *, int) 21 | PyObject *, PyTuple_New, (Py_ssize_t) 22 | int, PyTuple_SetItem, (PyObject*, Py_ssize_t, PyObject *) 23 | int, Py_IsInitialized, (void) 24 | int, PyObject_SetAttrString, (PyObject *, char *, PyObject *) 25 | PyObject *, PyCFunction_NewEx, (PyMethodDef *, PyObject *, PyObject *) 26 | PyObject *, PyObject_GetAttrString, (PyObject *, char *) 27 | PyObject *, Py_BuildValue, (char *, ...) 28 | PyObject *, PyObject_Call, (PyObject *, PyObject *, PyObject *) 29 | void, PySys_WriteStderr, (const char *, ...) 30 | PyObject *, PyErr_Occurred, (void) 31 | void, PyErr_Clear, (void) 32 | int, PyObject_IsInstance, (PyObject *, PyObject *) 33 | 34 | PyObject, PyInt_Type 35 | PyObject, _Py_NoneStruct 36 | PyObject *, PyExc_ImportError 37 | char *, _Py_PackageContext 38 | 39 | PyGILState_STATE, PyGILState_Ensure, (void) 40 | void, PyGILState_Release, (PyGILState_STATE) 41 | 42 | void, PySys_SetObject, (char *, PyObject *) 43 | PyObject *, PySys_GetObject, (char *) 44 | PyObject *, PyString_FromString, (char *) 45 | int, Py_FdIsInteractive, (FILE *, char *) 46 | int, PyRun_InteractiveLoop, (FILE *, char *) 47 | void, PySys_SetArgv, (int, char **) 48 | PyObject *, PyImport_AddModule, (char *) 49 | PyObject *, PyModule_GetDict, (PyObject *) 50 | Py_ssize_t, PySequence_Length, (PyObject *) 51 | PyObject *, PySequence_GetItem, (PyObject *, Py_ssize_t) 52 | //int, PyCode_Check, (PyObject *) 53 | PyObject *, PyEval_EvalCode, (PyCodeObject *, PyObject *, PyObject *) 54 | void, PyErr_Print, (void) 55 | PyObject *, PyBool_FromLong, (long) 56 | int, Py_VerboseFlag 57 | int, Py_NoSiteFlag 58 | int, Py_OptimizeFlag 59 | int, Py_IgnoreEnvironmentFlag 60 | PyObject *, PyObject_Str, (PyObject *) 61 | PyObject *, PyList_New, (Py_ssize_t) 62 | int, PyList_SetItem, (PyObject *, Py_ssize_t, PyObject *) 63 | int, PyList_Append, (PyObject *, PyObject *) 64 | '''.strip().splitlines() 65 | 66 | import string 67 | 68 | hfile = open("import-tab.h", "w") 69 | cfile = open("import-tab.c", "w") 70 | 71 | index = 0 72 | for decl in decls: 73 | if not decl or decl.startswith("//"): 74 | continue 75 | items = decl.split(',', 2) 76 | if len(items) == 3: 77 | # exported function with argument list 78 | restype, name, argtypes = map(string.strip, items) 79 | print >> hfile, '#define %(name)s ((%(restype)s(*)%(argtypes)s)imports[%(index)d].proc)' % locals() 80 | elif len(items) == 2: 81 | # exported data 82 | typ, name = map(string.strip, items) 83 | print >> hfile, '#define %(name)s (*(%(typ)s(*))imports[%(index)s].proc)' % locals() 84 | else: 85 | raise ValueError, "could not parse %r" % decl 86 | if name == "Py_InitModule4": 87 | print >> cfile, '#ifdef _DEBUG' 88 | print >> cfile, '\t{ "Py_InitModule4TraceRefs", NULL },' % locals() 89 | print >> cfile, '#else' 90 | print >> cfile, '# if defined (_WIN64)' 91 | print >> cfile, '\t{ "Py_InitModule4_64", NULL },' % locals() 92 | print >> cfile, '# else' 93 | print >> cfile, '\t{ "Py_InitModule4", NULL },' % locals() 94 | print >> cfile, '# endif' 95 | print >> cfile, '#endif' 96 | else: 97 | print >> cfile, '\t{ "%(name)s", NULL },' % locals() 98 | 99 | index += 1 100 | 101 | hfile.close() 102 | cfile.close() 103 | -------------------------------------------------------------------------------- /py2exe/boot_com_servers.py: -------------------------------------------------------------------------------- 1 | # This support script is executed as the entry point for py2exe. 2 | 3 | import sys 4 | import win32api 5 | 6 | if 0: 7 | ################################################################ 8 | # XXX Remove later! 9 | class LOGGER: 10 | def __init__(self): 11 | self.softspace = None 12 | self.ofi = open(r"c:\comerror.txt", "w") 13 | def write(self, text): 14 | self.ofi.write(text) 15 | self.ofi.flush() 16 | sys.stderr = sys.stdout = LOGGER() 17 | sys.stderr.write("PATH is %s\n" % sys.path) 18 | ################################################################ 19 | # tell the win32 COM registering/unregistering code that we're inside 20 | # of an EXE/DLL 21 | import pythoncom 22 | if not hasattr(sys, "frozen"): 23 | # standard exes have none. 24 | sys.frozen = pythoncom.frozen = 1 25 | else: 26 | # com DLLs already have sys.frozen set to 'dll' 27 | pythoncom.frozen = sys.frozen 28 | 29 | # Add some extra imports here, just to avoid putting them as "hidden imports" 30 | # anywhere else - this script has the best idea about what it needs. 31 | # (and hidden imports are currently disabled :) 32 | import win32com.server.policy, win32com.server.util 33 | 34 | # Patchup sys.argv for our DLL 35 | if sys.frozen=="dll" and not hasattr(sys, "argv"): 36 | sys.argv = [win32api.GetModuleFileName(sys.frozendllhandle)] 37 | # We assume that py2exe has magically set com_module_names 38 | # to the module names that expose the COM objects we host. 39 | # Note that here all the COM modules for the app are imported - hence any 40 | # environment changes (such as sys.stderr redirection) will happen now. 41 | com_modules = [] 42 | try: 43 | for name in com_module_names: 44 | __import__(name) 45 | com_modules.append(sys.modules[name]) 46 | except NameError: 47 | print "This script is designed to be run from inside py2exe" 48 | sys.exit(1) 49 | del name 50 | 51 | def get_classes(module): 52 | return [ob 53 | for ob in module.__dict__.itervalues() 54 | if hasattr(ob, "_reg_progid_") 55 | ] 56 | 57 | def DllRegisterServer(): 58 | # Enumerate each module implementing an object 59 | import win32com.server.register 60 | for mod in com_modules: 61 | # register each class 62 | win32com.server.register.RegisterClasses(*get_classes(mod)) 63 | # see if the module has a custom registration function. 64 | extra_fun = getattr(mod, "DllRegisterServer", None) 65 | if extra_fun is not None: 66 | extra_fun() 67 | 68 | def DllUnregisterServer(): 69 | # Enumerate each module implementing an object 70 | import win32com.server.register 71 | for mod in com_modules: 72 | # see if the module has a custom unregister function. 73 | extra_fun = getattr(mod, "DllUnregisterServer", None) 74 | if extra_fun is not None: 75 | extra_fun() 76 | # and unregister each class 77 | win32com.server.register.UnregisterClasses(*get_classes(mod)) 78 | 79 | def DllInstall(bInstall, cmdline): 80 | # Enumerate each module implementing an object 81 | for mod in com_modules: 82 | # see if the module has the function. 83 | extra_fun = getattr(mod, "DllInstall", None) 84 | if extra_fun is not None: 85 | extra_fun(bInstall, cmdline) 86 | 87 | # Mainline code - executed always 88 | # If we are running as a .EXE, check and process command-line args 89 | if sys.frozen != "dll": 90 | import win32com.server.localserver 91 | for i in range(1, len(sys.argv)): 92 | arg = sys.argv[i].lower() 93 | # support "exe /regserver" 94 | if arg.find("/reg") > -1 or arg.find("--reg") > -1 \ 95 | or arg.find("-regserver") > -1: 96 | DllRegisterServer() 97 | break 98 | 99 | # support "exe /unreg...r" 100 | if arg.find("/unreg") > -1 or arg.find("--unreg") > -1 \ 101 | or arg.find("-unregserver") > -1: 102 | DllUnregisterServer() 103 | break 104 | 105 | # MS seems to like /automate to run the class factories. 106 | if arg.find("/automate") > -1: 107 | clsids = [] 108 | for m in com_modules: 109 | for k in get_classes(m): 110 | clsids.append(k._reg_clsid_) 111 | # Fire up the class factories, and run the servers 112 | win32com.server.localserver.serve(clsids) 113 | # All servers dead - we are done! 114 | break 115 | else: 116 | # You could do something else useful here. 117 | win32api.MessageBox(0, 118 | "This program hosts a COM Object and\r\n" 119 | "is started automatically\r\n" 120 | "(or maybe you want /register or /unregister?)", 121 | "COM Object") 122 | -------------------------------------------------------------------------------- /ANNOUNCE: -------------------------------------------------------------------------------- 1 | py2exe 0.6.9 released 2 | ===================== 3 | 4 | py2exe is a Python distutils extension which converts Python scripts 5 | into executable Windows programs, able to run without requiring a 6 | Python installation. Console and Windows (GUI) applications, Windows 7 | NT services, exe and dll COM servers are supported. 8 | 9 | Changes in 0.6.9: 10 | 11 | * Binaries for Python 2.6 and Python 2.7. 12 | 13 | * Fixed a modulefinder crash on certain relative imports. 14 | 15 | * Changed the py2exe\samples\singlefile\gui\test_wx.py sample to 16 | use the wx package instead of the old wxPython package. 17 | 18 | * Copy the manifest, if any, from the 'template' into the targets 19 | to ensure embedded assembly references, as required for python 2.6 based 20 | apps, are copied. 21 | 22 | * Allow each target to specify Vista User Access Control flags. For 23 | example, specifying 'uac_execution_info="requireAdministrator"' would 24 | force elevation for the final executable. 25 | 26 | 27 | Changes in 0.6.8: 28 | 29 | * Support for relative imports. 30 | 31 | * Fix MemoryLoadLibrary to handle loading function addresses by ordinal 32 | numbers. Patch and test by Matthias Miller. 33 | 34 | * Using the options compressed=1, bundle_files=3, and zipfile=None at 35 | the same time now works; patch from Alexey Borzenkov. 36 | 37 | * Allow renaming of single-executable files; patch from Alexey 38 | Borzenkov. 39 | 40 | * Embedding icon resources into the image now works correctly even for 41 | ico files containing multiple images. 42 | 43 | * pyd files from different packages with the same filename no longer 44 | conflict. Patch from Grant Edwards. 45 | 46 | * There are new samples for the 'typelibs' support, including the new 47 | option of pre-generating a typelib and specifying the file as an 48 | input to py2exe. 49 | 50 | * The test suite is now included in the source distribution. 51 | 52 | 53 | Changes in 0.6.6: 54 | 55 | * Better support for Python 2.5. 56 | 57 | * Experimental support for 64-bit builds of Python on win64. 58 | 59 | * Better ISAPI support. 60 | 61 | * New samples for ISAPI and COM servers. 62 | 63 | * Support for new "command-line styles" when building Windows services. 64 | 65 | Changes in 0.6.5: 66 | 67 | * Fixed modulefinder / mf related bugs introduced in 0.6.4. This 68 | will be most evident when working with things like 69 | win32com.shell and xml.xpath. 70 | 71 | * Files no longer keep read-only attributes when they are copied 72 | as this was causing problems with the copying of some MS DLLs. 73 | 74 | Changes in 0.6.4: 75 | 76 | * New skip-archive option which copies the Python bytecode files 77 | directly into the dist directory and subdirectories - no 78 | archive is used. 79 | 80 | * An experimental new custom-boot-script option which allows a 81 | boot script to be specified (e.g., --custom-boot-script=cbs.py) 82 | which can do things like installing a customized stdout 83 | blackhole. See py2exe's boot_common.py for examples of what can 84 | be done. The custom boot script is executed during startup of 85 | the executable immediately after boot_common.py is executed. 86 | 87 | * Thomas Heller's performance improvements for finding needed 88 | modules. 89 | 90 | * Mark Hammond's fix for thread-state errors when a py2exe 91 | created executable tries to use a py2exe created COM DLL. 92 | 93 | Changes in 0.6.3: 94 | 95 | * First release assembled by py2exe's new maintainer, Jimmy 96 | Retzlaff. Code changes in this release are from Thomas Heller 97 | and Gordon Scott. 98 | 99 | * The dll-excludes option is now available on the command line. 100 | It was only possible to specify that in the options argument to 101 | the setup function before. 102 | 103 | The dll-excludes option can now be used to filter out dlls like 104 | msvcr71.dll or even w9xpopen.exe. 105 | 106 | * Fix from Gordon Scott: py2exe crashed copying extension modules 107 | in packages. 108 | 109 | Changes in 0.6.2: 110 | 111 | * Several important bugfixes: 112 | 113 | - bundled extensions in packages did not work correctly, this 114 | made the wxPython single-file sample fail with newer wxPython 115 | versions. 116 | 117 | - occasionally dlls/pyds were loaded twice, with very strange 118 | effects. 119 | 120 | - the source distribution was not complete. 121 | 122 | - it is now possible to build a debug version of py2exe. 123 | 124 | Changes in 0.6.1: 125 | 126 | * py2exe can now bundle binary extensions and dlls into the 127 | library-archive or the executable itself. This allows to 128 | finally build real single-file executables. 129 | 130 | The bundled dlls and pyds are loaded at runtime by some special 131 | code that emulates the Windows LoadLibrary function - they are 132 | never unpacked to the file system. 133 | 134 | This part of the code is distributed under the MPL 1.1, so this 135 | license is now pulled in by py2exe. 136 | 137 | * By default py2exe now includes the codecs module and the 138 | encodings package. 139 | 140 | * Several other fixes. 141 | 142 | Homepage: 143 | 144 | 145 | 146 | Download from the usual location: 147 | 148 | 149 | 150 | Enjoy, 151 | Jimmy 152 | -------------------------------------------------------------------------------- /py2exe/samples/advanced/setup.py: -------------------------------------------------------------------------------- 1 | # A setup script showing advanced features. 2 | # 3 | # Note that for the NT service to build correctly, you need at least 4 | # win32all build 161, for the COM samples, you need build 163. 5 | # Requires wxPython, and Tim Golden's WMI module. 6 | 7 | # Note: WMI is probably NOT a good example for demonstrating how to 8 | # include a pywin32 typelib wrapper into the exe: wmi uses different 9 | # typelib versions on win2k and winXP. The resulting exe will only 10 | # run on the same windows version as the one used to build the exe. 11 | # So, the newest version of wmi.py doesn't use any typelib anymore. 12 | 13 | from distutils.core import setup 14 | import py2exe 15 | import sys 16 | 17 | # If run without args, build executables, in quiet mode. 18 | if len(sys.argv) == 1: 19 | sys.argv.append("py2exe") 20 | sys.argv.append("-q") 21 | 22 | class Target: 23 | def __init__(self, **kw): 24 | self.__dict__.update(kw) 25 | # for the versioninfo resources 26 | self.version = "0.5.0" 27 | self.company_name = "No Company" 28 | self.copyright = "no copyright" 29 | self.name = "py2exe sample files" 30 | 31 | ################################################################ 32 | # A program using wxPython 33 | 34 | # The manifest will be inserted as resource into test_wx.exe. This 35 | # gives the controls the Windows XP appearance (if run on XP ;-) 36 | # 37 | # Another option would be to store it in a file named 38 | # test_wx.exe.manifest, and copy it with the data_files option into 39 | # the dist-dir. 40 | # 41 | manifest_template = ''' 42 | 43 | 44 | 50 | %(prog)s Program 51 | 52 | 53 | 61 | 62 | 63 | 64 | 65 | 72 | 73 | 74 | 75 | ''' 76 | 77 | RT_MANIFEST = 24 78 | 79 | test_wx = Target( 80 | # used for the versioninfo resource 81 | description = "A sample GUI app", 82 | 83 | # what to build 84 | script = "test_wx.py", 85 | other_resources = [(RT_MANIFEST, 1, manifest_template % dict(prog="test_wx"))], 86 | ## icon_resources = [(1, "icon.ico")], 87 | dest_base = "test_wx") 88 | 89 | test_wx_console = Target( 90 | # used for the versioninfo resource 91 | description = "A sample GUI app with console", 92 | 93 | # what to build 94 | script = "test_wx.py", 95 | other_resources = [(RT_MANIFEST, 1, manifest_template % dict(prog="test_wx"))], 96 | dest_base = "test_wx_console") 97 | 98 | ################################################################ 99 | # A program using early bound COM, needs the typelibs option below 100 | test_wmi = Target( 101 | description = "Early bound COM client example", 102 | script = "test_wmi.py", 103 | ) 104 | 105 | ################################################################ 106 | # a NT service, modules is required 107 | myservice = Target( 108 | # used for the versioninfo resource 109 | description = "A sample Windows NT service", 110 | # what to build. For a service, the module name (not the 111 | # filename) must be specified! 112 | modules = ["MyService"] 113 | ) 114 | 115 | ################################################################ 116 | # a COM server (exe and dll), modules is required 117 | # 118 | # If you only want a dll or an exe, comment out one of the create_xxx 119 | # lines below. 120 | 121 | interp = Target( 122 | description = "Python Interpreter as COM server module", 123 | # what to build. For COM servers, the module name (not the 124 | # filename) must be specified! 125 | modules = ["win32com.servers.interp"], 126 | ## create_exe = False, 127 | ## create_dll = False, 128 | ) 129 | 130 | ################################################################ 131 | # COM pulls in a lot of stuff which we don't want or need. 132 | 133 | excludes = ["pywin", "pywin.debugger", "pywin.debugger.dbgcon", 134 | "pywin.dialogs", "pywin.dialogs.list"] 135 | 136 | dll_excludes = "MSVCP90.dll mswsock.dll powrprof.dll".split() 137 | 138 | from glob import glob 139 | data_files = [("Microsoft.VC90.CRT", glob(r'C:\Program Files (x86)\Microsoft Visual Studio 9.0\VC\redist\amd64\Microsoft.VC90.CRT\*.*'))] 140 | 141 | setup( 142 | options = {"py2exe": {"typelibs": 143 | # typelib for WMI 144 | [('{565783C6-CB41-11D1-8B02-00600806D9B6}', 0, 1, 2)], 145 | # create a compressed zip archive 146 | "compressed": 1, 147 | "optimize": 2, 148 | "dll_excludes": dll_excludes, 149 | "excludes": excludes}}, 150 | # The lib directory contains everything except the executables and the python dll. 151 | # Can include a subdirectory name. 152 | zipfile = "lib/shared.zip", 153 | 154 | data_files = data_files, 155 | service = [myservice], 156 | com_server = [interp], 157 | console = [test_wx_console, test_wmi], 158 | windows = [test_wx], 159 | ) 160 | -------------------------------------------------------------------------------- /test/test.py: -------------------------------------------------------------------------------- 1 | """ 2 | Run a series of test scripts before and after packaging with py2exe 3 | and ensure that stdout/stderr and the return code are the same. 4 | Several different modules are tested for compatibility purposes. 5 | 6 | Running all tests requires the following packages: 7 | 8 | ctypes 9 | EasyDialogs for Windows 10 | pywin32 11 | subprocess 12 | http://sourceforge.net/project/showfiles.php?group_id=6473 13 | """ 14 | 15 | import glob 16 | import os 17 | import shutil 18 | import subprocess 19 | import sys 20 | import time 21 | 22 | 23 | excludedTestFiles = dict( 24 | AMD64=['test_pysvn', 'test_win32com_shell.py'], 25 | Intel=[], 26 | ) 27 | 28 | excludedTestOptions = dict( 29 | AMD64=['--bundle=1', '--bundle=2'], 30 | Intel=[], 31 | ) 32 | 33 | options = { 34 | 'test_noZipFile.py' : ['--quiet', '--compressed', '--bundle=1', '--bundle=2', '--bundle=3', '--ascii'], 35 | } 36 | 37 | 38 | # This is the default setup script. A custom script will be used for 39 | # a test file called test_xyz.py if a corresponding setup_xyz.py is 40 | # present. 41 | py2exeTemplate = """ 42 | from distutils.core import setup 43 | import py2exe 44 | setup(console = ['%s']) 45 | """ 46 | 47 | generatedSetup = 'generated_setup.py' 48 | 49 | 50 | def getPlatform(version): 51 | for platform in 'AMD64', 'Intel': 52 | if '(' + platform + ')' in version: 53 | return platform 54 | raise RuntimeError("Can't determine Intel vs. AMD64 from: " + version) 55 | 56 | 57 | def PythonInterpreters(pattern): 58 | num_found = 0 59 | for folder in glob.glob(pattern): 60 | path = os.path.join(folder, 'python.exe') 61 | if os.path.exists(path): 62 | errorlevel, output = run(path, '-c', 'import sys; print sys.version') 63 | if errorlevel == 0: 64 | num_found += 1 65 | yield output.strip(), path 66 | if not num_found: 67 | yield sys.version, sys.executable 68 | 69 | 70 | def shortVersion(version): 71 | return '%s-%s' % (version.split()[0], getPlatform(version)) 72 | 73 | 74 | def reasonForSkipping(interpreter, basename): 75 | errorlevel, output = run(interpreter, 'checkTestModule.py', basename) 76 | if errorlevel: 77 | return output.strip() 78 | else: 79 | return None 80 | 81 | 82 | def clean(): 83 | for path in ['build', 'dist']: 84 | if os.path.exists(path): 85 | shutil.rmtree(path) 86 | if os.path.exists(generatedSetup): 87 | os.remove(generatedSetup) 88 | 89 | 90 | def run(*args): 91 | popen = subprocess.Popen( 92 | args, 93 | shell=True, 94 | stdout=subprocess.PIPE, 95 | stderr=subprocess.STDOUT 96 | ) 97 | output = popen.communicate() 98 | return popen.returncode, output[0] 99 | 100 | 101 | def main(interpreter_pattern=r'C:\Python*', test_pattern='test_*.py'): 102 | start = time.time() 103 | succeeded = {} 104 | skipped = {} 105 | failed = {} 106 | versions = [] 107 | for version, interpreter in PythonInterpreters(interpreter_pattern): 108 | print 'Python', version 109 | versions.append(version) 110 | succeeded[version] = 0 111 | skipped[version] = 0 112 | failed[version] = 0 113 | for test in glob.glob(test_pattern): 114 | if test not in excludedTestFiles[getPlatform(version)]: 115 | print ' ', test 116 | basename = os.path.splitext(test)[0] 117 | reason = reasonForSkipping(interpreter, basename) 118 | if reason: 119 | print ' SKIPPED: %s' % reason 120 | skipped[version] += 1 121 | continue 122 | 123 | # Execute script to get baseline 124 | baseline = run(interpreter, test) 125 | exe = os.path.join('dist', basename + '.exe') 126 | exe2 = os.path.join('dist', basename + '_2.exe') 127 | 128 | for option in options.get(test, ['--quiet', '--compressed', '--bundle=1', '--bundle=2', '--bundle=3', '--ascii', '--skip-archive']): 129 | if option not in excludedTestOptions[getPlatform(version)]: 130 | # Build exe 131 | clean() 132 | print ' ', option 133 | if os.path.exists(test.replace('test_', 'setup_')): 134 | open(generatedSetup, 'wt').write(open(test.replace('test_', 'setup_'), 'rt').read() % test) 135 | else: 136 | open(generatedSetup, 'wt').write(py2exeTemplate % test) 137 | run(interpreter, generatedSetup, 'py2exe', option) 138 | 139 | # Run exe and test against baseline 140 | os.rename(exe, exe2) # ensure that the exe works when renamed 141 | out2 = run(exe2) 142 | if out2 == baseline: 143 | succeeded[version] += 1 144 | else: 145 | failed[version] += 1 146 | print "FAILED." 147 | print "\tExpected:", baseline 148 | print "\t Got:", out2 149 | print 150 | 151 | clean() 152 | print 153 | 154 | columnWidth = max(map(len, map(shortVersion, versions))) 155 | format = '%' + str(columnWidth) + 's' 156 | format = ' '.join(4*[format]) 157 | separator = ' '.join(4*[columnWidth*'-']) 158 | print round(time.time()-start, 1), 'seconds' 159 | print 160 | print format % ('', 'Succeeded', 'Skipped', 'Failed') 161 | print separator 162 | for version in versions: 163 | print format % (shortVersion(version), succeeded[version], skipped[version], failed[version]) 164 | print separator 165 | print format % ('TOTAL', sum(succeeded.values()), sum(skipped.values()), sum(failed.values())) 166 | return sum(failed.values()) 167 | 168 | 169 | if __name__ == '__main__': 170 | sys.exit(main(*sys.argv[1:])) 171 | -------------------------------------------------------------------------------- /source/MyLoadLibrary.c: -------------------------------------------------------------------------------- 1 | #ifdef STANDALONE 2 | # include 3 | # include "Python-version.h" 4 | #else 5 | # include "Python-dynload.h" 6 | # include 7 | #endif 8 | #include 9 | 10 | #include "MemoryModule.h" 11 | #include "MyLoadLibrary.h" 12 | 13 | /* #define VERBOSE /* enable to print debug output */ 14 | 15 | /* 16 | 17 | Windows API: 18 | ============ 19 | 20 | HMODULE LoadLibraryA(LPCSTR) 21 | HMODULE GetModuleHandleA(LPCSTR) 22 | BOOL FreeLibrary(HMODULE) 23 | FARPROC GetProcAddress(HMODULE, LPCSTR) 24 | 25 | 26 | MemoryModule API: 27 | ================= 28 | 29 | HMEMORYMODULE MemoryLoadLibrary(void *) 30 | void MemoryFreeLibrary(HMEMORYMODULE) 31 | FARPROC MemoryGetProcAddress(HMEMORYMODULE, LPCSTR) 32 | 33 | HMEMORYMODULE MemoryLoadLibrayEx(void *, 34 | load_func, getproc_func, free_func, userdata) 35 | 36 | (there are also some resource functions which are not used here...) 37 | 38 | General API in this file: 39 | ========================= 40 | 41 | HMODULE MyLoadLibrary(LPCSTR, void *, userdata) 42 | HMODULE MyGetModuleHandle(LPCSTR) 43 | BOOL MyFreeLibrary(HMODULE) 44 | FARPROC MyGetProcAddress(HMODULE, LPCSTR) 45 | 46 | */ 47 | 48 | /**************************************************************** 49 | * A linked list of loaded MemoryModules. 50 | */ 51 | typedef struct tagLIST { 52 | HCUSTOMMODULE module; 53 | LPCSTR name; 54 | struct tagLIST *next; 55 | struct tagLIST *prev; 56 | int refcount; 57 | } LIST; 58 | 59 | static LIST *libraries; 60 | 61 | int level; 62 | 63 | static int dprintf(char *fmt, ...) 64 | { 65 | #ifdef VERBOSE 66 | va_list marker; 67 | int i; 68 | 69 | va_start(marker, fmt); 70 | for (i = 0; i < level; ++i) { 71 | putchar(' '); 72 | putchar(' '); 73 | } 74 | return vfprintf(stderr, fmt, marker) + 2*level; 75 | #else 76 | return 0; 77 | #endif 78 | } 79 | 80 | #define PUSH() level++ 81 | #define POP() level-- 82 | 83 | /**************************************************************** 84 | * Search for a loaded MemoryModule in the linked list, either by name 85 | * or by module handle. 86 | */ 87 | static LIST *_FindMemoryModule(LPCSTR name, HMODULE module) 88 | { 89 | LIST *lib = libraries; 90 | while (lib) { 91 | if (name && 0 == _stricmp(name, lib->name)) { 92 | dprintf("_FindMemoryModule(%s, %p) -> %s[%d]\n", name, module, lib->name, lib->refcount); 93 | return lib; 94 | } else if (module == lib->module) { 95 | dprintf("_FindMemoryModule(%s, %p) -> %s[%d]\n", name, module, lib->name, lib->refcount); 96 | return lib; 97 | } else { 98 | lib = lib->next; 99 | } 100 | } 101 | return NULL; 102 | } 103 | 104 | /**************************************************************** 105 | * Insert a MemoryModule into the linked list of loaded modules 106 | */ 107 | static LIST *_AddMemoryModule(LPCSTR name, HCUSTOMMODULE module) 108 | { 109 | LIST *entry = (LIST *)malloc(sizeof(LIST)); 110 | entry->name = _strdup(name); 111 | entry->module = module; 112 | entry->next = libraries; 113 | entry->prev = NULL; 114 | entry->refcount = 1; 115 | libraries = entry; 116 | dprintf("_AddMemoryModule(%s, %p) -> %p[%d]\n", 117 | name, module, entry, entry->refcount); 118 | return entry; 119 | } 120 | 121 | /**************************************************************** 122 | * Helper functions for MemoryLoadLibraryEx 123 | */ 124 | static FARPROC _GetProcAddress(HCUSTOMMODULE module, LPCSTR name, void *userdata) 125 | { 126 | return MyGetProcAddress(module, name); 127 | } 128 | 129 | static void _FreeLibrary(HCUSTOMMODULE module, void *userdata) 130 | { 131 | MyFreeLibrary(module); 132 | } 133 | 134 | static HCUSTOMMODULE _LoadLibrary(LPCSTR filename, void *userdata) 135 | { 136 | HCUSTOMMODULE result; 137 | LIST *lib; 138 | dprintf("_LoadLibrary(%s, %p)\n", filename, userdata); 139 | PUSH(); 140 | lib = _FindMemoryModule(filename, NULL); 141 | if (lib) { 142 | lib->refcount += 1; 143 | POP(); 144 | dprintf("_LoadLibrary(%s, %p) -> %s[%d]\n\n", 145 | filename, userdata, lib->name, lib->refcount); 146 | return lib->module; 147 | } 148 | if (userdata) { 149 | PyObject *findproc = (PyObject *)userdata; 150 | PyObject *res = PyObject_CallFunction(findproc, "s", filename); 151 | if (res && PyString_AsString(res)) { 152 | result = MemoryLoadLibraryEx(PyString_AsString(res), 153 | _LoadLibrary, _GetProcAddress, _FreeLibrary, 154 | userdata); 155 | Py_DECREF(res); 156 | if (result) { 157 | lib = _AddMemoryModule(filename, result); 158 | POP(); 159 | dprintf("_LoadLibrary(%s, %p) -> %s[%d]\n\n", 160 | filename, userdata, lib->name, lib->refcount); 161 | return lib->module; 162 | } else { 163 | dprintf("_LoadLibrary(%s, %p) failed with error %d\n", 164 | filename, userdata, GetLastError()); 165 | } 166 | } else { 167 | PyErr_Clear(); 168 | } 169 | } 170 | result = (HCUSTOMMODULE)LoadLibraryA(filename); 171 | POP(); 172 | dprintf("LoadLibraryA(%s) -> %p\n\n", filename, result); 173 | return result; 174 | } 175 | 176 | /**************************************************************** 177 | * Public functions 178 | */ 179 | HMODULE MyGetModuleHandle(LPCSTR name) 180 | { 181 | LIST *lib; 182 | lib = _FindMemoryModule(name, NULL); 183 | if (lib) 184 | return lib->module; 185 | return GetModuleHandle(name); 186 | } 187 | 188 | HMODULE MyLoadLibrary(LPCSTR name, void *bytes, void *userdata) 189 | { 190 | if (userdata) { 191 | HCUSTOMMODULE mod = _LoadLibrary(name, userdata); 192 | if (mod) 193 | return mod; 194 | } else if (bytes) { 195 | HCUSTOMMODULE mod = MemoryLoadLibraryEx(bytes, 196 | _LoadLibrary, 197 | _GetProcAddress, 198 | _FreeLibrary, 199 | userdata); 200 | if (mod) { 201 | LIST *lib = _AddMemoryModule(name, mod); 202 | return lib->module; 203 | } 204 | } 205 | return LoadLibrary(name); 206 | } 207 | 208 | BOOL MyFreeLibrary(HMODULE module) 209 | { 210 | LIST *lib = _FindMemoryModule(NULL, module); 211 | if (lib) { 212 | if (--lib->refcount == 0) 213 | MemoryFreeLibrary(module); 214 | return TRUE; 215 | } else 216 | return FreeLibrary(module); 217 | } 218 | 219 | FARPROC MyGetProcAddress(HMODULE module, LPCSTR procname) 220 | { 221 | FARPROC proc; 222 | LIST *lib = _FindMemoryModule(NULL, module); 223 | if (lib) { 224 | dprintf("MyGetProcAddress(%p, %p(%s))\n", module, procname, HIWORD(procname) ? procname : ""); 225 | PUSH(); 226 | proc = MemoryGetProcAddress(lib->module, procname); 227 | POP(); 228 | dprintf("MyGetProcAddress(%p, %p(%s)) -> %p\n", module, procname, HIWORD(procname) ? procname : "", proc); 229 | return proc; 230 | } else 231 | return GetProcAddress(module, procname); 232 | } 233 | -------------------------------------------------------------------------------- /py2exe/samples/extending/setup.py: -------------------------------------------------------------------------------- 1 | # A setup script showing how to extend py2exe. 2 | # 3 | # In this case, the py2exe command is subclassed to create an installation 4 | # script for InnoSetup, which can be compiled with the InnoSetup compiler 5 | # to a single file windows installer. 6 | # 7 | # By default, the installer will be created as dist\Output\setup.exe. 8 | 9 | from distutils.core import setup 10 | import py2exe 11 | import sys 12 | 13 | ################################################################ 14 | # A program using wxPython 15 | 16 | # The manifest will be inserted as resource into test_wx.exe. This 17 | # gives the controls the Windows XP appearance (if run on XP ;-) 18 | # 19 | # Another option would be to store if in a file named 20 | # test_wx.exe.manifest, and probably copy it with the data_files 21 | # option. 22 | # 23 | manifest_template = ''' 24 | 25 | 26 | 32 | %(prog)s Program 33 | 34 | 35 | 43 | 44 | 45 | 46 | ''' 47 | 48 | RT_MANIFEST = 24 49 | 50 | ################################################################ 51 | # arguments for the setup() call 52 | 53 | test_wx = dict( 54 | script = "test_wx.py", 55 | other_resources = [(RT_MANIFEST, 1, manifest_template % dict(prog="test_wx"))], 56 | dest_base = r"prog\test_wx") 57 | 58 | zipfile = r"lib\shardlib" 59 | 60 | options = {"py2exe": {"compressed": 1, 61 | "optimize": 2}} 62 | 63 | ################################################################ 64 | import os 65 | 66 | class InnoScript: 67 | def __init__(self, 68 | name, 69 | lib_dir, 70 | dist_dir, 71 | windows_exe_files = [], 72 | lib_files = [], 73 | version = "1.0"): 74 | self.lib_dir = lib_dir 75 | self.dist_dir = dist_dir 76 | if not self.dist_dir[-1] in "\\/": 77 | self.dist_dir += "\\" 78 | self.name = name 79 | self.version = version 80 | self.windows_exe_files = [self.chop(p) for p in windows_exe_files] 81 | self.lib_files = [self.chop(p) for p in lib_files] 82 | 83 | def chop(self, pathname): 84 | assert pathname.startswith(self.dist_dir) 85 | return pathname[len(self.dist_dir):] 86 | 87 | def create(self, pathname="dist\\test_wx.iss"): 88 | self.pathname = pathname 89 | ofi = self.file = open(pathname, "w") 90 | print >> ofi, "; WARNING: This script has been created by py2exe. Changes to this script" 91 | print >> ofi, "; will be overwritten the next time py2exe is run!" 92 | print >> ofi, r"[Setup]" 93 | print >> ofi, r"AppName=%s" % self.name 94 | print >> ofi, r"AppVerName=%s %s" % (self.name, self.version) 95 | print >> ofi, r"DefaultDirName={pf}\%s" % self.name 96 | print >> ofi, r"DefaultGroupName=%s" % self.name 97 | print >> ofi 98 | 99 | print >> ofi, r"[Files]" 100 | for path in self.windows_exe_files + self.lib_files: 101 | print >> ofi, r'Source: "%s"; DestDir: "{app}\%s"; Flags: ignoreversion' % (path, os.path.dirname(path)) 102 | print >> ofi 103 | 104 | print >> ofi, r"[Icons]" 105 | for path in self.windows_exe_files: 106 | print >> ofi, r'Name: "{group}\%s"; Filename: "{app}\%s"' % \ 107 | (self.name, path) 108 | print >> ofi, 'Name: "{group}\Uninstall %s"; Filename: "{uninstallexe}"' % self.name 109 | 110 | def compile(self): 111 | try: 112 | import ctypes 113 | except ImportError: 114 | try: 115 | import win32api 116 | except ImportError: 117 | import os 118 | os.startfile(self.pathname) 119 | else: 120 | print "Ok, using win32api." 121 | win32api.ShellExecute(0, "compile", 122 | self.pathname, 123 | None, 124 | None, 125 | 0) 126 | else: 127 | print "Cool, you have ctypes installed." 128 | res = ctypes.windll.shell32.ShellExecuteA(0, "compile", 129 | self.pathname, 130 | None, 131 | None, 132 | 0) 133 | if res < 32: 134 | raise RuntimeError, "ShellExecute failed, error %d" % res 135 | 136 | 137 | ################################################################ 138 | 139 | from py2exe.build_exe import py2exe 140 | 141 | class build_installer(py2exe): 142 | # This class first builds the exe file(s), then creates a Windows installer. 143 | # You need InnoSetup for it. 144 | def run(self): 145 | # First, let py2exe do it's work. 146 | py2exe.run(self) 147 | 148 | lib_dir = self.lib_dir 149 | dist_dir = self.dist_dir 150 | 151 | # create the Installer, using the files py2exe has created. 152 | script = InnoScript("test_wx", 153 | lib_dir, 154 | dist_dir, 155 | self.windows_exe_files, 156 | self.lib_files) 157 | print "*** creating the inno setup script***" 158 | script.create() 159 | print "*** compiling the inno setup script***" 160 | script.compile() 161 | # Note: By default the final setup.exe will be in an Output subdirectory. 162 | 163 | ################################################################ 164 | 165 | setup( 166 | options = options, 167 | # The lib directory contains everything except the executables and the python dll. 168 | zipfile = zipfile, 169 | windows = [test_wx], 170 | # use out build_installer class as extended py2exe build command 171 | cmdclass = {"py2exe": build_installer}, 172 | ) 173 | -------------------------------------------------------------------------------- /py2exe/boot_service.py: -------------------------------------------------------------------------------- 1 | # boot_service.py 2 | import sys 3 | import os 4 | import servicemanager 5 | import win32service 6 | import win32serviceutil 7 | import winerror 8 | # We assume that py2exe has magically set service_module_names 9 | # to the module names that expose the services we host. 10 | service_klasses = [] 11 | try: 12 | service_module_names 13 | except NameError: 14 | print "This script is designed to be run from inside py2exe" 15 | sys.exit(1) 16 | 17 | for name in service_module_names: 18 | # Use the documented fact that when a fromlist is present, 19 | # __import__ returns the innermost module in 'name'. 20 | # This makes it possible to have a dotted name work the 21 | # way you'd expect. 22 | mod = __import__(name, globals(), locals(), ['DUMMY']) 23 | for ob in mod.__dict__.itervalues(): 24 | if hasattr(ob, "_svc_name_"): 25 | service_klasses.append(ob) 26 | 27 | if not service_klasses: 28 | raise RuntimeError("No service classes found") 29 | 30 | # Event source records come from servicemanager 31 | evtsrc_dll = os.path.abspath(servicemanager.__file__) 32 | 33 | # Tell the Python servicemanager what classes we host. 34 | if len(service_klasses)==1: 35 | k = service_klasses[0] 36 | # One service - make the event name the same as the service. 37 | servicemanager.Initialize(k._svc_name_, evtsrc_dll) 38 | # And the class that hosts it. 39 | servicemanager.PrepareToHostSingle(k) 40 | else: 41 | # Multiple services (NOTE - this hasn't been tested!) 42 | # Use the base name of the exe as the event source 43 | servicemanager.Initialize(os.path.basename(sys.executable), evtsrc_dll) 44 | for k in service_klasses: 45 | servicemanager.PrepareToHostMultiple(k._svc_name_, k) 46 | 47 | ################################################################ 48 | 49 | if cmdline_style == "py2exe": 50 | # Simulate the old py2exe service command line handling (to some extent) 51 | # This could do with some re-thought 52 | 53 | class GetoptError(Exception): 54 | pass 55 | 56 | def w_getopt(args, options): 57 | """A getopt for Windows style command lines. 58 | 59 | Options may start with either '-' or '/', the option names may 60 | have more than one letter (examples are /tlb or -RegServer), and 61 | option names are case insensitive. 62 | 63 | Returns two elements, just as getopt.getopt. The first is a list 64 | of (option, value) pairs in the same way getopt.getopt does, but 65 | there is no '-' or '/' prefix to the option name, and the option 66 | name is always lower case. The second is the list of arguments 67 | which do not belong to any option. 68 | 69 | Different from getopt.getopt, a single argument not belonging to an option 70 | does not terminate parsing. 71 | """ 72 | opts = [] 73 | arguments = [] 74 | while args: 75 | if args[0][:1] in "/-": 76 | arg = args[0][1:] # strip the '-' or '/' 77 | arg = arg.lower() 78 | if arg + ':' in options: 79 | try: 80 | opts.append((arg, args[1])) 81 | except IndexError: 82 | raise GetoptError("option '%s' requires an argument" % args[0]) 83 | args = args[1:] 84 | elif arg in options: 85 | opts.append((arg, '')) 86 | else: 87 | raise GetoptError("invalid option '%s'" % args[0]) 88 | args = args[1:] 89 | else: 90 | arguments.append(args[0]) 91 | args = args[1:] 92 | 93 | return opts, arguments 94 | 95 | options = "help install remove auto disabled interactive user: password:".split() 96 | 97 | def usage(): 98 | print "Services are supposed to be run by the system after they have been installed." 99 | print "These command line options are available for (de)installation:" 100 | for opt in options: 101 | if opt.endswith(":"): 102 | print "\t-%s " % opt 103 | else: 104 | print "\t-%s" % opt 105 | print 106 | 107 | try: 108 | opts, args = w_getopt(sys.argv[1:], options) 109 | except GetoptError, detail: 110 | print detail 111 | usage() 112 | sys.exit(1) 113 | 114 | if opts: 115 | startType = None 116 | bRunInteractive = 0 117 | serviceDeps = None 118 | userName = None 119 | password = None 120 | 121 | do_install = False 122 | do_remove = False 123 | 124 | done = False 125 | 126 | for o, a in opts: 127 | if o == "help": 128 | usage() 129 | done = True 130 | elif o == "install": 131 | do_install = True 132 | elif o == "remove": 133 | do_remove = True 134 | elif o == "auto": 135 | startType = win32service.SERVICE_AUTO_START 136 | elif o == "disabled": 137 | startType = win32service.SERVICE_DISABLED 138 | elif o == "user": 139 | userName = a 140 | elif o == "password": 141 | password = a 142 | elif o == "interactive": 143 | bRunInteractive = True 144 | 145 | if do_install: 146 | for k in service_klasses: 147 | svc_display_name = getattr(k, "_svc_display_name_", k._svc_name_) 148 | svc_deps = getattr(k, "_svc_deps_", None) 149 | win32serviceutil.InstallService(None, 150 | k._svc_name_, 151 | svc_display_name, 152 | exeName = sys.executable, 153 | userName = userName, 154 | password = password, 155 | startType = startType, 156 | bRunInteractive = bRunInteractive, 157 | serviceDeps = svc_deps, 158 | description = getattr(k, "_svc_description_", None), 159 | ) 160 | done = True 161 | 162 | if do_remove: 163 | for k in service_klasses: 164 | win32serviceutil.RemoveService(k._svc_name_) 165 | done = True 166 | 167 | if done: 168 | sys.exit(0) 169 | else: 170 | usage() 171 | 172 | print "Connecting to the Service Control Manager" 173 | servicemanager.StartServiceCtrlDispatcher() 174 | 175 | elif cmdline_style == "pywin32": 176 | assert len(service_klasses) == 1, "Can only handle 1 service!" 177 | k = service_klasses[0] 178 | if len(sys.argv) == 1: 179 | try: 180 | servicemanager.StartServiceCtrlDispatcher() 181 | except win32service.error, details: 182 | if details[0] == winerror.ERROR_FAILED_SERVICE_CONTROLLER_CONNECT: 183 | win32serviceutil.usage() 184 | else: 185 | win32serviceutil.HandleCommandLine(k) 186 | 187 | elif cmdline_style == "custom": 188 | assert len(service_module_names) == 1, "Can only handle 1 service!" 189 | # Unlike services implemented in .py files, when a py2exe service exe is 190 | # executed without args, it may mean the service is being started. 191 | if len(sys.argv) == 1: 192 | try: 193 | servicemanager.StartServiceCtrlDispatcher() 194 | except win32service.error, details: 195 | if details[0] == winerror.ERROR_FAILED_SERVICE_CONTROLLER_CONNECT: 196 | win32serviceutil.usage() 197 | else: 198 | # assume/insist that the module provides a HandleCommandLine function. 199 | mod = sys.modules[service_module_names[0]] 200 | mod.HandleCommandLine() 201 | -------------------------------------------------------------------------------- /source/run_ctypes_dll.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2000-2013 Thomas Heller, Mark Hammond 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining 5 | * a copy of this software and associated documentation files (the 6 | * "Software"), to deal in the Software without restriction, including 7 | * without limitation the rights to use, copy, modify, merge, publish, 8 | * distribute, sublicense, and/or sell copies of the Software, and to 9 | * permit persons to whom the Software is furnished to do so, subject to 10 | * the following conditions: 11 | * 12 | * The above copyright notice and this permission notice shall be 13 | * included in all copies or substantial portions of the Software. 14 | * 15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 16 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 17 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 18 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 19 | * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 20 | * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 21 | * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 22 | */ 23 | 24 | #include 25 | #include 26 | #include 27 | 28 | #include 29 | #include "Python-dynload.h" 30 | #include "MyLoadLibrary.h" 31 | #include "actctx.h" 32 | 33 | // Function pointers we load from _ctypes.pyd 34 | typedef int (__stdcall *__PROC__DllCanUnloadNow) (void); 35 | typedef HRESULT (__stdcall *__PROC__DllGetClassObject) (REFCLSID, REFIID, LPVOID *); 36 | 37 | CRITICAL_SECTION csInit; // protecting our init code 38 | 39 | __PROC__DllCanUnloadNow Pyc_DllCanUnloadNow = NULL; 40 | __PROC__DllGetClassObject Pyc_DllGetClassObject = NULL; 41 | 42 | extern BOOL _LoadPythonDLL(HMODULE hmod); 43 | extern BOOL _LocateScript(HMODULE hmod); 44 | 45 | extern void init_memimporter(void); 46 | 47 | void SystemError(int error, char *msg) 48 | { 49 | char Buffer[1024]; 50 | int n; 51 | 52 | if (error) { 53 | LPVOID lpMsgBuf; 54 | FormatMessage( 55 | FORMAT_MESSAGE_ALLOCATE_BUFFER | 56 | FORMAT_MESSAGE_FROM_SYSTEM, 57 | NULL, 58 | error, 59 | MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), 60 | (LPSTR)&lpMsgBuf, 61 | 0, 62 | NULL 63 | ); 64 | strncpy(Buffer, lpMsgBuf, sizeof(Buffer)); 65 | LocalFree(lpMsgBuf); 66 | } else 67 | Buffer[0] = '\0'; 68 | n = lstrlen(Buffer); 69 | _snprintf(Buffer+n, sizeof(Buffer)-n, msg); 70 | MessageBox(GetFocus(), Buffer, NULL, MB_OK | MB_ICONSTOP); 71 | } 72 | 73 | BOOL have_init = FALSE; 74 | HANDLE g_ctypes = 0; 75 | HMODULE gInstance = 0; 76 | 77 | extern int init_with_instance(HMODULE, char *); 78 | extern void fini(); 79 | extern int run_script(void); 80 | 81 | int load_ctypes(void) 82 | { 83 | char dll_path[_MAX_PATH+_MAX_FNAME+1]; 84 | 85 | // shouldn't do this twice 86 | assert(g_ctypes == NULL); 87 | 88 | #ifdef _DEBUG 89 | strcpy(dll_path, "_ctypes_d.pyd"); 90 | #else 91 | strcpy(dll_path, "_ctypes.pyd"); 92 | #endif 93 | 94 | g_ctypes = MyGetModuleHandle(dll_path); 95 | /* 96 | if (g_ctypes == NULL) { 97 | // not already loaded - try and load from the current dir 98 | char *temp; 99 | GetModuleFileNameA(gInstance, dll_path, sizeof(dll_path)); 100 | temp = dll_path + strlen(dll_path); 101 | while (temp>dll_path && *temp != '\\') 102 | temp--; 103 | // and printf directly in the buffer. 104 | // temp points to '\\filename.ext'! 105 | #ifdef _DEBUG 106 | g_ctypes = MyGetModuleHandle("_ctypes_d.pyd"); 107 | #else 108 | g_ctypes = MyGetModuleHandle("_ctypes.pyd"); 109 | #endif 110 | g_ctypes = LoadLibraryEx(dll_path, // points to name of executable module 111 | NULL, // HANDLE hFile, // reserved, must be NULL 112 | LOAD_WITH_ALTERED_SEARCH_PATH // DWORD dwFlags // entry-point execution flag 113 | ); 114 | } 115 | */ 116 | if (g_ctypes == NULL) { 117 | OutputDebugString("GetModuleHandle _ctypes?.pyd failed"); 118 | // give up in disgust 119 | return -1; 120 | } 121 | 122 | Pyc_DllCanUnloadNow = (__PROC__DllCanUnloadNow)MyGetProcAddress(g_ctypes, "DllCanUnloadNow"); 123 | Pyc_DllGetClassObject = (__PROC__DllGetClassObject)MyGetProcAddress(g_ctypes, "DllGetClassObject"); 124 | assert(Pyc_DllGetClassObject); 125 | 126 | return 0; 127 | } 128 | 129 | int check_init() 130 | { 131 | if (!have_init) { 132 | EnterCriticalSection(&csInit); 133 | // Check the flag again - another thread may have beat us to it! 134 | if (!have_init) { 135 | PyObject *frozen; 136 | /* If Python had previously been initialized, we must use 137 | PyGILState_Ensure normally. If Python has not been initialized, 138 | we must leave the thread state unlocked, so other threads can 139 | call in. 140 | */ 141 | PyGILState_STATE restore_state = PyGILState_UNLOCKED; 142 | if (!Py_IsInitialized) { 143 | // Python function pointers are yet to be loaded 144 | // - force that now. See above for why we *must* 145 | // know about the initialized state of Python so 146 | // we can setup the thread-state correctly 147 | // before calling init_with_instance(); This is 148 | // wasteful, but fixing it would involve a 149 | // restructure of init_with_instance() 150 | _LocateScript(gInstance); 151 | _LoadPythonDLL(gInstance); 152 | } 153 | if (Py_IsInitialized && Py_IsInitialized()) { 154 | restore_state = PyGILState_Ensure(); 155 | } 156 | // a little DLL magic. Set sys.frozen='dll' 157 | init_with_instance(gInstance, "dll"); 158 | init_memimporter(); 159 | frozen = PyLong_FromVoidPtr(gInstance); 160 | if (frozen) { 161 | PySys_SetObject("frozendllhandle", frozen); 162 | Py_DECREF(frozen); 163 | } 164 | // Now run the generic script - this always returns in a DLL. 165 | run_script(); 166 | have_init = TRUE; 167 | if (g_ctypes == NULL) 168 | load_ctypes(); 169 | // Reset the thread-state, so any thread can call in 170 | PyGILState_Release(restore_state); 171 | } 172 | LeaveCriticalSection(&csInit); 173 | } 174 | return g_ctypes != NULL; 175 | } 176 | 177 | 178 | // ***************************************************************** 179 | // All the public entry points needed for COM, Windows, and anyone 180 | // else who wants their piece of the action. 181 | // ***************************************************************** 182 | BOOL WINAPI DllMain(HINSTANCE hInstance, DWORD dwReason, LPVOID lpReserved) 183 | { 184 | if ( dwReason == DLL_PROCESS_ATTACH) { 185 | gInstance = hInstance; 186 | InitializeCriticalSection(&csInit); 187 | _MyLoadActCtxPointers(); 188 | if (pfnGetCurrentActCtx && pfnAddRefActCtx) 189 | if ((*pfnGetCurrentActCtx)(&PyWin_DLLhActivationContext)) 190 | if (!(*pfnAddRefActCtx)(PyWin_DLLhActivationContext)) 191 | OutputDebugString("Python failed to load the default activation context\n"); 192 | } 193 | else if ( dwReason == DLL_PROCESS_DETACH ) { 194 | gInstance = 0; 195 | DeleteCriticalSection(&csInit); 196 | if (pfnReleaseActCtx) 197 | (*pfnReleaseActCtx)(PyWin_DLLhActivationContext); 198 | // not much else safe to do here 199 | } 200 | return TRUE; 201 | } 202 | 203 | HRESULT __stdcall DllCanUnloadNow(void) 204 | { 205 | HRESULT rc; 206 | check_init(); 207 | assert(Pyc_DllCanUnloadNow); 208 | if (!Pyc_DllCanUnloadNow) return E_UNEXPECTED; 209 | rc = Pyc_DllCanUnloadNow(); 210 | return rc; 211 | } 212 | 213 | //__declspec(dllexport) int __stdcall DllGetClassObject(void *rclsid, void *riid, void *ppv) 214 | HRESULT __stdcall DllGetClassObject(REFCLSID rclsid, REFIID riid, LPVOID *ppv) 215 | { 216 | HRESULT rc; 217 | check_init(); 218 | assert(Pyc_DllGetClassObject); 219 | if (!Pyc_DllGetClassObject) return E_UNEXPECTED; 220 | rc = Pyc_DllGetClassObject(rclsid, riid, ppv); 221 | return rc; 222 | } 223 | 224 | 225 | STDAPI DllRegisterServer() 226 | { 227 | int rc=0; 228 | PyGILState_STATE state; 229 | check_init(); 230 | state = PyGILState_Ensure(); 231 | rc = PyRun_SimpleString("DllRegisterServer()\n"); 232 | if (rc != 0) 233 | PyErr_Print(); 234 | PyGILState_Release(state); 235 | return rc==0 ? 0 : SELFREG_E_CLASS; 236 | } 237 | 238 | STDAPI DllUnregisterServer() 239 | { 240 | int rc=0; 241 | PyGILState_STATE state; 242 | check_init(); 243 | state = PyGILState_Ensure(); 244 | rc = PyRun_SimpleString("DllUnregisterServer()\n"); 245 | if (rc != 0) 246 | PyErr_Print(); 247 | PyGILState_Release(state); 248 | return rc==0 ? 0 : SELFREG_E_CLASS; 249 | } 250 | -------------------------------------------------------------------------------- /source/run_isapi.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2000, 2001 Thomas Heller, Mark Hammond 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining 5 | * a copy of this software and associated documentation files (the 6 | * "Software"), to deal in the Software without restriction, including 7 | * without limitation the rights to use, copy, modify, merge, publish, 8 | * distribute, sublicense, and/or sell copies of the Software, and to 9 | * permit persons to whom the Software is furnished to do so, subject to 10 | * the following conditions: 11 | * 12 | * The above copyright notice and this permission notice shall be 13 | * included in all copies or substantial portions of the Software. 14 | * 15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 16 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 17 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 18 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 19 | * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 20 | * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 21 | * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 22 | */ 23 | 24 | #include 25 | #include "httpext.h" 26 | #include 27 | //#include "Python.h" 28 | #include 29 | #include "Python-dynload.h" 30 | 31 | 32 | typedef BOOL (__stdcall *__PROC__GetExtensionVersion)(HSE_VERSION_INFO *pVer); 33 | typedef BOOL (__stdcall *__PROC__HttpExtensionProc)(EXTENSION_CONTROL_BLOCK *pECB); 34 | typedef BOOL (__stdcall *__PROC__TerminateExtension)(DWORD dwFlags); 35 | typedef BOOL (__stdcall *__PROC__GetFilterVersion)(HTTP_FILTER_VERSION *pVer); 36 | typedef DWORD (__stdcall *__PROC__HttpFilterProc)(HTTP_FILTER_CONTEXT *phfc, DWORD NotificationType, VOID *pvData); 37 | typedef BOOL (__stdcall *__PROC__TerminateFilter)(DWORD status); 38 | typedef void (__stdcall *__PROC__PyISAPISetOptions)(const char *modname, BOOL is_frozen); 39 | typedef BOOL (__stdcall *__PROC__WriteEventLogMessage)(WORD eventType, DWORD eventID, WORD num_inserts, const char **inserts); 40 | 41 | 42 | CRITICAL_SECTION csInit; // protecting our init code 43 | HMODULE gInstance = 0; 44 | HMODULE hmodPyISAPI = 0; 45 | BOOL have_init = FALSE; 46 | 47 | __PROC__GetExtensionVersion pGetExtensionVersion = NULL; 48 | __PROC__HttpExtensionProc pHttpExtensionProc = NULL; 49 | __PROC__TerminateExtension pTerminateExtension = NULL; 50 | __PROC__GetFilterVersion pGetFilterVersion = NULL; 51 | __PROC__HttpFilterProc pHttpFilterProc = NULL; 52 | __PROC__TerminateFilter pTerminateFilter = NULL; 53 | __PROC__PyISAPISetOptions pPyISAPISetOptions = NULL; 54 | __PROC__WriteEventLogMessage pWriteEventLogMessage = NULL; 55 | 56 | extern int init_with_instance(HMODULE, char *); 57 | extern BOOL _LoadPythonDLL(HMODULE); 58 | 59 | extern void fini(); 60 | extern int run_script(void); 61 | extern void init_memimporter(void); 62 | 63 | void SystemError(int error, char *msg) 64 | { 65 | // From pywin32's pyisapi_messages.h: 66 | // #define E_PYISAPI_STARTUP_FAILED ((DWORD)0xC0001100L) 67 | // 0x1100 == E_PYISAPI_STARTUP_FAILED 68 | // We use this even when we can't use pyisapi to log the record. 69 | const DWORD evt_id = (DWORD)0xC0001100L; 70 | 71 | char Buffer[1024]; 72 | int n; 73 | HANDLE hEventSource; 74 | 75 | if (error) { 76 | LPVOID lpMsgBuf; 77 | FormatMessage( 78 | FORMAT_MESSAGE_ALLOCATE_BUFFER | 79 | FORMAT_MESSAGE_FROM_SYSTEM, 80 | NULL, 81 | error, 82 | MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), 83 | (LPSTR)&lpMsgBuf, 84 | 0, 85 | NULL 86 | ); 87 | strncpy(Buffer, lpMsgBuf, sizeof(Buffer)); 88 | LocalFree(lpMsgBuf); 89 | } else 90 | Buffer[0] = '\0'; 91 | 92 | // Can't display messages in a service. Write to the event log. 93 | // Later pywin32 versions export a function for writing to the 94 | // event log - useful as it also has the message resources necessary 95 | // to get reasonable looking messages. 96 | // If that exists, use it - otherwise write an "ugly" message. 97 | 98 | if (pWriteEventLogMessage) { 99 | // Can use the one exported! 100 | TCHAR * inserts[] = {msg, Buffer}; 101 | pWriteEventLogMessage(EVENTLOG_ERROR_TYPE, evt_id, 102 | 2, inserts); 103 | return; // all done! 104 | } 105 | 106 | n = lstrlen(Buffer); 107 | _snprintf(Buffer+n, sizeof(Buffer)-n, msg); 108 | 109 | // We have no message resources, so the message will be somewhat 110 | // ugly - but so long as the info is there, that's ok. 111 | hEventSource = RegisterEventSource(NULL, "ISAPI Filter or Extension"); 112 | if (hEventSource) { 113 | // a big sucky - windows error already in string - so we 114 | // send "see above" 115 | TCHAR * inserts[] = {Buffer, "see above"}; 116 | ReportEvent(hEventSource, // handle of event source 117 | EVENTLOG_ERROR_TYPE, // event type 118 | 0, // event category 119 | evt_id, // event ID 120 | NULL, // current user's SID 121 | 2, // strings in lpszStrings 122 | 0, // no bytes of raw data 123 | inserts, // array of error strings 124 | NULL); // no raw data 125 | DeregisterEventSource(hEventSource); 126 | } 127 | } 128 | 129 | BOOL check_init() 130 | { 131 | BOOL ok = TRUE; // if already initialized all is good. 132 | if (!have_init) { 133 | EnterCriticalSection(&csInit); 134 | // Check the flag again - another thread may have beat us to it! 135 | if (!have_init) { 136 | 137 | PyGILState_STATE restore_state = PyGILState_UNLOCKED; 138 | PyObject *frozen; 139 | char dll_path[1024]; 140 | char *slash; 141 | 142 | ok = FALSE; // must be reset after good init. 143 | // We must ensure Python is loaded, and therefore the 144 | // function pointers are non-NULL, before we can check 145 | // if Python is initialized! Further, as our 146 | // ISAPI dll depends on python, we must load Python 147 | // before loading our module. 148 | if (!_LoadPythonDLL(gInstance)) 149 | goto done; 150 | 151 | // Find and load the pyisapi DLL. 152 | GetModuleFileName(gInstance, dll_path, sizeof(dll_path)/sizeof(dll_path[0])); 153 | slash = strrchr(dll_path, '\\'); 154 | if (slash) { 155 | // insert an underscore. 156 | char *pos_move = dll_path + strlen(dll_path); 157 | while (pos_move > slash) { 158 | *(pos_move+1) = *pos_move; 159 | pos_move --; 160 | } 161 | *(slash+1) = '_'; 162 | hmodPyISAPI = LoadLibrary(dll_path); 163 | if (hmodPyISAPI) { 164 | pGetExtensionVersion = (__PROC__GetExtensionVersion)GetProcAddress(hmodPyISAPI, "GetExtensionVersion"); 165 | pHttpExtensionProc = (__PROC__HttpExtensionProc)GetProcAddress(hmodPyISAPI, "HttpExtensionProc"); 166 | pTerminateExtension = (__PROC__TerminateExtension)GetProcAddress(hmodPyISAPI, "TerminateExtension"); 167 | pGetFilterVersion = (__PROC__GetFilterVersion)GetProcAddress(hmodPyISAPI, "GetFilterVersion"); 168 | pHttpFilterProc = (__PROC__HttpFilterProc)GetProcAddress(hmodPyISAPI, "HttpFilterProc"); 169 | pTerminateFilter = (__PROC__TerminateFilter)GetProcAddress(hmodPyISAPI, "TerminateFilter"); 170 | pPyISAPISetOptions = (__PROC__PyISAPISetOptions)GetProcAddress(hmodPyISAPI, "PyISAPISetOptions"); 171 | pWriteEventLogMessage = (__PROC__WriteEventLogMessage)GetProcAddress(hmodPyISAPI, "WriteEventLogMessage"); 172 | } else { 173 | SystemError(GetLastError(), "Failed to load the extension DLL"); 174 | } 175 | } else { 176 | SystemError(GetLastError(), "Failed to locate my own DLL"); 177 | } 178 | 179 | if (Py_IsInitialized && Py_IsInitialized()) 180 | restore_state = PyGILState_Ensure(); 181 | // a little DLL magic. Set sys.frozen='dll' 182 | if (init_with_instance(gInstance, "dll") != 0) { 183 | PyGILState_Release(restore_state); 184 | goto done; 185 | } 186 | init_memimporter(); 187 | frozen = PyLong_FromVoidPtr(gInstance); 188 | if (frozen) { 189 | PySys_SetObject("frozendllhandle", frozen); 190 | Py_DECREF(frozen); 191 | } 192 | // Now run the generic script - this always returns in a DLL. 193 | run_script(); 194 | // Let the ISAPI extension know about the frozen environment. 195 | // (the ISAPI boot code currently has no way of talking directly 196 | // to the pyISAPI dll, so we fetch it directly from the py2exe 197 | // 'variable' which is already in module '__main__'. 198 | if (pPyISAPISetOptions) { 199 | PyObject *main = PyImport_ImportModule("__main__"); 200 | if (main) { 201 | PyObject *name = PyObject_GetAttrString(main, "isapi_module_name"); 202 | char *str; 203 | if (name && (str = PyString_AsString(name))) 204 | (*pPyISAPISetOptions)(str, TRUE); 205 | else 206 | PyErr_Clear(); // In case PyString_AsString fails 207 | Py_XDECREF(name); 208 | } 209 | Py_DECREF(main); 210 | } 211 | have_init = TRUE; 212 | PyGILState_Release(restore_state); 213 | ok = TRUE; 214 | } 215 | done: 216 | LeaveCriticalSection(&csInit); 217 | } 218 | return ok; 219 | } 220 | 221 | // ***************************************************************** 222 | // All the public entry points needed for COM, Windows, and anyone 223 | // else who wants their piece of the action. 224 | // ***************************************************************** 225 | 226 | BOOL WINAPI DllMain(HINSTANCE hInstance, DWORD dwReason, LPVOID lpReserved) 227 | { 228 | if ( dwReason == DLL_PROCESS_ATTACH) { 229 | gInstance = hInstance; 230 | InitializeCriticalSection(&csInit); 231 | } 232 | else if ( dwReason == DLL_PROCESS_DETACH ) { 233 | gInstance = 0; 234 | if (hmodPyISAPI) 235 | FreeLibrary(hmodPyISAPI); 236 | DeleteCriticalSection(&csInit); 237 | } 238 | return TRUE; 239 | } 240 | 241 | BOOL WINAPI GetExtensionVersion(HSE_VERSION_INFO *pVer) 242 | { 243 | if (!check_init() || !pGetExtensionVersion) return FALSE; 244 | return (*pGetExtensionVersion)(pVer); 245 | } 246 | DWORD WINAPI HttpExtensionProc(EXTENSION_CONTROL_BLOCK *pECB) 247 | { 248 | if (!check_init() || !pHttpExtensionProc) return HSE_STATUS_ERROR; 249 | return (*pHttpExtensionProc)(pECB); 250 | } 251 | BOOL WINAPI TerminateExtension(DWORD dwFlags) 252 | { 253 | if (!check_init() || !pTerminateExtension) return FALSE; 254 | return (*pTerminateExtension)(dwFlags); 255 | } 256 | 257 | BOOL WINAPI GetFilterVersion(HTTP_FILTER_VERSION *pVer) 258 | { 259 | if (!check_init() || !pGetFilterVersion) return FALSE; 260 | return (*pGetFilterVersion)(pVer); 261 | } 262 | 263 | DWORD WINAPI HttpFilterProc(HTTP_FILTER_CONTEXT *phfc, DWORD NotificationType, VOID *pvData) 264 | { 265 | if (!check_init() || !pHttpFilterProc) return SF_STATUS_REQ_NEXT_NOTIFICATION; 266 | return (*pHttpFilterProc)(phfc, NotificationType, pvData); 267 | } 268 | 269 | BOOL WINAPI TerminateFilter(DWORD status) 270 | { 271 | if (!check_init() || !pTerminateFilter) return FALSE; 272 | return (*pTerminateFilter)(status); 273 | } 274 | -------------------------------------------------------------------------------- /source/run_dll.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2000-2013 Thomas Heller, Mark Hammond 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining 5 | * a copy of this software and associated documentation files (the 6 | * "Software"), to deal in the Software without restriction, including 7 | * without limitation the rights to use, copy, modify, merge, publish, 8 | * distribute, sublicense, and/or sell copies of the Software, and to 9 | * permit persons to whom the Software is furnished to do so, subject to 10 | * the following conditions: 11 | * 12 | * The above copyright notice and this permission notice shall be 13 | * included in all copies or substantial portions of the Software. 14 | * 15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 16 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 17 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 18 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 19 | * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 20 | * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 21 | * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 22 | */ 23 | #include "Python-dynload.h" 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include "MyLoadLibrary.h" 29 | 30 | // Function pointers we load from pythoncom 31 | typedef int (__stdcall *__PROC__DllCanUnloadNow) (void); 32 | typedef HRESULT (__stdcall *__PROC__DllGetClassObject) (REFCLSID, REFIID, LPVOID *); 33 | typedef void (__cdecl *__PROC__PyCom_CoUninitialize) (void); 34 | 35 | extern BOOL _LoadPythonDLL(HMODULE hmod); 36 | extern BOOL _LocateScript(HMODULE hmod); 37 | 38 | CRITICAL_SECTION csInit; // protecting our init code 39 | 40 | __PROC__DllCanUnloadNow Pyc_DllCanUnloadNow = NULL; 41 | __PROC__DllGetClassObject Pyc_DllGetClassObject = NULL; 42 | __PROC__PyCom_CoUninitialize PyCom_CoUninitialize = NULL; 43 | 44 | void SystemError(int error, char *msg) 45 | { 46 | char Buffer[1024]; 47 | int n; 48 | 49 | if (error) { 50 | LPVOID lpMsgBuf; 51 | FormatMessage( 52 | FORMAT_MESSAGE_ALLOCATE_BUFFER | 53 | FORMAT_MESSAGE_FROM_SYSTEM, 54 | NULL, 55 | error, 56 | MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), 57 | (LPSTR)&lpMsgBuf, 58 | 0, 59 | NULL 60 | ); 61 | strncpy(Buffer, lpMsgBuf, sizeof(Buffer)); 62 | LocalFree(lpMsgBuf); 63 | } else 64 | Buffer[0] = '\0'; 65 | n = lstrlen(Buffer); 66 | _snprintf(Buffer+n, sizeof(Buffer)-n, msg); 67 | MessageBox(GetFocus(), Buffer, NULL, MB_OK | MB_ICONSTOP); 68 | } 69 | 70 | BOOL have_init = FALSE; 71 | HANDLE gPythoncom = 0; 72 | HMODULE gInstance = 0; 73 | 74 | extern int init_with_instance(HMODULE, char *); 75 | extern void fini(); 76 | extern int run_script(void); 77 | extern void init_memimporter(void); 78 | 79 | int load_pythoncom(void) 80 | { 81 | char dll_path[_MAX_PATH+_MAX_FNAME+1]; 82 | char major[35] = "x"; // itoa max size is 33. 83 | char minor[35] = "y"; 84 | #ifdef _DEBUG 85 | char *suffix = "_d"; 86 | #else 87 | char *suffix = ""; 88 | #endif 89 | /* 90 | // no reference added by PySys_GetObject 91 | PyObject *ob_vi = PySys_GetObject("version_info"); 92 | if (ob_vi && PyTuple_Check(ob_vi) && PyTuple_Size(ob_vi)>1) { 93 | itoa(PyInt_AsLong(PyTuple_GET_ITEM(ob_vi, 0)), major, 10); 94 | itoa(PyInt_AsLong(PyTuple_GET_ITEM(ob_vi, 1)), minor, 10); 95 | } 96 | */ 97 | // shouldn't do this twice 98 | assert(gPythoncom == NULL); 99 | 100 | snprintf(dll_path, sizeof(dll_path), PYTHONCOM); 101 | gPythoncom = MyGetModuleHandle(dll_path); 102 | // GetModuleFileNameA and LoadLibraryEx would not work in single-file dlls 103 | /* 104 | if (gPythoncom == NULL) { 105 | // not already loaded - try and load from the current dir 106 | char *temp; 107 | GetModuleFileNameA(gInstance, dll_path, sizeof(dll_path)); 108 | temp = dll_path + strlen(dll_path); 109 | while (temp>dll_path && *temp != '\\') 110 | temp--; 111 | // and printf directly in the buffer. 112 | // don't overwrite the backslash, so temp+1! 113 | snprintf(temp+1, sizeof(dll_path)-strlen(temp+1), 114 | "pythoncom%s%s%s.dll", major, minor, suffix); 115 | gPythoncom = LoadLibraryEx(dll_path, // points to name of executable module 116 | NULL, // HANDLE hFile, // reserved, must be NULL 117 | LOAD_WITH_ALTERED_SEARCH_PATH // DWORD dwFlags // entry-point execution flag 118 | ); 119 | } 120 | */ 121 | if (gPythoncom == NULL) { 122 | OutputDebugString("GetModuleHandle pythoncom failed"); 123 | // give up in disgust 124 | return -1; 125 | } 126 | 127 | Pyc_DllCanUnloadNow = (__PROC__DllCanUnloadNow)MyGetProcAddress(gPythoncom, "DllCanUnloadNow"); 128 | Pyc_DllGetClassObject = (__PROC__DllGetClassObject)MyGetProcAddress(gPythoncom, "DllGetClassObject"); 129 | PyCom_CoUninitialize = (__PROC__PyCom_CoUninitialize)MyGetProcAddress(gPythoncom, "PyCom_CoUninitialize"); 130 | return 0; 131 | } 132 | 133 | /* for debugging 134 | #define ODS(s) OutputDebugString(s) 135 | 136 | static int dprintf(char *fmt, ...) 137 | { 138 | char Buffer[4096]; 139 | va_list marker; 140 | int result; 141 | 142 | va_start(marker, fmt); 143 | result = wvsprintf(Buffer, fmt, marker); 144 | OutputDebugString(Buffer); 145 | return result; 146 | } 147 | */ 148 | 149 | int check_init() 150 | { 151 | if (!have_init) { 152 | EnterCriticalSection(&csInit); 153 | // Check the flag again - another thread may have beat us to it! 154 | if (!have_init) { 155 | PyObject *frozen; 156 | /* Consider a py2exe generated COM DLL, and a py2exe 157 | generated .EXE that makes use of the COM object (both 158 | in the same distribution) 159 | 160 | When VB, for example, creates the COM object, this 161 | code has not previously loaded Python. Python is 162 | therefore not initialized, so a normal Python init 163 | routine works fine. 164 | 165 | However - consider when our .exe attempts to create 166 | the COM object. Python has already been initialized 167 | in this process (as the .exe started up), but the 168 | function pointers (eg, Py_IsInitialized) are yet to 169 | be loaded in this DLLs private data. Worse, in this 170 | case the GIL is not held, so calling 171 | init_with_instance in this state will do things like 172 | call PySys_SetObject, which will abort() as there is 173 | no thread-state. 174 | 175 | In all cases, we must exit this function with the GIL 176 | released. 177 | */ 178 | PyGILState_STATE restore_state = PyGILState_UNLOCKED; 179 | /* Before we call Python functions, we must make sure 180 | that the python dll is loaded - we are loading it 181 | at runtime now. MyGetModuleHandle() should work, 182 | but we can aso check if the functions are 183 | available. 184 | */ 185 | if (!Py_IsInitialized) { 186 | // Python function pointers are yet to be loaded 187 | // - force that now. See above for why we *must* 188 | // know about the initialized state of Python so 189 | // we can setup the thread-state correctly 190 | // before calling init_with_instance(); This is 191 | // wasteful, but fixing it would involve a 192 | // restructure of init_with_instance() 193 | _LocateScript(gInstance); 194 | _LoadPythonDLL(gInstance); 195 | } 196 | if (Py_IsInitialized && Py_IsInitialized()) { 197 | restore_state = PyGILState_Ensure(); 198 | } 199 | // a little DLL magic. Set sys.frozen='dll' 200 | init_with_instance(gInstance, "dll"); 201 | init_memimporter(); 202 | frozen = PyLong_FromVoidPtr(gInstance); 203 | if (frozen) { 204 | PySys_SetObject("frozendllhandle", frozen); 205 | Py_DECREF(frozen); 206 | } 207 | // Now run the generic script - this always returns in a DLL. 208 | run_script(); 209 | have_init = TRUE; 210 | if (gPythoncom == NULL) 211 | load_pythoncom(); 212 | // Reset the thread-state, so any thread can call in 213 | PyGILState_Release(restore_state); 214 | } 215 | LeaveCriticalSection(&csInit); 216 | } 217 | return gPythoncom != NULL; 218 | } 219 | 220 | 221 | // ***************************************************************** 222 | // All the public entry points needed for COM, Windows, and anyone 223 | // else who wants their piece of the action. 224 | // ***************************************************************** 225 | BOOL WINAPI DllMain(HINSTANCE hInstance, DWORD dwReason, LPVOID lpReserved) 226 | { 227 | if ( dwReason == DLL_PROCESS_ATTACH) { 228 | gInstance = hInstance; 229 | InitializeCriticalSection(&csInit); 230 | } 231 | else if ( dwReason == DLL_PROCESS_DETACH ) { 232 | gInstance = 0; 233 | DeleteCriticalSection(&csInit); 234 | // not much else safe to do here 235 | } 236 | return TRUE; 237 | } 238 | 239 | HRESULT __stdcall DllCanUnloadNow(void) 240 | { 241 | HRESULT rc; 242 | check_init(); 243 | assert(Pyc_DllCanUnloadNow); 244 | if (!Pyc_DllCanUnloadNow) return E_UNEXPECTED; 245 | rc = Pyc_DllCanUnloadNow(); 246 | //if (rc == S_OK && PyCom_CoUninitialize) 247 | // PyCom_CoUninitialize(); 248 | return rc; 249 | } 250 | 251 | //__declspec(dllexport) int __stdcall DllGetClassObject(void *rclsid, void *riid, void *ppv) 252 | HRESULT __stdcall DllGetClassObject(REFCLSID rclsid, REFIID riid, LPVOID *ppv) 253 | { 254 | HRESULT rc; 255 | check_init(); 256 | assert(Pyc_DllGetClassObject); 257 | if (!Pyc_DllGetClassObject) return E_UNEXPECTED; 258 | rc = Pyc_DllGetClassObject(rclsid, riid, ppv); 259 | return rc; 260 | } 261 | 262 | 263 | STDAPI DllRegisterServer() 264 | { 265 | int rc=0; 266 | PyGILState_STATE state; 267 | check_init(); 268 | state = PyGILState_Ensure(); 269 | rc = PyRun_SimpleString("DllRegisterServer()\n"); 270 | if (rc != 0) 271 | PyErr_Print(); 272 | PyGILState_Release(state); 273 | return rc==0 ? 0 : SELFREG_E_CLASS; 274 | } 275 | 276 | STDAPI DllUnregisterServer() 277 | { 278 | int rc=0; 279 | PyGILState_STATE state; 280 | check_init(); 281 | state = PyGILState_Ensure(); 282 | rc = PyRun_SimpleString("DllUnregisterServer()\n"); 283 | if (rc != 0) 284 | PyErr_Print(); 285 | PyGILState_Release(state); 286 | return rc==0 ? 0 : SELFREG_E_CLASS; 287 | } 288 | 289 | STDAPI DllInstall(BOOL install, LPCWSTR cmdline) 290 | { 291 | PyObject *m = NULL, *func = NULL, *args = NULL, *result = NULL; 292 | PyGILState_STATE state; 293 | int rc=SELFREG_E_CLASS; 294 | check_init(); 295 | state = PyGILState_Ensure(); 296 | m = PyImport_AddModule("__main__"); 297 | if (!m) goto done; 298 | func = PyObject_GetAttrString(m, "DllInstall"); 299 | if (!func) goto done; 300 | args = Py_BuildValue("(Oi)", install ? 1 : 0, cmdline); 301 | if (!args) goto done; 302 | result = PyObject_Call(func, args, NULL); 303 | if (result==NULL) goto done; 304 | rc = 0; 305 | /* but let them return a custom rc (even though we don't above!) */ 306 | if (PyInt_Check(result)) 307 | rc = PyInt_AsLong(result); 308 | else if (result == Py_None) 309 | ; /* do nothing */ 310 | else 311 | /* We cannot access internals of PyObject anymore */ 312 | PySys_WriteStderr("Unexpected return type for DllInstall\n"); 313 | // result->ob_type->tp_name); 314 | done: 315 | if (PyErr_Occurred()) { 316 | PyErr_Print(); 317 | PyErr_Clear(); 318 | } 319 | // no ref added to m 320 | Py_XDECREF(func); 321 | Py_XDECREF(args); 322 | Py_XDECREF(result); 323 | PyGILState_Release(state); 324 | return rc; 325 | } 326 | -------------------------------------------------------------------------------- /ChangeLog: -------------------------------------------------------------------------------- 1 | 2013-06-23 Thomas Heller 2 | 3 | * Updated the code with the current MemoryLoadLibrary module which 4 | will also work on 64-bit windows. 5 | 6 | 2013-05-24 Thomas Heller 7 | 8 | * properly implemented the activation context handling like it 9 | works in the python dll itself: We store the actctx, and wrap 10 | calls to MemoryLoadLibrary with _My_ActivateActCtx() and 11 | _My_DeactivateActCtx(). 12 | 13 | 14 | 2009-08-14 Thomas Heller 15 | 16 | * Fix 'DeprecationWarning: the sets module is deprecated' in Python 2.6, 17 | when building an executable. 18 | 19 | 2008-04-10 Mark Hammond 20 | 21 | * If a Python 2.5 built app was installed over a Python 2.4 built app, 22 | the app would crash as Python 2.5 loaded Python 2.4's zlib.pyd; zlib is 23 | builtin in Python 2.5 and later, so no 2.5 version of zlib.pyd exists. 24 | 25 | 2008-12-15 Mark Hammond 26 | 27 | * Fix via the mailing list to fix strange icons being displayed on Vista. 28 | 29 | 2008-11-06 Thomas Heller 30 | 31 | * Fixed a modulefinder crash on certain relative imports. 32 | 33 | 2008-11-01 Thomas Heller 34 | 35 | * Changed the py2exe\samples\singlefile\gui\test_wx.py sample to 36 | use the wx package instead of the old wxPython package. 37 | 38 | 2008-08-28 Mark Hammond 39 | 40 | * Copy the manifest, if any, from the 'template' into the targets 41 | to ensure embedded assembly references, as required for python 2.6 based 42 | apps, are copied. 43 | 44 | * Allow each target to specify Vista User Access Control flags. For 45 | example, specifying 'uac_execution_info="requireAdministrator"' would 46 | force elevation for the final executable. 47 | 48 | 2008-05-19 Jimmy Retzlaff 49 | 50 | * Bump version number to 0.6.8. 51 | 52 | * Updated test suite to be smarter about which interpreters to use 53 | for testing and to output stats. 54 | 55 | * Merged modulefinder.py r59200 from the Python svn trunk into 56 | mf.py in order to support relative imports. 57 | 58 | * Use Python 2.5 to build the source distribution. 59 | 60 | * Include the entire test suite in the source distribution. 61 | 62 | 2008-04-17 Thomas Heller 63 | 64 | * Changes to the test suite. 65 | 66 | * Fix MemoryLoadLibrary to handle loading function addresses by 67 | ordinal numbers. Patch and test by Matthias Miller - thanks! 68 | 69 | 2008-04-05 Jimmy Retzlaff 70 | 71 | * Using the options compressed=1, bundle_files=3, and zipfile=None at 72 | the same time now works; patch from Alexey Borzenkov (sf request id 73 | 1707920) 74 | 75 | 2008-04-04 Thomas Heller 76 | 77 | * py2exe\boot_ctypes_com_server.py: Port this module from 78 | ctypes.com to comtypes. Work in progress. 79 | 80 | 2008-04-01 Thomas Heller 81 | 82 | * Allow renaming of single-executable files; patch from Alexey 83 | Borzenkov (sf request id 1516099) 84 | 85 | 86 | 2008-02-29 Thomas Heller 87 | 88 | * py2exe\__init__.py: Bump version number to 0.6.7. 89 | 90 | * source\py2exe_util.c: Embedding icon resources into the image 91 | does now work correctly even for ico files containing multiple 92 | images. 93 | 94 | 2007-09-07 Thomas Heller 95 | 96 | * build_exe.py: Patch from Grant Edwards, slightly adjusted: 97 | py2exe now renames the pyd files that it copies into the dist 98 | directory so that they include the package name. This prevents 99 | name conflicts. 100 | 101 | 2007-03-26 Mark Hammond 102 | * Samples for the 'typelibs' support, including the new option of 103 | pre-generating a typelib and specifying the file as an input to py2exe 104 | 105 | 2006-12-27 Jimmy Retzlaff 106 | 107 | * boot_common.py: Handle new parameter to fake_getline in Python 2.5 108 | as suggested by Tim Tucker. 109 | 110 | 2006-11-22 Thomas Heller 111 | 112 | * py2exe does now work sort-of on win64, with a 64-bit build of 113 | Python. 114 | 115 | * On win64, complain if bundle_files < 3. This is not yet 116 | supported since the code in source\MemoryModule.c does not work on 117 | win64. 118 | 119 | * Updated the mktab.py script (which generates import-tab.c and 120 | import-tab.h) for Py_ssize_t and the definition of PyInit_Module4 121 | on win64. Regenerated import-tab.c and import-tab.h. 122 | 123 | * build_exe.py: Don't copy w9xpopen.exe if it does not exist (on a 124 | 64-bit Python installation, for example). 125 | 126 | * build_exe.py: Add gdiplus.dll to the list of excluded dlls. 127 | 128 | 2006-12-27 Jimmy Retzlaff 129 | 130 | * test: 131 | * Run all tests with and without the --compression option - this 132 | catches the problems zlib problem with Python 2.5. 133 | * Added a test case that catches the sys.path regression. 134 | 135 | 2006-10-24 Mark Hammond 136 | 137 | * start.c: 138 | * Add calc_dirname() which calculates the dirname global, and call this 139 | from _InitPython, so _InitPython can be called externally before 140 | init_with_instance 141 | * My most recent checkin did not update sys.frozen to the new value if 142 | Python was already initialized. Although that is all nasty hackery, 143 | it now works as before (ie, sys.frozen is set to the new value) 144 | 145 | * run_isapi.c: 146 | * Load Python before the ISAPI extension module, as that module itself 147 | depends on Python. 148 | * Write an event log error when the ISAPI module failed to load. 149 | 150 | 2006-10-18 Mark Hammond 151 | 152 | * boot_com_servers.py: 153 | 154 | * zipextimporter.py: Py2.5 doesn't recognize .dll as a module; 155 | pywintypes/pythoncom now get specital treatment 156 | 157 | * start.c: If Python is already initialized, assume we have struck 2 158 | pyexe DLLs in the same process, and adjust sys.path accordingly. 159 | Its kinda lame, but will work if everyone magically happens to use 160 | the same version. 161 | 162 | * run_isapi.c: Replace MessageBox (which will hang an ISAPI app) with 163 | an event-log entry. Entry is pretty lame; there are no message 164 | resources in py2exe apps. 165 | 166 | 2006-07-02 Mark Hammond 167 | 168 | * New isapi and com_server samples 169 | 170 | 2006-06-29 Mark Hammond 171 | 172 | * py2exe.txt: Add notes re service cmdline handling. 173 | 174 | * Python-dynload.c: Before doing a LoadLibrary for the Python DLL, 175 | ensure it isn't already in memory. This gets the ISAPI stuff working 176 | again. 177 | 178 | 2006-06-20 Mark Hammond 179 | 180 | * boot_service.py: Support more 'command-line styles' for services 181 | (allowing 'pywin32' meaning the same as pywin32 itself, and 'custom' 182 | meaning the cmdline handler must be provided) and allow the user to 183 | select it via the 'cmdline_style' option. 184 | 185 | 2006-02-13 Jimmy Retzlaff 186 | 187 | * py2exe 0.6.4 released. 188 | 189 | * Changed bundle-files=4 option to be the skip-archive option. 190 | bundle-files is really about DLLs, not bytecode files. 191 | 192 | * Added experimental new custom-boot-script option which allows a 193 | boot script to be specified which can do things like installing 194 | a customized stdout blackhole. The custom boot script is executed 195 | during startup of the executable immediately after boot_common.py 196 | is executed. 197 | 198 | 2005-12-10 Jimmy Retzlaff 199 | 200 | * Apply a patch from Antony Kummel adding a more elaborate 201 | explanation for the motivation behind the special handling of 202 | stdout/stderr in windows (as opposed to console) applications. 203 | 204 | * Locate extension modules relative to the archive's location 205 | when an archive is used. 206 | 207 | * Add bundle-files=4 option which copies the .pyo files directly 208 | into the dist directory and subdirectories - no archive is used. 209 | 210 | * Performance improvements for mf.py from Thomas Heller. 211 | 212 | 2005-10-06 Jimmy Retzlaff 213 | 214 | * py2exe 0.6.3 released. 215 | 216 | * Added build.cmd that builds files for release. 217 | 218 | * Added Jimmy Retzlaff as maintainer and changed website pointers 219 | to http://www.py2exe.org/. 220 | 221 | 2005-09-09 Thomas Heller 222 | 223 | * py2exe\build_exe.py (py2exe.copy_extensions): Make the 224 | dll-excludes option available on the command line - it was only 225 | possible to specify that in the options argument to the setup 226 | function before. 227 | The dll-excludes list can now be used to filter out dlls like 228 | msvcr71.dll or even the w9xpopen.exe. 229 | 230 | (py2exe.copy_extensions): Fix from Gordon Scott, py2exe crashed 231 | copying extension modules in packages. 232 | 233 | 234 | 2005-09-07 Thomas Heller 235 | 236 | * py2exe 0.6.2 released. 237 | 238 | * MANIFEST.in: The source archive was not complete. 239 | 240 | * MemoryModule.c: Fixed a bug which loaded dlls more than once, 241 | with very strange effects. 242 | 243 | * Special handling of MSVCR71.dll and MSVCR71D.dll - they are now 244 | copied into the dist directory if needed. Note that Microsoft 245 | explicitely states that MSVCR71D.dll - the debug version - is NOT 246 | REDISTRIBUTABLE! 247 | 248 | * Use w9xpopen_d.exe in a debug build. Handle the release and the 249 | debug version of MSVCR71 in the same way. 250 | 251 | * Fix the definition of Py_InitModule4 in the import table. This 252 | allows to build a debug version of py2exe. 253 | 254 | 2005-09-06 Thomas Heller 255 | 256 | * Fix the import of extensions in packages. This made newer 257 | versions of wxPython (for example) fail. 258 | 259 | 2005-09-05 Thomas Heller 260 | 261 | * py2exe 0.6.1 released. 262 | 263 | * docs\py2exe.txt: Updated the html-pages. 264 | 265 | 2005-04-28 Thomas Heller 266 | 267 | * py2exe can now bundle binary extensions and dlls into the zip 268 | archive, and load them with a custom zipextimporter. This uses 269 | code originally written by Joachim Bauch and enhanced by me, which 270 | simulates the LoadLibrary windows api call. The exe stubs now use 271 | runtime dynamic loading of the Python dll. 272 | 273 | * py2exe does now by default include the codecs module and the 274 | complete encodings package. 275 | 276 | * py2exe\boot_service.py: Patch from Cory Dodt to allow building a 277 | service from a module inside a package. 278 | 279 | * py2exe\build_exe.py (py2exe.find_needed_modules): Another patch 280 | from Shane Holloway to handle packages with multiple entries in a 281 | package's __path__ list. 282 | 283 | 2004-12-30 Thomas Heller 284 | 285 | * py2exe\build_exe.py (py2exe.find_needed_modules.visit): Patch 286 | from Shane Holloway for better modulefinder's AddPackagePath 287 | interactions. 288 | 289 | * source\start.c: Patch from David Bolen, to make the unbuffered 290 | option work. 291 | 292 | 2004-10-22 Thomas Heller 293 | 294 | * py2exe can now create module crosss references in HTML format, 295 | and displays them in the default browser. 296 | 297 | 2004-09-22 Thomas Heller 298 | 299 | * py2exe\build_exe.py: Added the .pyw extension for Python modules. 300 | 301 | 2004-09-06 Mark Hammond 302 | 303 | * Support for stand-alone ISAPI DLL. 304 | 305 | 2004-06-02 Mark Hammond 306 | 2004-08-24 Mark Hammond 307 | 308 | * Various 'thread-state' issues in COM DLL support. 309 | 310 | 2004-07-30 Thomas Heller 311 | 312 | * py2exe\build_exe.py: zipfile can now be specified as None, in 313 | this case the Python modules library archive is appended to the 314 | exe-files created. Doesn't make too much sense in the normal case 315 | probably, but prepares the way to single file executables. 316 | 317 | 2004-07-29 Thomas Heller 318 | 319 | * py2exe\build_exe.py: When using static built 320 | templates, python.dll may not be needed anymore. 321 | 322 | 2004-07-23 Thomas Heller 323 | 324 | * (Message): py2exe 0.5.3 released. 325 | 326 | 2004-07-13 Thomas Heller 327 | 328 | * source\run_dll.c: From Mark Hammond: patch to correctly manage 329 | the thread state. 330 | 331 | * py2exe\build_exe.py (py2exe.build_executable): Add a line feed 332 | to the script's code, to avoid problems compiling it when it 333 | contains trailing white space. 334 | 335 | * py2exe\build_exe.py: Fix a problem with 2.4 when no extension 336 | modules are needed - py2exe didn't track that python24.dll is 337 | needed. Add the '_emx_link' symbol to the ignored imports list. 338 | 339 | 2004-07-09 Thomas Heller 340 | 341 | * (Message): py2exe 0.5.2 released. 342 | 343 | * source\run_dll.c: I took out again Mark's threadstate patch, it 344 | breaks registering dll COM servers. 345 | 346 | 2004-07-08 Thomas Heller 347 | 348 | * (Message): py2exe 0.5.1 released. 349 | 350 | 2004-06-09 Thomas Heller 351 | 352 | * source\start.c (run_script): Return an exit code of 255 when 353 | there's an uncatched exception in the main script. 354 | 355 | 2004-06-08 Thomas Heller 356 | 357 | * py2exe\boot_service.py: Register service dependencies when a 358 | service is started with the -install flag. 359 | 360 | * source\start.c (run_script): Triple-quote sys.path with double 361 | quotes to avoid problems if the directory contains single quotes 362 | (double quotes are impossible on Windows). 363 | 364 | * py2exe\build_exe.py: Support for precompiled .pyc and .pyo 365 | files, based on a patch from Shane Holloway. 366 | 367 | 2004-06-02 Thomas Heller 368 | 369 | * source\run_dll.c: From Mark Hammond: patch to correctly manage 370 | the thread state. 371 | 372 | 2004-06-01 Thomas Heller 373 | 374 | * setup.py, source/icon.rc: Change so that py2exe can be built 375 | with mingw32. 376 | 377 | 2004-04-28 Thomas Heller 378 | 379 | * py2exe\build_exe.py: Run the 'build' command before actually 380 | building the exe, and insert the lib and plat_lib directories to 381 | sys.path. After the exe is built, sys.path is restored. 382 | 383 | http://sourceforge.net/tracker/?func=detail&atid=115583&aid=911596&group_id=15583 384 | 385 | 2004-04-27 Thomas Heller 386 | 387 | * py2exe\build_exe.py: Fix ModuleFinders import_module() method, 388 | see http://python.org/sf/876278. I assume the fix will it make 389 | into Python 2.4, but not earlier versions. 390 | 391 | 2004-04-26 Thomas Heller 392 | 393 | * (Message): Add flush() methods to the Blackhole and Stderr 394 | objects for windows programs. 395 | 396 | 397 | 2004-04-18 Mark Hammond 398 | 399 | * (build_exe.py): Patch sys.winver in the distributed 400 | pythonxx.dll, so that there is no possibility of conflicts with 401 | existing distributions and the registry keys found there. Of 402 | note, ActivePython/old win32all versions registered 'Modules', and 403 | these were used in preference to the one shipped with py2exe, 404 | generally causing problem. 405 | 406 | 2004-04-07 Thomas Heller 407 | 408 | * (EXCLUDED_DLLS): Readded the builtin list of system dlls to 409 | exclude. 410 | 411 | 2004-03-23 Thomas Heller 412 | 413 | * source\py2exe_util.c: The code was calling CreateFileW directly 414 | instead of the function in unicows.dll, this had the effect that 415 | the icons could not be changed on Win98. 416 | 417 | 2004-03-12 Thomas Heller 418 | 419 | * py2exe\resources\VersionInfo.py: Version resource built by 420 | py2exe was wrong: found by Roger Upole, reported on c.l.p 421 | 422 | 2004-03-02 Thomas Heller 423 | 424 | * py2exe\boot_service.py: Print a message when a service exe is 425 | started from the command line. 426 | 427 | * py2exe\build_exe.py: makepy code generation with bForDemand=True is buggy. 428 | Use bForDemand=False instead. 429 | 430 | 431 | 2004-02-17 Thomas Heller 432 | 433 | * source\start.c (init_with_instance): Fixed a bufferoverflow when 434 | the exe is run in a directory with a long name, found by Ralf Sieger. 435 | http://sourceforge.net/tracker/index.php?func=detail&aid=893310&group_id=15583&atid=115583 436 | 437 | * py2exe\boot_common.py: Fix two problems found by Mathew 438 | Thornley: Could not open the logfile because the 'sys' symbol was 439 | no longer defined. Wrong wording when the logfile could not be 440 | opened. 441 | http://sourceforge.net/tracker/index.php?func=detail&aid=887856&group_id=15583&atid=115583 442 | http://sourceforge.net/tracker/index.php?func=detail&aid=887855&group_id=15583&atid=115583 443 | 444 | -------------------------------------------------------------------------------- /source/start.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2000, 2001 Thomas Heller 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining 5 | * a copy of this software and associated documentation files (the 6 | * "Software"), to deal in the Software without restriction, including 7 | * without limitation the rights to use, copy, modify, merge, publish, 8 | * distribute, sublicense, and/or sell copies of the Software, and to 9 | * permit persons to whom the Software is furnished to do so, subject to 10 | * the following conditions: 11 | * 12 | * The above copyright notice and this permission notice shall be 13 | * included in all copies or substantial portions of the Software. 14 | * 15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 16 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 17 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 18 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 19 | * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 20 | * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 21 | * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 22 | */ 23 | 24 | /* 25 | * $Id: start.c 651 2008-04-05 11:26:42Z jretz $ 26 | * 27 | */ 28 | 29 | /* 30 | #include 31 | #include 32 | #include 33 | #include 34 | */ 35 | #include "Python-dynload.h" 36 | #include 37 | #include 38 | #include "MemoryModule.h" 39 | 40 | #pragma comment(lib, "Shell32.lib") 41 | 42 | #if defined(MS_WINDOWS) || defined(__CYGWIN__) 43 | #include 44 | #endif 45 | 46 | struct scriptinfo { 47 | int tag; 48 | int optimize; 49 | int unbuffered; 50 | int data_bytes; 51 | 52 | char zippath[0]; 53 | }; 54 | 55 | extern void SystemError(int error, char *msg); 56 | int run_script(void); 57 | void fini(void); 58 | char *pScript; 59 | char *pZipBaseName; 60 | int numScriptBytes; 61 | char modulename[_MAX_PATH + _MAX_FNAME + _MAX_EXT]; // from GetModuleName() 62 | char dirname[_MAX_PATH]; // directory part of GetModuleName() 63 | char libdirname[_MAX_PATH]; // library directory - probably same as above. 64 | char libfilename[_MAX_PATH + _MAX_FNAME + _MAX_EXT]; // library filename 65 | struct scriptinfo *p_script_info; 66 | 67 | 68 | /* 69 | static int dprintf(char *fmt, ...) 70 | { 71 | char Buffer[4096]; 72 | va_list marker; 73 | int result; 74 | 75 | va_start(marker, fmt); 76 | result = vsprintf(Buffer, fmt, marker); 77 | OutputDebugString(Buffer); 78 | return result; 79 | } 80 | */ 81 | 82 | BOOL calc_dirname(HMODULE hmod) 83 | { 84 | int is_special; 85 | wchar_t* module_namew = (wchar_t*)malloc(sizeof(wchar_t)*sizeof(modulename)); 86 | char *modulename_start; 87 | char *cp; 88 | 89 | int parse; 90 | wchar_t *currdir = (wchar_t*)malloc(sizeof(wchar_t)*1024); 91 | 92 | // get module filename 93 | if (!GetModuleFileNameW(hmod, module_namew, sizeof(modulename))) { 94 | SystemError(GetLastError(), "Retrieving module name"); 95 | return FALSE; 96 | } 97 | 98 | //set working directory 99 | wcscpy(currdir, module_namew); 100 | parse = wcslen(currdir) -1; 101 | while(parse>0) 102 | { 103 | if(currdir[parse]==L'\\') 104 | { 105 | currdir[parse] = 0; 106 | break; 107 | } 108 | 109 | parse--; 110 | } 111 | 112 | SetCurrentDirectoryW(currdir); 113 | free(currdir); 114 | 115 | WideCharToMultiByte(CP_UTF8, 0, module_namew, -1, modulename, sizeof(modulename), 0, 0); 116 | free(module_namew); 117 | 118 | 119 | // get directory of modulename. Note that in some cases 120 | // (eg, ISAPI), GetModuleFileName may return a leading "\\?\" 121 | // (which is a special format you can pass to the Unicode API 122 | // to avoid MAX_PATH limitations). Python currently can't understand 123 | // such names, and as it uses the ANSI API, neither does Windows! 124 | // So fix that up here. 125 | is_special = strlen(modulename) > 4 && 126 | strncmp(modulename, "\\\\?\\", 4)==0; 127 | modulename_start = is_special ? modulename + 4 : modulename; 128 | strcpy(dirname, modulename_start); 129 | cp = strrchr(dirname, '\\'); 130 | *cp = '\0'; 131 | return TRUE; 132 | } 133 | 134 | BOOL _LocateScript(HMODULE hmod) 135 | { 136 | HRSRC hrsrc = FindResource(hmod, MAKEINTRESOURCE(1), "PYTHONSCRIPT"); 137 | HGLOBAL hgbl; 138 | 139 | if (!dirname[0]) 140 | calc_dirname(hmod); 141 | 142 | // load the script resource 143 | if (!hrsrc) { 144 | SystemError(GetLastError(), "Could not locate script resource:"); 145 | return FALSE; 146 | } 147 | hgbl = LoadResource(hmod, hrsrc); 148 | if (!hgbl) { 149 | SystemError(GetLastError(), "Could not load script resource:"); 150 | return FALSE; 151 | } 152 | p_script_info = (struct scriptinfo *)pScript = LockResource(hgbl); 153 | if (!pScript) { 154 | SystemError(GetLastError(), "Could not lock script resource:"); 155 | return FALSE; 156 | } 157 | // validate script resource 158 | numScriptBytes = p_script_info->data_bytes; 159 | pScript += sizeof(struct scriptinfo); 160 | if (p_script_info->tag != 0x78563412) { 161 | SystemError (0, "Bug: Invalid script resource"); 162 | return FALSE; 163 | } 164 | // let pScript point to the start of the python script resource 165 | pScript += strlen(p_script_info->zippath) + 1; 166 | 167 | // get full pathname of the 'library.zip' file 168 | if(p_script_info->zippath[0]) { 169 | snprintf(libfilename, sizeof(libfilename), 170 | "%s\\%s", dirname, p_script_info->zippath); 171 | } else { 172 | wchar_t *libfilenamew = (wchar_t*)malloc(sizeof(wchar_t)*sizeof(libfilename)); 173 | GetModuleFileNameW(hmod, libfilenamew, sizeof(libfilename)); 174 | WideCharToMultiByte(CP_UTF8, 0, libfilenamew, -1, libfilename, sizeof(libfilename), 0, 0); 175 | free(libfilenamew); 176 | } 177 | return TRUE; // success 178 | } 179 | 180 | static char *MapExistingFile(char *pathname, DWORD *psize) 181 | { 182 | HANDLE hFile, hFileMapping; 183 | DWORD nSizeLow, nSizeHigh; 184 | char *data; 185 | 186 | wchar_t *pathnamew = (wchar_t*)malloc(sizeof(wchar_t)*(strlen(pathname)+1)); 187 | MultiByteToWideChar(CP_UTF8, 0, pathname, -1, pathnamew, strlen(pathname)+1); 188 | 189 | hFile = CreateFileW(pathnamew, 190 | GENERIC_READ, FILE_SHARE_READ, NULL, 191 | OPEN_EXISTING, 192 | FILE_ATTRIBUTE_NORMAL, NULL); 193 | free(pathnamew); 194 | 195 | if (hFile == INVALID_HANDLE_VALUE) 196 | return NULL; 197 | nSizeLow = GetFileSize(hFile, &nSizeHigh); 198 | hFileMapping = CreateFileMapping(hFile, 199 | NULL, PAGE_READONLY, 0, 0, NULL); 200 | CloseHandle(hFile); 201 | 202 | if (hFileMapping == INVALID_HANDLE_VALUE) 203 | return NULL; 204 | 205 | data = MapViewOfFile(hFileMapping, 206 | FILE_MAP_READ, 0, 0, 0); 207 | 208 | CloseHandle(hFileMapping); 209 | if (psize) 210 | *psize = nSizeLow; 211 | return data; 212 | } 213 | 214 | BOOL _LoadPythonDLL(HMODULE hmod) 215 | { 216 | HRSRC hrsrc; 217 | char *pBaseAddress; 218 | int size, a; 219 | 220 | if (!dirname[0]) 221 | calc_dirname(hmod); 222 | 223 | // Try to locate pythonxy.dll as resource in the exe 224 | hrsrc = FindResource(hmod, MAKEINTRESOURCE(1), PYTHONDLL); 225 | if (hrsrc) { 226 | HGLOBAL hgbl = LoadResource(hmod, hrsrc); 227 | if (!_load_python(PYTHONDLL, LockResource(hgbl))) { 228 | SystemError(GetLastError(), "Could not load python dll"); 229 | return FALSE; 230 | } 231 | // dprintf("Loaded pythondll as RESOURCE\n"); 232 | return TRUE; 233 | } 234 | 235 | // try to load pythonxy.dll as bytes at the start of the zipfile 236 | pBaseAddress = MapExistingFile(libfilename, &size); 237 | if (pBaseAddress) { 238 | int res = 0; 239 | if (0 == strncmp(pBaseAddress, "", 11)) 240 | res = _load_python(PYTHONDLL, pBaseAddress + 11 + sizeof(int)); 241 | UnmapViewOfFile(pBaseAddress); 242 | if (res) { 243 | // dprintf("Loaded pythondll as from %s\n", libfilename); 244 | return TRUE; 245 | } 246 | } 247 | 248 | // try to load pythonxy.dll from the file system 249 | { 250 | char buffer[_MAX_PATH + _MAX_FNAME + _MAX_EXT]; 251 | snprintf(buffer, sizeof(buffer), "%s\\%s", dirname, PYTHONDLL); 252 | 253 | if (!_load_python(buffer, NULL)) { 254 | SystemError(GetLastError(), "LoadLibrary(pythondll) failed"); 255 | return FALSE; 256 | } 257 | // dprintf("Loaded pythondll from file %s\n", buffer); 258 | } 259 | return TRUE; 260 | } 261 | 262 | void _Import_Zlib(char *pdata) 263 | { 264 | HMODULE hlib; 265 | hlib = MemoryLoadLibrary("zlib.pyd", pdata); 266 | if (hlib) { 267 | void (*proc)(void); 268 | proc = (void(*)(void))MemoryGetProcAddress(hlib, "initzlib"); 269 | if (proc) 270 | proc(); 271 | } 272 | } 273 | 274 | void _TryLoadZlib(HMODULE hmod) 275 | { 276 | char *pBaseAddress; 277 | char *pdata; 278 | wchar_t* bufferw; 279 | HRSRC hrsrc; 280 | 281 | // Try to locate pythonxy.dll as resource in the exe 282 | hrsrc = FindResource(hmod, MAKEINTRESOURCE(1), "ZLIB.PYD"); 283 | if (hrsrc) { 284 | HGLOBAL hglb = LoadResource(hmod, hrsrc); 285 | if (hglb) { 286 | _Import_Zlib(LockResource(hglb)); 287 | } 288 | return; 289 | } 290 | 291 | // try to load zlib.pyd from the file system 292 | { 293 | HMODULE hlib; 294 | char buffer[_MAX_PATH + _MAX_FNAME + _MAX_EXT]; 295 | snprintf(buffer, sizeof(buffer), "%s\\%s", dirname, "zlib.pyd"); 296 | 297 | //goatpig's change: resolve utf8 to utf16, feed to W function 298 | bufferw = (wchar_t*)malloc(sizeof(wchar_t)*(strlen(buffer)+1)); 299 | MultiByteToWideChar(CP_UTF8, 0, buffer, -1, bufferw, strlen(buffer)+1); 300 | hlib = LoadLibraryW(bufferw); 301 | free(bufferw); 302 | 303 | if(hlib) { 304 | void (*proc)(void); 305 | proc = (void(*)(void))GetProcAddress(hlib, "initzlib"); 306 | if(proc) { 307 | proc(); 308 | return; 309 | } 310 | } 311 | } 312 | 313 | // try to load zlib.pyd as bytes at the start of the zipfile 314 | pdata = pBaseAddress = MapExistingFile(libfilename, NULL); 315 | if (pBaseAddress) { 316 | if (0 == strncmp(pBaseAddress, "", 11)) { 317 | pdata += 11; 318 | pdata += *(int *)pdata + sizeof(int); 319 | } 320 | if (0 == strncmp(pdata, "", 10)) { 321 | pdata += 10 + sizeof(int); 322 | _Import_Zlib(pdata); 323 | } 324 | UnmapViewOfFile(pBaseAddress); 325 | } 326 | } 327 | 328 | static void calc_path() 329 | { 330 | /* If the zip path has any path component, then build our Python 331 | home directory from that. 332 | */ 333 | char *fname; 334 | wchar_t *fnamew; 335 | wchar_t *libdirnamew; 336 | wchar_t *libdirnamewout; 337 | 338 | size_t lib_dir_len; 339 | pZipBaseName = libfilename + strlen(libfilename); 340 | /* let pZipBaseName point to the basename of the zippath */ 341 | while (pZipBaseName > libfilename && \ 342 | *(pZipBaseName-1) != '\\') 343 | pZipBaseName--; 344 | 345 | /* length of lib director name */ 346 | lib_dir_len = pZipBaseName-libfilename; /* incl. tail slash */ 347 | if (lib_dir_len) { 348 | char *p = libdirname; 349 | strncpy(p, libfilename, lib_dir_len-1); 350 | p += lib_dir_len-1; 351 | *p++ = '\0'; 352 | } else { 353 | libdirname[0] = '\0'; 354 | } 355 | /* Fully-qualify it */ 356 | libdirnamew = (wchar_t*)malloc(sizeof(libdirname)*sizeof(wchar_t)); 357 | libdirnamewout = (wchar_t*)malloc(sizeof(libdirname)*sizeof(wchar_t)); 358 | 359 | MultiByteToWideChar(CP_UTF8, 0, libdirname, -1, libdirnamew, sizeof(libdirname)); 360 | GetFullPathNameW(libdirnamew, sizeof(libdirname), libdirnamewout, fnamew); 361 | WideCharToMultiByte(CP_UTF8, 0, libdirnamewout, -1, libdirname, sizeof(libdirname), 0, 0); 362 | free(libdirnamew); 363 | free(libdirnamewout); 364 | } 365 | 366 | // Set the Python path before initialization 367 | static int set_path_early() 368 | { 369 | char *ppath; 370 | 371 | Py_SetPythonHome("."); 372 | /* Let Python calculate its initial path, according to the 373 | builtin rules */ 374 | ppath = Py_GetPath(); 375 | // printf("Initial path: %s\n", ppath); 376 | 377 | /* We know that Py_GetPath points to writeable memory, 378 | so we copy our own path into it. 379 | */ 380 | if (strlen(ppath) <= strlen(libdirname) + strlen(pZipBaseName) + 1) { 381 | /* Um. Not enough space. What now? */ 382 | SystemError(0, "Not enough space for new sys.path"); 383 | return -1; 384 | } 385 | 386 | strcpy(ppath, "."); 387 | strcat(ppath, "\\"); 388 | strcat(ppath, pZipBaseName); 389 | strcat(ppath, ";."); 390 | /*** 391 | added '.' to the python paths so that it can locate the libraries. 392 | ***/ 393 | 394 | return 0; 395 | } 396 | 397 | // Set the Python path after initialization 398 | static int set_path_late() 399 | { 400 | size_t buflen = strlen(libdirname) + strlen(pZipBaseName) + 2; 401 | char *ppath = (char *)malloc(buflen); 402 | PyObject *syspath, *newEntry; 403 | if (!ppath) { 404 | SystemError(ERROR_NOT_ENOUGH_MEMORY, "no mem for late sys.path"); 405 | return -1; 406 | } 407 | strcpy(ppath, "."); 408 | strcat(ppath, "\\"); 409 | strcat(ppath, pZipBaseName); 410 | strcat(ppath, ";."); 411 | syspath = PySys_GetObject("path"); 412 | newEntry = PyString_FromString(ppath); 413 | if (newEntry) { 414 | PyList_Append(syspath, newEntry); 415 | Py_DECREF(newEntry); 416 | } 417 | free(ppath); 418 | return 0; 419 | } 420 | 421 | 422 | /* 423 | * returns an error code if initialization fails 424 | */ 425 | int init_with_instance(HMODULE hmod, char *frozen) 426 | { 427 | int rc; 428 | if (!_LocateScript(hmod)) 429 | return 255; 430 | 431 | if (!_LoadPythonDLL(hmod)) 432 | return 255; 433 | if (p_script_info->unbuffered) { 434 | #if defined(MS_WINDOWS) || defined(__CYGWIN__) 435 | _setmode(fileno(stdin), O_BINARY); 436 | _setmode(fileno(stdout), O_BINARY); 437 | #endif 438 | #ifdef HAVE_SETVBUF 439 | setvbuf(stdin, (char *)NULL, _IONBF, BUFSIZ); 440 | setvbuf(stdout, (char *)NULL, _IONBF, BUFSIZ); 441 | setvbuf(stderr, (char *)NULL, _IONBF, BUFSIZ); 442 | #else /* !HAVE_SETVBUF */ 443 | setbuf(stdin, (char *)NULL); 444 | setbuf(stdout, (char *)NULL); 445 | setbuf(stderr, (char *)NULL); 446 | #endif /* !HAVE_SETVBUF */ 447 | } 448 | 449 | if (getenv("PY2EXE_VERBOSE")) 450 | Py_VerboseFlag = atoi(getenv("PY2EXE_VERBOSE")); 451 | else 452 | Py_VerboseFlag = 0; 453 | 454 | Py_IgnoreEnvironmentFlag = 1; 455 | Py_NoSiteFlag = 1; 456 | Py_OptimizeFlag = p_script_info->optimize; 457 | 458 | Py_SetProgramName(modulename); 459 | 460 | calc_path(); 461 | 462 | if (!Py_IsInitialized()) { 463 | // First time round and the usual case - set sys.path 464 | // statically. 465 | rc = set_path_early(); 466 | if (rc != 0) 467 | return rc; 468 | 469 | // printf("Path before Py_Initialize(): %s\n", Py_GetPath()); 470 | Py_Initialize(); 471 | // printf("Path after Py_Initialize(): %s\n", PyString_AsString(PyObject_Str(PySys_GetObject("path")))); 472 | } else { 473 | // Python already initialized. This likely means there are 474 | // 2 py2exe based apps in the same process (eg, 2 COM objects 475 | // in a single host, 2 ISAPI filters in the same site, ...) 476 | // Until we get a better answer, add what we need to sys.path 477 | rc = set_path_late(); 478 | if (rc != 0) 479 | return rc; 480 | } 481 | /* Set sys.frozen so apps that care can tell. 482 | If the caller did pass NULL, sys.frozen will be set zo True. 483 | If a string is passed this is used as the frozen attribute. 484 | run.c passes "console_exe", run_w.c passes "windows_exe", 485 | run_dll.c passes "dll" 486 | This falls apart when you consider that in some cases, a single 487 | process may end up with two py2exe generated apps - but still, we 488 | reset frozen to the correct 'current' value for the newly 489 | initializing app. 490 | */ 491 | if (frozen == NULL) 492 | PySys_SetObject("frozen", PyBool_FromLong(1)); 493 | else { 494 | PyObject *o = PyString_FromString(frozen); 495 | if (o) { 496 | PySys_SetObject("frozen", o); 497 | Py_DECREF(o); 498 | } 499 | } 500 | 501 | _TryLoadZlib(hmod); 502 | 503 | return 0; 504 | } 505 | 506 | int init(char *frozen) 507 | { 508 | return init_with_instance(NULL, frozen); 509 | } 510 | 511 | void fini(void) 512 | { 513 | /* The standard Python 2.3 does also allow this: Set PYTHONINSPECT 514 | in the script and examine it afterwards 515 | */ 516 | if (getenv("PYTHONINSPECT") && Py_FdIsInteractive(stdin, "")) 517 | PyRun_InteractiveLoop(stdin, ""); 518 | /* Clean up */ 519 | Py_Finalize(); 520 | } 521 | 522 | int start (int argc, char **argv) 523 | { 524 | int rc, nargs, i; 525 | PyObject *new_path; 526 | 527 | char **args; 528 | 529 | wchar_t* warg_str = GetCommandLineW(); 530 | wchar_t** warg_v = CommandLineToArgvW(warg_str, &nargs); 531 | 532 | args = (char**)malloc(sizeof(char*)*nargs); 533 | for(i=0; istrlen(args[0])) 541 | args[0] = (char*)realloc(args[0], strlen(modulename) +1); 542 | 543 | strcpy(args[0], modulename); 544 | PySys_SetArgv(nargs, args); 545 | 546 | for(i=0; i`` or ``-b `` command line switch 172 | instructs py2exe to bundle needed dlls and pyds into the library file 173 | or the executable itself, instead of simply collecting them in the 174 | dist directory. Not only does this create less files you have to 175 | distribute, it also allows Python inprocess COM servers to run 176 | completely isolated from other Python interpreters in the same 177 | process. See below for more details. 178 | 179 | - To prevent unicode encoding error, py2exe now by default includes the 180 | ``codecs`` module and the ``encodings`` package. If you are sure your 181 | program never implicitely or explicitely has to convert between 182 | unicode and ascii strings this can be prevented by the ``--ascii`` or 183 | ``-a`` command line switch. 184 | 185 | - It is no longer required to clean the build directory from time to 186 | time to prevent some strange errors. 187 | 188 | - Several patches have been integrated (if you miss a patch you sent me, 189 | please send it again. It can be that I missed some mails). 190 | 191 | The announcement_, and the ChangeLog_. 192 | 193 | Some comments about py2exe 0.5, still valid for 0.6 194 | --------------------------------------------------- 195 | 196 | The documentation is still to be written, but there is quite some info 197 | available in the included samples, and in the WIKI_ pages. Thanks to 198 | everyone who contributed. 199 | 200 | Python 2.3 or 2.4 is required, because the new zipimport feature is 201 | used. The zipimport mechanism is able to handle the early imports of 202 | the warnings and also the encodings module which is done by Python. 203 | 204 | 205 | Using py2exe 206 | ------------ 207 | 208 | Assuming you have written a python script ``myscript.py`` which you 209 | want to convert into an executable windows program, able to run on 210 | systems without a python installation. If you don't already have 211 | written a *distutils* setup-script_, write one, and insert the 212 | statement ``import py2exe`` before the call to the setup function:: 213 | 214 | # setup.py 215 | from distutils.core import setup 216 | import py2exe 217 | 218 | setup(console=["myscript.py"]) 219 | 220 | Running :: 221 | 222 | python setup.py py2exe --help 223 | 224 | will display all available command-line flags to the **py2exe** 225 | command. 226 | 227 | Now you can call the setup script like in this way:: 228 | 229 | python setup.py py2exe 230 | 231 | and a subdirectory ``dist`` will be created, containing the files 232 | ``myscript.exe``, ``python23.dll``, and ``library.zip``. If your script 233 | uses compiled C extension modules, they will be copied here as well, 234 | also all dlls needed at runtime (except the system dlls). 235 | 236 | These files include everything that is needed for your program, and 237 | you should distribute the whole directory contents. 238 | 239 | The above setup script creates a console program, if you want a GUI 240 | program without the console window, simply replace 241 | ``console=["myscript.py"]`` with ``windows=["myscript.py"]``. 242 | 243 | **py2exe** can create more than one exe file in one run, this is 244 | useful if you have a couple of related scripts. Pass a list of all 245 | scripts in the ``console`` and/or ``windows`` keyword argument. 246 | 247 | Specifying additional files 248 | --------------------------- 249 | 250 | Some applications need additional files at runtime, like configuration 251 | files, fonts, or bitmaps. 252 | 253 | **py2exe** can copy these files into subdirectories of ``dist`` if they 254 | are specified in the setup script with the ``data_files`` 255 | option. ``data_files`` should contain a sequence of ``(target-dir, 256 | files)`` tuples, where files is a sequence of files to be copied. 257 | 258 | Here's an example:: 259 | 260 | # setup.py 261 | from distutils.core import setup 262 | import glob 263 | import py2exe 264 | 265 | setup(console=["myscript.py"], 266 | data_files=[("bitmaps", 267 | ["bm/large.gif", "bm/small.gif"]), 268 | ("fonts", 269 | glob.glob("fonts\\*.fnt"))], 270 | ) 271 | 272 | 273 | This would create a subdirectory ``dist\bitmaps``, containing the two 274 | ``.gif`` files, and a subdirectory ``dist\fonts``, containing all the 275 | ``.fnt`` files. 276 | 277 | Windows NT services 278 | ------------------- 279 | 280 | You can build Windows NT services by passing a ``service`` keyword 281 | argument to the ``setup`` function, the value must be a list of Python 282 | module names containing a service class (identified by the ``_svc_name_`` 283 | attribute):: 284 | 285 | # setup.py 286 | from distutils.core import setup 287 | import py2exe 288 | 289 | setup(service=["MyService"]) 290 | 291 | Optionally, you can specify a 'cmdline-style' attribute to py2exe, with 292 | valid values being 'py2exe' (the default), 'pywin32' or 'custom'. 'py2exe' 293 | specifies the traditional command-line always supported by py2exe. 'pywin32' 294 | supports the exact same command-line arguments as pywin32 supports (ie, the 295 | same arguments supported when running the service from the .py file.) 296 | 'custom' means that your module is expected to provide a 'HandleCommandLine' 297 | function which is responsible for all command-line handling. 298 | 299 | The built service executables are able to install and remove 300 | themselves by calling them with certain command line flags, run the 301 | exe with the ``-help`` argument to find out more. 302 | 303 | COM servers 304 | ----------- 305 | 306 | COM servers are built by passing a ``com_server`` keyword argument to 307 | the setup function, again the value must be a list of Python module 308 | names containing one or more COM server classes (identified by their 309 | ``_reg_progid_`` attribute):: 310 | 311 | # setup.py 312 | from distutils.core import setup 313 | import py2exe 314 | 315 | setup(com_server=["win32com.server.interp"]) 316 | 317 | By default both DLL and EXE servers are built, you should simply 318 | delete those you don't need. 319 | 320 | The bundle option 321 | ----------------- 322 | 323 | By default py2exe creates these files in the ``dist`` directory which 324 | you must deploy: 325 | 326 | 1. One (or more) .exe files 327 | 328 | 2. The python##.dll 329 | 330 | 3. A couple of .pyd files which are the compiled extensions that the 331 | exe files need, plus any other .dll files that the extensions need. 332 | 333 | 4. A ``library.zip`` file which contains the compiled pure python 334 | modules as .pyc or .pyo files (if you have specified 'zipfile=None' 335 | in the setup script this file is append to the .exe files and not 336 | present in the dist-directory). 337 | 338 | 339 | The ``--bundle `` or ``-b `` command line switch will 340 | create less files because binary extensions, runtime dlls, and even 341 | the Python-dll itself is bundled into the executable itself, or inside 342 | the library-archive if you prefer that. 343 | 344 | The bundled pyds and dlls are *never* unpacked to the file system, 345 | instead they are transparently loaded at runtime from the bundle. The 346 | resulting executable *appears* to be statically linked. 347 | 348 | Specifying a level of ``2`` includes the .pyd and .dll files into the 349 | zip-archive or the executable. Thus, the dist directory will contain 350 | your exe file(s), the library.zip file (if you haven't specified 351 | 'zipfile=None'), and the python dll. The advantage of this scheme is 352 | that the application can still load extension modules from the file 353 | system if you extend ``sys.path`` at runtime. 354 | 355 | Using a level of ``1`` includes the .pyd and .dll files into the 356 | zip-archive or the executable itself, and does the same for 357 | pythonXY.dll. The advantage is that you only need to distribute one 358 | file per exe, which will however be quite large. Another advantage is 359 | that inproc COM servers will run completely isolated from other Python 360 | interpreters in the same exe. The disadvantage of this scheme is that 361 | it is impossible to load other extensions from the file system, the 362 | application will crash with a fatal Python error if you try this. I 363 | have still to find a way to prevent this and raise an ImportError 364 | instead - any suggestions how this can be implemented would be very 365 | welcome. 366 | 367 | The bundle-option has been tested with some popular extensions, but of 368 | course there's no guarantee that any extension will work in bundled 369 | form - be sure to test the executable (which you should do anyway). 370 | 371 | The bundle option achieves its magic by code which emulates the 372 | Windows LoadLibrary api, it is compiled into the exe-stubs that py2exe 373 | uses. For experimentation, it is also installed as a normal Python 374 | extension ``_memimporter.pyd`` in the ``lib\site-packages`` directory. 375 | The Python module ``zipextimported.py`` in the same directory 376 | demonstrates how it can be used to load binary extensions from 377 | zip-files. 378 | 379 | Samples 380 | ------- 381 | 382 | The ``py2exe``-installer installs some examples into the 383 | ``lib\site-packages\py2exe\samples`` directory, demonstrating several 384 | simple and advances features. 385 | 386 | The ``singlefile`` subdirectory contains two samples which are built 387 | as single-file executables: a trivial wxPython gui program, and a 388 | pywin32 dll COM server module. 389 | 390 | How does it work? 391 | ----------------- 392 | 393 | **py2exe** uses python's ``modulefinder`` to examine your script and 394 | find all python and extension modules needed to run it. Pure python 395 | modules are compiled into ``.pyc`` or ``.pyo`` files in a temporary 396 | directory. Compiled extension modules (``.pyd``) are also found and 397 | parsed for binary dependencies. 398 | 399 | A zip-compatible archive is built, containing all python files from 400 | this directory. Your main script is inserted as a resource into a 401 | custom embedded python interpreter supplied with py2exe, and the 402 | zip-archive is installed as the only item on ``sys.path``. 403 | 404 | In simple cases, only ``pythonxx.dll`` is needed in addition to 405 | ``myscript.exe``. If, however, your script needs extension modules, 406 | unfortunately those cannot be included or imported from the 407 | zip-archive, so they are needed as separate files (and are copied into 408 | the ``dist`` directory). 409 | 410 | *Attention*: **py2exe** tries to track down all binary dependencies 411 | for all pyds and dlls copied to the dist directory recursively, and 412 | copies all these dependend files into the dist directory. **py2exe** 413 | has a builtin list of some system dlls which are not copied, but this 414 | list can never be complete. 415 | 416 | Installing py2exe 417 | ----------------- 418 | 419 | Download and run the installer py2exe-0.6.9.win32-py2.3.exe_ (for 420 | Python 2.3), py2exe-0.6.9.win32-py2.4.exe_ (for 421 | Python 2.4), py2exe-0.6.9.win32-py2.5.exe_ (for Python 2.5), 422 | py2exe-0.6.9.win64-py2.5.amd64.msi_ (for 64-bit Python 2.5), 423 | py2exe-0.6.9.win32-py2.6.exe_ (for Python 2.6), 424 | py2exe-0.6.9.win64-py2.6.amd64.exe_ (for 64-bit Python 2.6), 425 | py2exe-0.6.9.win32-py2.7.exe_ (for Python 2.7), or 426 | py2exe-0.6.9.win64-py2.7.amd64.exe_ (for 64-bit Python 2.7). 427 | 428 | This installs **py2exe** together with some samples, the samples are in 429 | the ``lib\site-packages\py2exe\samples`` subdirectory. 430 | 431 | For **Windows 95/98/Me**, you need the *Microsoft Layer for Unicode on 432 | Windows 95/98/ME Systems (MSLU)* dll from here_ (Internet Explorer is 433 | required to download it: Scroll down to the Win95/98/Me section). 434 | 435 | Download and run the self-extracting ``unicows.exe`` file, and copy 436 | the unpacked ``unicows.dll`` file in the directory which contains your 437 | ``python.exe``. Note that this is only needed on the machine where 438 | you want to build executables with **py2exe**, it is not required on 439 | the machine where you want to run the created programs. 440 | 441 | If you use ``py2exe`` to build COM clients or servers, win32all build 442 | 163 (or later) is strongly recommened - it contains much better support 443 | for frozen executables. 444 | 445 | .. _here: http://www.microsoft.com/msdownload/platformsdk/sdkupdate/psdkredist.htm 446 | 447 | Project information 448 | ------------------- 449 | 450 | The project is hosted at |SourceForge|_. 451 | 452 | .. |SourceForge| image:: 453 | http://sourceforge.net/sflogo.php?group_id=15583&;type=1 454 | :alt: SourceForge Logo 455 | :align: middle 456 | :class: borderless 457 | :width: 88 458 | :height: 31 459 | --------------------------------------------------------------------------------