wxPython框架显示在XP但不是win2003服务器

时间:2011-04-04 19:11:33

标签: python windows-xp windows-server-2003

我已经编写了一个在我的XP开发平台上运行良好的应用程序。当我用py2exe编译它并将其移动到没有安装python等的其他XP平台时它也可以正常工作。当我将它移动到2003服务器平台时,它无法显示主框架,但会显示wx.messagebox弹出窗口。

在同一个2003平台上,我安装python 2.7,wx 2.8,ObjectListView来模仿我的开发环境,但我有相同的结果。显示wx.messagebox弹出窗口,但主框架不显示。

我通过依赖walker运行已编译的exe版本,并突出显示2003平台缺少msjava.dll的事实。然后我重新编译并在py2exe设置中包含它。但这并没有改变任何事情。

非常感谢任何帮助。

代码示例

import wx
import random
import datetime
import sys
import getpass
import os
import socket
import subprocess
import platform
from _winreg import *
import zipfile
import bisect
from threading import Thread
import fileinput
import subprocess
from subprocess import call

######################
# Thread functions
#####################
class unzipThread(Thread):
    def __init__(self, fileName, destination):
        self.fileName = fileName
        self.destination = destination
        super(unzipThread, self).__init__()

    def run(self):
        print "unzipThread", self.fileName, self.destination
        zip = zipfile.ZipFile(self.fileName)        
        zip.extractall(self.destination)
        zip.close()

###########################################


def create(parent):
    return Frame1(parent)

[wxID_FRAME1, wxID_FRAME1BTBEGININSTALL, wxID_FRAME1BTVALIDATEALL, 
 wxID_FRAME1BTVALIDATEIAS_ADMIN, wxID_FRAME1BTVALIDATEINFRASYSTEM, 
 wxID_FRAME1BTVALIDATEIWPCADMIN, wxID_FRAME1BTVALIDATEIWPCIWPCDBA, 
 wxID_FRAME1BTVALIDATEIWPCSYSTEM, wxID_FRAME1BTVALIDATELDAPOC4JADMIN, 
 wxID_FRAME1BTVALIDATELDAPORCLADMIN, wxID_FRAME1CBINSTALLPATCH3, 
 wxID_FRAME1CBINSTALLPATCH4, wxID_FRAME1CBINSTALLPATCH5, 
 wxID_FRAME1CBINSTALLSSP, wxID_FRAME1LISTCTRL1, wxID_FRAME1PANEL1, 
 wxID_FRAME1STACCOUNTSETTINGS, wxID_FRAME1STIAS_ADMIN, 
 wxID_FRAME1STINFRASYSTEM, wxID_FRAME1STINSTALLACTIONS, 
 wxID_FRAME1STIWPCADMIN, wxID_FRAME1STIWPCIWPCDBA, wxID_FRAME1STIWPCSYSTEM, 
 wxID_FRAME1STLDAPOC4JADMIN, wxID_FRAME1STLDAPORCLADMIN, wxID_FRAME1STSTATUS, 
 wxID_FRAME1TXIAS_ADMIN, wxID_FRAME1TXINFRASYSTEM, wxID_FRAME1TXIWPCADMIN, 
 wxID_FRAME1TXIWPCIWPCDBA, wxID_FRAME1TXIWPCSYSTEM, 
 wxID_FRAME1TXLDAPOC4JADMIN, wxID_FRAME1TXLDAPORCLADMIN, 
] = [wx.NewId() for _init_ctrls in range(33)]

class Frame1(wx.Frame):

    listSSP=[]    
    sspStartPoint=""
    passwordsTestList = {"infra.system":False, "iwpc.system":False, "iwpc.iwpcdba":False, "ldap.oc4jadmin":False, "ldap.orcladmin":False, "ias_admin":False, "iwpcadmin":False}  
    passwordsValidList = {"infra.system":"", "iwpc.system":"", "iwpc.iwpcdba":"", "ldap.oc4jadmin":"", "ldap.orcladmin":"", "ias_admin":"", "iwpcadmin":""}


    def _init_coll_listCtrl1_Columns(self, parent):
        # generated method, don't edit

        parent.InsertColumn(col=0, format=wx.LIST_FORMAT_LEFT,
              heading=u'Timestamp', width=200)
        parent.InsertColumn(col=1, format=wx.LIST_FORMAT_LEFT,
              heading=u'Action', width=200)
        parent.InsertColumn(col=2, format=wx.LIST_FORMAT_LEFT,
              heading=u'Result', width=400)

    def _init_ctrls(self, prnt):
        # generated method, don't edit
        wx.Frame.__init__(self, id=wxID_FRAME1, name='', parent=prnt,
              pos=wx.Point(1932, 17), size=wx.Size(849, 748),
              style=wx.DEFAULT_FRAME_STYLE,
              title=u'IWPC Patch and SSP Installer')
        self.SetClientSize(wx.Size(841, 714))

        self.panel1 = wx.Panel(id=wxID_FRAME1PANEL1, name='panel1', parent=self,
              pos=wx.Point(0, 0), size=wx.Size(841, 714),
              style=wx.TAB_TRAVERSAL)

        self.listCtrl1 = wx.ListCtrl(id=wxID_FRAME1LISTCTRL1, name='listCtrl1',
              parent=self.panel1, pos=wx.Point(15, 24), size=wx.Size(808, 419),
              style=wx.LC_REPORT)
        self._init_coll_listCtrl1_Columns(self.listCtrl1)

---剪断以获得最大字符下的帖子长度...---

    def __init__(self, parent):
        self._init_ctrls(parent)

    def updateList(self, action, result):
        self.listCtrl1.Append([datetime.datetime.now(),action,result])
        self.listCtrl1.EnsureVisible(self.listCtrl1.GetItemCount() -1)
        self.Update()

    def allPasswordsValid(self):       
        #if all passwords are true then enable the button
        for k, v in self.passwordsTestList.items():
            print "  %s=%s" % (k,v)
            if v == False:
                print "  NOT ENABLED"
                return()

        print "  ENABLE IT"
        self.btBeginInstall.Enable()
        self.btValidateAll.Disable()

    def checkPassword(self, password):

        #randomize password results
        bResult = random.choice([True,False])

        return bResult

    def passwordChecker(self, sAccount, sTxName, sBtName):
        print "check " + sAccount
        self.btBeginInstall.Disable()

        if self.passwordsTestList[sAccount] == False:
            #Get password from value
            sPassword = sTxName.Value

            #TODO: Make diff tests for each password type
            bResult = self.checkPassword(sPassword)

            #update test list with current result
            self.passwordsTestList[sAccount] = bResult

            #Do results from test
            if bResult == True:
                self.passwordsValidList[sAccount] = sPassword
                sTxName.SetBackgroundColour('Green')
                self.updateList("Validate " + sAccount,"Passed")
                sBtName.Disable()
            else:
                sTxName.SetBackgroundColour('Red')
                self.updateList("Validate " + sAccount,"Failed")
        else:
            #reset the displayed password back to the previously validated state
            self.updateList(sAccount + " is already valid","Display value reset to " + self.passwordsValidList[sAccount])
            sTxName.SetValue(self.passwordsValidList[sAccount])

        #run test to see if all are valid
        self.allPasswordsValid()        

    def OnBtValidateInfraSystemButton(self, event):
        print "button InfraSystem"
        self.passwordChecker("infra.system",self.txInfraSystem,self.btValidateInfraSystem)
        self.Refresh()

    def OnBtValidateIwpcSystemButton(self, event):
        print "button IwpcSystem"
        self.passwordChecker("iwpc.system",self.txIwpcSystem,self.btValidateIwpcSystem)
        self.Refresh()

    def OnBtValidateIwpcIwpcdbaButton(self, event):
        print "button IwpcIwpcdba"
        self.passwordChecker("iwpc.iwpcdba",self.txIwpcIwpcdba,self.btValidateIwpcIwpcdba)
        self.Refresh()

    def OnBtValidateLdapOc4jadminButton(self, event):
        print "button LdapOc4jadmin"
        self.passwordChecker("ldap.oc4jadmin",self.txLdapOc4jadmin,self.btValidateLdapOc4jadmin)
        self.Refresh()

    def OnBtValidateLdapOrcladminButton(self, event):
        print "button LdapOrcladmin"
        self.passwordChecker("ldap.orcladmin",self.txLdapOrcladmin,self.btValidateLdapOrcladmin)
        self.Refresh()

    def OnBtValidateIas_adminButton(self, event):
        print "button Ias_admin"
        self.passwordChecker("ias_admin",self.txIas_admin,self.btValidateIas_admin)
        self.Refresh()

    def OnBtValidateiwpcadminButton(self, event):
        print "button iwpcadmin"
        self.passwordChecker("iwpcadmin",self.txIwpcadmin,self.btValidateiwpcadmin)
        self.Refresh()

    def OnBtValidateAllButton(self, event):
        print "button Validate All"
        self.passwordChecker("infra.system",self.txInfraSystem,self.btValidateInfraSystem)
        self.passwordChecker("iwpc.system",self.txIwpcSystem,self.btValidateIwpcSystem)
        self.passwordChecker("iwpc.iwpcdba",self.txIwpcIwpcdba,self.btValidateIwpcIwpcdba)
        self.passwordChecker("ldap.oc4jadmin",self.txLdapOc4jadmin,self.btValidateLdapOc4jadmin)
        self.passwordChecker("ldap.orcladmin",self.txLdapOrcladmin,self.btValidateLdapOrcladmin)
        self.passwordChecker("ias_admin",self.txIas_admin,self.btValidateIas_admin)
        self.passwordChecker("iwpcadmin",self.txIwpcadmin,self.btValidateiwpcadmin)
        self.Refresh()

    def writeData(self):

        fileName = 'd:\ssptemp\OracleData.txt'
        FILE = open(fileName,"w")

        for key, value in self.passwordsValidList.items():
            writeLine = key + ': ' + value + '\n'
            FILE.write(writeLine)

        FILE.close()

        self.updateList("Account data stored","Complete")

    def find_fwd_iter(self, S, i):
        #Allows iteration of a list from a specific match of value in the list
        j = bisect.bisect_left(S, i)
        for k in xrange(j, len(S)):
            yield S[k]

    def copySSPTemp(self):
        #Unzip sourc\ssp X-Y\ssptemp.zip to d:\ssptemp\ssp X-Y

        #put start point into [X,y] form
        sYr, sQtr = self.sspStartPoint.split('-')
        iYr = int(sYr)
        iQtr = int(sQtr)

        sspStart =[iYr,iQtr]

        for yr, qtr in self.find_fwd_iter(self.listSSP,sspStart):
            dirName = 'ssp ' + str(yr) + '-' + str(qtr)
            sspDest = os.path.join('d:\ssptemp',dirName)
            currentDir = os.getcwd()
            sspTempPath = os.path.join(currentDir,dirName,'ssptemp.zip')
            installPath = os.path.join(currentDir,dirName,'install.zip')

            #create destination dir if needed d:\ssptemp\ssp yr-qtr
            if os.path.isdir(sspDest) == False:
                os.mkdir(sspDest)

            if os.path.isdir('d:\install') == False:
                os.mkdir('d:\install')

            #Unzip ssptemp to dest
            print "UNZIP"
            self.updateList("Unzip " + dirName + " ssptemp.zip", "Begining unzip.  Process may take several minutes")
            t1 = unzipThread(sspTempPath,sspDest)
            t1.start()
            t1.join()

            #Unzip install.zip to d:\install
            self.updateList("Unzip " + dirName + " install.zip", "Begining unzip.  Process may take several minutes")
            t2 = unzipThread(installPath,'d:\install')
            t2.start()
            t2.join()

        self.updateList("Unzip SSP control files","Complete")
        self.updateList("Unzip SSP install files","Complete")

    def createChain(self):

        ####### TODO - DON'T DO CHAIN IF LIST SIZE IS ONLY 1 #########

        #Iterate through all d:\ssptemp\sspX-Y dirs add all iwpcpatch files to list
        listOfFiles = []
        for path, dirs, files in os.walk('d:\ssptemp'):
            for file in files:
                newFile = os.path.join(path,file)
                if newFile.find('IWPCPatch') >= 0:
                    for line in fileinput.FileInput(newFile):
                        if "IWPCPatchFinal_a.wsf" in line:
                            print "Added", newFile
                            listOfFiles.append(newFile)

        #Iterate through list looking for "D:\ssptemp\<currentFilesDir>\IWPCPATCHFinal_a.wsf
        idx = 1
        for item in listOfFiles[0:len(listOfFiles)-1]:
            currentPath, currentFile = os.path.split(item)
            currentPath = os.path.join(currentPath,"IWPCPatchFinal_a.wsf")
            nextPath, nextFile = os.path.split(listOfFiles[idx])
            nextPath = os.path.join(nextPath,'IWPCPatch.wsf')
            print currentPath, nextPath
            for line in fileinput.FileInput(item,inplace=1):
                if currentPath in line:
                    line = line.replace(currentPath,nextPath)
                sys.stdout.write(line)
            idx += 1
            self.updateList("Edit " + currentPath,"Complete")

        self.updateList("Create install chain","Complete")

    # TODO: Null the GW to prevent Oracle from attempting to dial home
    def nullGateWay(self):
        self.updateList("Gateway set to null","PLACEHOLDER: Complete")

    def enableWFS(self):        
        key = OpenKey(HKEY_LOCAL_MACHINE,
                      r'Software\Microsoft\Windows Script Host\Settings',
                      0,
                      KEY_ALL_ACCESS)

        try:
            SetValueEx(key, "Enabled", 0, REG_DWORD, 1)
            self.updateList(".WFS Scripts enable","Complete")
        except:
            self.updateList(".WFS Scripts enable","ERROR: Key not present")
            self.markWarning()

        CloseKey(key)

    def disableJedi(self):
        key = OpenKey(HKEY_LOCAL_MACHINE,
                      r'Software\Microsoft\Windows NT\CurrentVersion\Winlogon',
                      0,
                      KEY_ALL_ACCESS)
        try:
            SetValueEx(key, "GinaDLL", 0, REG_SZ, "msgina.dll")
            self.updateList("Jedi Disabled","Complete")
        except:
            self.updateList("Jedi Disabled","ERROR: Key not present")
            self.markWarning()

        CloseKey(key)        

    def enableVBS(self):
        key = OpenKey(HKEY_CURRENT_USER,
                      r'Software\Microsoft\Windows\CurrentVersion\Explorer\FileExts\.VBS',
                      0,
                      KEY_ALL_ACCESS)
        try:
            DeleteValue(key, "Application")
            self.updateList("Remove VBS to Notepad mapping","Complete")
        except:
            self.updateList("Remove VBS to Notepad mapping","ERROR: Key not present")
            self.markWarning()

        CloseKey(key) 

    def runInstall(self):
        print "-- runInstall --"

        #Run
        print self.sspStartPoint
        firstRun = "d:\ssptemp\ssp " + str(self.sspStartPoint)
        firstRun = os.path.join(firstRun,"IWPCPatch.wsf")


        retcode = subprocess.call(["wscript.exe", "d:\ssptemp\ssp 9-2\IWPCPatch.wsf"])

    def OnBtBeginInstallButton(self, event):
        #Disable to prevent multi-clicks
        self.btBeginInstall.Disable

        # TODO: Enable button only if all passwords are valid
        self.writeData()
        self.copySSPTemp()
        self.createChain()
        #self.nullGateWay()
        self.enableWFS()
        self.disableJedi()
        self.enableVBS()
        self.runInstall()

        self.updateList("Begin Install","Complete")


        self.Refresh()

    def validateCurrentUser(self):
        sCurrentUser = getpass.getuser()
        print sCurrentUser

        if (sCurrentUser == 'Chris.White'):
            print "iwpcadmin verified"
            self.updateList('Validate user as Chris.White', 'user validated as Chris.White')
            return True
        else:
            print "Error:  Current user is " + sCurrentUser + " not iwpcadmin"
            strError = "ERROR:  Current user is not iwpcadmin.  Please logoff and logon as iwpcadmin"

            self.updateList('Validate user as iwpcadmin',strError)
            self.markError()
            return False

    def createDir(self, sDir):
        if os.path.isdir(sDir):
            self.updateList('Check for ' + sDir,'exists')
            return True

        else:
            self.updateList('Check for ' + sDir,'does not exist')
            os.mkdir(sDir)
            if os.path.isdir(sDir):
                self.updateList('Created ' + sDir, 'success')
                return True

            else:
                self.updateList('Created ' + sDir, 'FAILED')
                self.markError()
                return False

    def markError(self):
        idx = self.listCtrl1.GetItemCount()
        idx -= 1
        self.listCtrl1.SetItemBackgroundColour(idx,"red")
        self.listCtrl1.SetItemTextColour(idx,"white")

    def markWarning(self):
        idx = self.listCtrl1.GetItemCount()
        idx -= 1
        self.listCtrl1.SetItemBackgroundColour(idx,"yellow")

    def getServerID(self):
        sHostname = platform.uname()[1]
        self.updateList('Get Hostname', sHostname)

        sIP = socket.gethostbyaddr(socket.gethostname())[-1][0]
        self.updateList('Get IP', sIP)

        fileName = "d:\ssptemp\PCinfo.txt"

        FILE = open(fileName,"w")

        writeline = "Hostaname: " + sHostname + '\n'
        FILE.write(writeline)

        writeline = "IP: " + sIP + '\n'
        FILE.write(writeline)

        FILE.close()

        if os.path.isfile(fileName):
            return True
        else:
            return False

    #TODO Get Netmask and GW

    def getCurrentSSP(self):
        try:            
            key = OpenKey(HKEY_LOCAL_MACHINE, r'SOFTWARE\IWPC')
            SSPYr = QueryValueEx(key, "SSPYr")[0]
            SSPQtr = QueryValueEx(key, "SSPQtr")[0]

            CloseKey(key)

        except WindowsError:
            print "no value in reg"
            self.updateList('Check Registry for current SSP Level',
                            'Registry key SSPYr does not exist - Checking Folder Structure')

            if os.path.isdir('D:\OracleAppSvr\10.1.3\.patch_storage\9173042'):
                SSPYr = '10'
                SSPQtr = '02'
            elif os.path.isdir('D:\OracleAppSvr\10.1.3\.patch_storage\9173036'):
                SSPYr = '10'
                SSPQtr = '01'                
            elif os.path.isdir('D:\OracleAppSvr\10.1.3\.patch_storage\8874212'):
                SSPYr = '09'
                SSPQtr = '04'
            elif os.path.isdir('D:\OracleAppSvr\10.1.3\.patch_storage\8537043'):
                SSPYr = '09'
                SSPQtr = '03'
            elif os.path.isdir('D:\OracleAppSvr\10.1.3\.patch_storage\8300356'):
                SSPYr = '09'
                SSPQtr = '02'
            elif os.path.isdir('D:\OracleAppSvr\10.1.3\.patch_storage\7608333'):
                SSPYr = '09'
                SSPQtr = '01'
            elif os.path.isdir('D:\OracleAppSvr\10.1.3\.patch_storage\7135490'):
                SSPYr = '09'
                SSPQtr = '01'                
            else:
                SSPYr = '99'
                SSPQtr = '99'

            keyValue = r'SOFTWARE\IWPC'
            key = CreateKey(HKEY_LOCAL_MACHINE, keyValue)

            SetValueEx(key, "SSPYr", 0, REG_DWORD, int(SSPYr))
            SetValueEx(key, "SSPQtr", 0, REG_DWORD, int(SSPQtr))
            self.updateList("SSP Value set in registry","Complete")

            CloseKey(key)

        sCurrentSSP = str(SSPYr) + "-" + str(SSPQtr)
        self.updateList('Check Registry for current SSP Level',
                            'Current SSP is ' + sCurrentSSP)

        #TODO Write Reg Value


        return sCurrentSSP

    def getNextSSP(self, currentSSP):
        sCurrentYr, sCurrentQtr = currentSSP.split('-')

        if int(sCurrentQtr) == 4:
            iNextYr = int(sCurrentYr)+1
            iNextQtr = 1
        else:
            iNextYr = int(sCurrentYr)
            iNextQtr = int(sCurrentQtr)+1

        sNextSSP = str(iNextYr) + "-" + str(iNextQtr)
        self.updateList('Set next SSP Level',
                            'Next SSP is ' + sNextSSP)

        return sNextSSP

    def getListSSP(self):
        #Get current dir
        currentDir = os.getcwd()

        #List dirs in current
        dirContents = os.listdir(currentDir)

        for item in dirContents:
            if os.path.isdir(item):
                if (item.find('ssp') >= 0):
                    sSSP = item.lstrip('ssp ')
                    sYr, sQtr = sSSP.split('-')
                    iYr = int(sYr)
                    iQtr = int(sQtr)
                    self.listSSP.append([iYr,iQtr])

        #Put list in yr,qtr order
        self.listSSP.sort()

        #Display resutls to user
        for yr,qtr in self.listSSP:
            sSSP = str(yr) + '-' + str(qtr)
            self.updateList('Check media for SSPs', sSSP + " is present")

    def getSSPStart(self, sNextSSP):
        #split next to yr,qtr
        print sNextSSP

        #Make nextssp to int
        sNextYr, sNextQtr = sNextSSP.split('-')
        iNextYr = int(sNextYr)
        iNextQtr = int(sNextQtr)

        for yr,qtr in self.listSSP:         
            if ([yr,qtr] == [iNextYr,iNextQtr]):
                sspStart = str(yr) + '-' + str(qtr)
                self.updateList('Set SSP Start', sspStart + ' set as start')
                self.sspStartPoint = sspStart
                return sspStart

        self.updateList('Set SSP Start', 'ERROR: No valid SSP start point found')
        self.markError()
        return False

    def validateSSPMedia(self):

        #Get Current SSP Level
        sCurrentSSP = self.getCurrentSSP()
        print "CURRENT SSP", sCurrentSSP

        #Get Next SSP
        sNextSSP = self.getNextSSP(sCurrentSSP)
        print "NEXT SSP", sNextSSP

        #Compile list of SSPs on media
        self.getListSSP()
        print "LIST SSP", self.listSSP

        #define start point
        sspStart = self.getSSPStart(sNextSSP)

        if sspStart == False:
            return False
        else:
            return True

if __name__ == '__main__':
    app = wx.PySimpleApp()
    frame = create(None)
    frame.Show()

    #disable the buttons
    frame.btBeginInstall.Disable()
    frame.btValidateInfraSystem.Disable()
    frame.btValidateIwpcSystem.Disable()
    frame.btValidateIwpcSystem.Disable()
    frame.btValidateIwpcIwpcdba.Disable()
    frame.btValidateLdapOc4jadmin.Disable()
    frame.btValidateLdapOrcladmin.Disable()
    frame.btValidateIas_admin.Disable()
    frame.btValidateiwpcadmin.Disable()
    frame.btValidateAll.Disable()

# 1) Prompt with backup warning message - offer to exit
    sMessage = """ WARNING: You should always have a valid, tested backup prepared
                prior to performing any type of upgrade in case of failure.
                Only press YES to continue if you are confident that you will be
                able to recover in case of failure"""

    successWarning = wx.MessageBox(sMessage, "WARNING", wx.YES_NO)
    if (successWarning == wx.YES):
        print "User selected Yes to warning"
    else:
        print "User selected No or cancled"
        sys.exit()

# 2) Validate current user = iwpcadmin
    successIwpcadmin = frame.validateCurrentUser()
    print "iwpcadmin ", successIwpcadmin

# 3) Compile starting variables
    successTempDir = frame.createDir('d:\ssptemp')
    print "TempDir ", successTempDir

    successLogDir = frame.createDir('d:\ssplogs')
    print "LogDir ", successLogDir

# 4) Write PC data to PCinfo.txt
    successServerID = frame.getServerID()
    print "ServerID", successServerID

# 5) Read available from media
    successValidateMedia = frame.validateSSPMedia()
    print "ValidateMedia", successValidateMedia

    testPreReq = [successIwpcadmin,
                  successTempDir,
                  successServerID,
                  successValidateMedia]

    for item in testPreReq:
        if item == False:
            dlg = wx.MessageBox('You have one or more errors and cannot continue',
                                'Error')
        else:
            #frame.btBeginInstall.Enable()
            frame.btValidateInfraSystem.Enable()
            frame.btValidateIwpcSystem.Enable()
            frame.btValidateIwpcSystem.Enable()
            frame.btValidateIwpcIwpcdba.Enable()
            frame.btValidateLdapOc4jadmin.Enable()
            frame.btValidateLdapOrcladmin.Enable()
            frame.btValidateIas_admin.Enable()
            frame.btValidateiwpcadmin.Enable()
            frame.btValidateAll.Enable()            




    app.MainLoop()

2 个答案:

答案 0 :(得分:0)

我没有时间阅读你冗长的代码示例,但我想知道这是臭名昭着的msvcr90.dll问题。我从py2exe列表herehere得到了很好的反馈。

答案 1 :(得分:0)

我使用wxGlade重建代码(原始版本是使用boaConstructor完成的),出于某种原因,它可以工作。我不知道为什么或如何,但确实如此。如果有人有兴趣,我可以根据要求提供新代码。