----- Original Message -----
From: "Thomas Heller" <[EMAIL PROTECTED]>
To: <pythonce@python.org>
Sent: Monday, January 09, 2006 10:42 PM
Subject: Re: [PythonCE] How do you develop on the PocketPC?
"Luke Dunstan" <[EMAIL PROTECTED]> writes:
I'm sorry to say that I've seen the NULL bug before but have been too
distracted by the task at hand to fix it, but here is a patch that
fixes it.
By the way, I've recently tried running the remote part of "winpdb"
(http://www.digitalpeers.com/pythondebugger/) on Windows CE and
connecting to it over TCP/IP from the GUI running on the PC, and after
a trivial change (to handle a lack of PATH environment variable) it
worked fine. Personally I would rather have the ability to communicate
to the remote debugger using ActiveSync rather than only TCP/IP
because it is more convenient especially since I only have Bluetooth
not WiFi, so I have been investigating using the Remote API (RAPI).
In case you are talking about the scripts I posted: Although the client
and server connect via TCP/IP, the only connection between the pockect
PC and the desktop computer I have is the cradle with an USB cable, plus
activesync (3.8, IIRC) running. It seems activesync emulates internet
connection on the pocket pc.
Thomas
I have noticed that IE works on the PDA when cradled, but I know that
ActiveSync is not providing a real network adapter on the PC side because an
extra IP does not appear in the output of 'ipconfig'. This prevents running
TCP listen servers on the PDA but it is true that your method works nicely
in this case. As a demonstration of how we could make it even more
convenient, I have modified it slightly so that the server starts the client
script on the PDA remotely, using RAPI via ctypes. I have put the
experimental RAPI interfacing code in a separate module "wincerapi".
We should probably consider putting all these scripts in CVS somewhere.
Luke
# Thomas Heller 20060109
# Start this script on the PC, then start client.py on the Pocket PC.
import socket, sys, threading
import wincerapi
# Initialise RAPI
wincerapi.CeRapiInitTimeout()
# Start the client program on the device
DEVICE_PYTHON_EXE = '\\Program Files\\Python\\python.exe'
DEVICE_SCRIPT = '\\my documents\\python\\pyceclient.py'
wincerapi.RunProcess(DEVICE_PYTHON_EXE, '"' + DEVICE_SCRIPT + '"')
HOST = '' # Symbolic name meaning the local host
PORT = 20000 # Arbitrary non-privileged port
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.bind((HOST, PORT))
s.listen(1)
conn, addr = s.accept()
def get_input():
while 1:
data = raw_input()
conn.send(data + '\n')
t = threading.Thread(target=get_input)
t.setDaemon(True)
t.start()
while 1:
data = conn.recv(1024)
if not data:
print "SystemExit, hit return to end."
raise SystemExit
sys.stderr.write(data)
# vi:ts=4:sw=4:et
import ctypes
from ctypes.com import STDMETHOD
from ctypes.com.storage import IStream
_rapi = ctypes.windll.rapi
###########################################################
#
# Internal helpers
#
_DWORD = ctypes.c_ulong
_WCHAR = ctypes.c_wchar
_BOOL = ctypes.c_int
def _SUCCEEDED(hr):
return hr >= 0
def _FAILED(hr):
return hr < 0
###########################################################
#
# Error handling
#
CeRapiGetError = _rapi.CeRapiGetError
CeRapiGetError.argtypes = []
CeRapiGetError.restype = _DWORD # really a HRESULT
CeGetLastError = _rapi.CeGetLastError
CeGetLastError.argtypes = []
CeGetLastError.restype = _DWORD
class RapiError(Exception):
"""This error is raised by some functions in this module when an error
occurs"""
def __init__(self, message):
self.rapi_errno = CeRapiGetError()
self.ce_errno = CeGetLastError()
if self.rapi_errno == 0:
if self.ce_errno == 0:
msg = message + " (No error code)"
else:
msg = "%s (CeGetLastError: %d)" % (message, self.ce_errno)
else:
msg = "%s (CeRapiGetError: %d)" % (message, self.rapi_errno)
Exception.__init__(self, msg)
###########################################################
#
# Initialisation
#
class RAPIINIT(ctypes.Structure):
_fields_ = [
("cbSize", _DWORD),
("heRapiInit", _DWORD),
("hrRapiInit", ctypes.HRESULT),
]
def __init__(self):
self.cbSize = ctypes.sizeof(self)
CeRapiInitEx = _rapi.CeRapiInitEx
CeRapiInitEx.argtypes = [ ctypes.POINTER(RAPIINIT) ]
CeRapiInitEx.restype = ctypes.HRESULT
CeRapiUninit = _rapi.CeRapiUninit
CeRapiUninit.argtypes = []
CeRapiUninit.restype = ctypes.HRESULT
def CeRapiInitTimeout(timeout_ms = 5000):
"""Initialises the RAPI connection, failing if it does not succeed within
the specified timeout (milliseconds).
Implemented by calling CeRapiInitEx, then waiting on the returned event
handle with a timeout.
Raises RapiError on failure.
"""
ri = RAPIINIT()
CeRapiInitEx(ctypes.byref(ri))
# FIXME: how do you get the address of a ctypes.Structure field?
hEvent = _DWORD(ri.heRapiInit)
WAIT_OBJECT_0 = 0
rwait = ctypes.windll.user32.MsgWaitForMultipleObjects(1,
ctypes.byref(hEvent), 0, timeout_ms, 0)
if rwait == WAIT_OBJECT_0:
if _FAILED(ri.hrRapiInit):
raise RapiError("CeRapiInitEx failed: " + str(ri.hrRapiInit))
# else success
else:
# The wait timed out or failed
ex = RapiError("Timeout waiting for CeRapiInitEx")
CeRapiUninit()
raise ex
###########################################################
#
# File I/O
#
INVALID_HANDLE_VALUE = 0xffffffff # HANDLE is an unsigned long
ERROR_NO_MORE_FILES = 18
MAX_PATH = 260
class HANDLE(ctypes.c_ulong):
def _check_HANDLE(handle):
if handle == INVALID_HANDLE_VALUE:
raise RapiError("RAPI call returned invalid handle")
return handle
_check_retval_ = staticmethod(_check_HANDLE)
class BOOLRESULT(ctypes.c_int):
def _check_BOOLRESULT(value):
if not value:
raise RapiError("RAPI call returned FALSE")
return value
_check_retval_ = staticmethod(_check_BOOLRESULT)
class FILETIME(ctypes.Structure):
_fields_ = [
("dwLowDateTime", _DWORD),
("dwHighDateTime", _DWORD),
]
class CE_FIND_DATA(ctypes.Structure):
_fields_ = [
("dwFileAttributes", _DWORD),
("ftCreationTime", FILETIME),
("ftLastAccessTime", FILETIME),
("ftLastWriteTime", FILETIME),
("nFileSizeHigh", _DWORD),
("nFileSizeLow", _DWORD),
("dwOID", _DWORD),
("cFileName", _WCHAR * MAX_PATH),
]
_as_parameter_ = property(ctypes.byref) # always passed by reference
CeFindFirstFile = _rapi.CeFindFirstFile
CeFindFirstFile.argtypes = [ ctypes.c_wchar_p, CE_FIND_DATA ]
CeFindFirstFile.restype = HANDLE
CeFindNextFile = _rapi.CeFindNextFile
CeFindNextFile.argtypes = [ HANDLE, CE_FIND_DATA ]
CeFindClose = _rapi.CeFindClose # TODO: check for errors?
CeFindClose.argtypes = [ HANDLE ]
CeCopyFile = _rapi.CeCopyFile
CeCopyFile.argtypes = [ ctypes.c_wchar_p, ctypes.c_wchar_p, _BOOL ]
CeDeleteFile = _rapi.CeDeleteFile
CeDeleteFile.argtypes = [ ctypes.c_wchar_p ]
CeDeleteFile.restype = BOOLRESULT
def listdir(path):
"""This function is meant to emulate os.listdir but lists files on the WinCE
device"""
pattern = unicode(path)
if pattern[-1:] != u'\\':
pattern += u'\\'
pattern += u'*'
lst = []
data = CE_FIND_DATA()
try:
hFind = CeFindFirstFile(pattern, data)
except RapiError, ex:
# A "no files" error is perfectly normal
if ex.ce_errno == ERROR_NO_MORE_FILES:
return lst
raise
try:
lst.append(data.cFileName)
while CeFindNextFile(hFind, data):
lst.append(data.cFileName)
finally:
CeFindClose(hFind)
return lst
###########################################################
#
# Miscellaneous
#
CeCloseHandle = _rapi.CeCloseHandle # TODO: check for errors?
CeCloseHandle.argtypes = [ HANDLE ]
RAPISTREAMFLAG = ctypes.c_int # enum
STREAM_TIMEOUT_READ = 0
class IRAPIStream(IStream):
#_iid_ = ?
_methods_ = IStream._methods_ + [
STDMETHOD(ctypes.HRESULT, "SetRapiStat", RAPISTREAMFLAG, _DWORD),
STDMETHOD(ctypes.HRESULT, "GetRapiStat", RAPISTREAMFLAG,
ctypes.POINTER(_DWORD)),
]
CeRapiInvoke = _rapi.CeRapiInvoke
CeRapiInvoke.argtypes = [ ctypes.c_wchar_p, ctypes.c_wchar_p,
_DWORD, ctypes.c_void_p, ctypes.POINTER(_DWORD),
ctypes.POINTER(ctypes.c_void_p),
ctypes.POINTER(ctypes.POINTER(IRAPIStream)), _DWORD ]
CeRapiInvoke.restype = ctypes.HRESULT
LocalFree = ctypes.windll.kernel32.LocalFree
LocalFree.argtypes = [ ctypes.c_void_p ]
class PROCESS_INFORMATION(ctypes.Structure):
_fields_ = [
("hProcess", HANDLE),
("hThread", HANDLE),
("dwProcessId", _DWORD),
("dwThreadId", _DWORD),
]
_as_parameter_ = property(ctypes.byref) # always passed by reference
CeCreateProcess = _rapi.CeCreateProcess
CeCreateProcess.argtypes = [ ctypes.c_wchar_p, ctypes.c_wchar_p,
ctypes.c_void_p,
ctypes.c_void_p, _BOOL, _DWORD, ctypes.c_void_p, ctypes.c_void_p,
ctypes.c_void_p,
PROCESS_INFORMATION ]
CeCreateProcess.restype = BOOLRESULT
def RunProcess(program, command_line, flags=0):
if command_line:
command_line = unicode(command_line)
else:
command_line = None
pi = PROCESS_INFORMATION()
CeCreateProcess(unicode(program), command_line,
None, None, 0, 0, None, None, None, pi)
CeCloseHandle(pi.hProcess)
CeCloseHandle(pi.hThread)
return pi.dwProcessId
###########################################################
#
# Testing
#
def test():
ri = RAPIINIT()
print "Calling CeRapiInitEx"
CeRapiInitEx(ctypes.byref(ri))
print "CeRapiInitEx started..."
# FIXME: how do you get the address of a ctypes.Structure field?
hEvent = _DWORD(ri.heRapiInit)
WAIT_OBJECT_0 = 0
rwait = ctypes.windll.user32.MsgWaitForMultipleObjects(1,
ctypes.byref(hEvent), 0, 5000, 0)
if rwait == WAIT_OBJECT_0:
if _SUCCEEDED(ri.hrRapiInit):
print "CeRapiInitEx finished successfully"
else:
print "CeRapiInitEx failed: ", ri.hrRapiInit
return
else:
print "CeRapiInitEx timed out: calling CeRapiUninit"
CeRapiUninit()
return
# Init success
# Clean up
print "Calling CeRapiUninit"
CeRapiUninit()
if __name__ == '__main__':
test()
_______________________________________________
PythonCE mailing list
PythonCE@python.org
http://mail.python.org/mailman/listinfo/pythonce