Pythonwin is distributed as 2 key components - Pythonwin.exe and win32ui.pyd. Win32ui.pyd contains all the user interface in Pythonwin - Pythonwin.exe is a simple "wrapper" .exe that hosts win32ui.pyd.
This document describes how to imbed the win32ui extension module in your own application.
The biggest limitations you will find are that a host application must
Below is some example code needed to embedd win32ui in your application..
You must sub-class a Win32uiHostGlue class. This class is used as a glue between win32ui.pyd and the host .exe, and is defined in Win32uiHostGlue.h
Currently, this consists of about 5 methods that must be called by your application. The principle is that the Application must hook certain handlers, and delegate them to the HostGlue class. This will ensure the appropriate Win32ui internals are called.
The win32uihostglue.h module defines a class which makes interfacing fairly simple. This Win32uiHostGlue class is used as a glue between win32ui.pyd and the host .exe. In the most simple case, you need to instantiate one of the classes, and at certain key points in your CWinApp derived class, call the appropriate methods. You may choose to provide your own glue class derived from Win32uiHostGlue in certain cases.
Below is an example class, which overrides the "SetStatusText" method, so that status information displays in the applications status bar. (win32ui has no real idea if the main frame has a status bar, or what its control ID is, etc.).
GameApp NEAR theApp; // My existing CWinApp derived class.
// HostGlue class.
class GameHostGlue : public Win32uiHostGlue {
virtual void SetStatusText(const char *text, BOOL bForce)
// Assuming our GameApp above defines a SetStatusText
method
{GetApp()->SetStatusText(text, bForce);}
};
// The one and only Glue object.
GameHostGlue NEAR glue;
And now we are well on our way.
You need to either implement, or modify, certain key methods of your Application object. Probably the most important is the call to initialise win32ui. You need to modify your CWinApp::InitInstance method (it is almost certain you already have one). The following code needs to be executed in this method:
BOOL GameApp::InitInstance()
{
...
if (!glue.DynamicApplicationInit("import initscore",
csScripts)) {
// Assuming you have a ReportError method - do whatever
makes sense!
ReportError("Could not attach to the Python win32ui
extensions");
return FALSE;
}
...
Note the following:
Below is the rest of the code you need to implement. You may need to create these methods, as the "typical" MFC applcation does not have some.
BOOL
GameApp::OnCmdMsg (UINT nID, int nCode,
void* pExtra, AFX_CMDHANDLERINFO*pHandlerInfo)
{
// yield to Python first - send to the main frame,
as there is no Python app object.
if (glue.OnCmdMsg (m_pMainWnd, nID, nCode, pExtra,
pHandlerInfo))
return TRUE;
else
return CWinApp::OnCmdMsg (nID, nCode, pExtra, pHandlerInfo);
}
BOOL GameApp::PreTranslateMessage(MSG *pMsg)
{
if (glue.PreTranslateMessage(pMsg))
return TRUE;
else
return CWinApp::PreTranslateMessage(pMsg);
}
BOOL GameApp::OnIdle( LONG lCount )
{
// call base class idle first
if (CWinApp::OnIdle(lCount))
return TRUE;
return glue.OnIdle(lCount);
}
Below is the code for initscore.py (with an annotated interruption). Obviously your code will vary, depending on your requirements.
import sys
import win32ui
import win32con
import score
# First step - redirect python output to the debugging device,
until we
# can create a window to capture it.
class DebugOutput:
softspace=1
def write(self,message):
win32ui.OutputDebug(message)
sys.stderr=sys.stdout=DebugOutput()
debugging = 1 # Or read it from an INI, or whatever.
import intpyapp # Simply use Pythonwins code to do the work.
import app
app.App = app.AppBuilder()
app.App.frame = win32ui.GetMainFrame()
app.App.HookCommands()
if debugging:
win32ui.CreateDebuggerThread() # The "Break"
button
# And create an interactive window. This captures sys.stdout,
# so all future Python errors go there.
import interact
interact.CreateInteractiveWindow()
import editor # To add a ".py" document handler.
This will
# mean that ".py" files should automatically appear
on your "Open File" dialog.
import scoreval # Import a Python module. This module is
my main
# interface back into the C++ application. Without this,
there is not
# a good reason for embedding Pythonwin in your app.
# This may call for black-magic!!!
# Minimise the interactive window (you may not want to!)
interact.edit.currentView.GetParent().ShowWindow(win32con.SW_MINIMIZE)