Using Pythonwin in an external project.

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.

Limitations.

The biggest limitations you will find are that a host application must

Below is some example code needed to embedd win32ui in your application..

Changes to the application.

Subclass a Win32uiHostGlue class

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.

Embedding win32ui Architecture

win32uihostglue.h

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.

Delegating to win32uiHostGlue

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:

InitInstance

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:

And the Rest

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.

initscore.py

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)