简体   繁体   中英

Win32 exception upon releasing virtualbox

I'm trying to run Virtualbox within a thread. During the second iteration of the while loop, where the th variable gets reasigned, the app crashes and produces a Win32 exception. This seems to be caused by the release of the vbox and session. My question is how I do I properly release them manually?

Win32 exception occurred releasing IUnknown at 0x035e40b8
Win32 exception occurred releasing IUnknown at 0x04babcb0

The basics of my application (virtualbox from pyvbox and virtualbox sdk)

import virtualbox
import threading
import time


class ThreadExecutor(threading.Thread):
    def __init__(self):
        self.vbox = None
        self.session = None
        self.vm = None
        super().__init__()

    def run(self):
        self.vbox = virtualbox.VirtualBox()
        self.session = virtualbox.Session()
        self.vm = self.vbox.find_machine("Ubuntu")
        self.vm.launch_vm_process(self.session, 'gui', '')

        time.sleep(30)
        if int(self.session.state) == 1:
            print('Boot failed!')
            return
        else:
            print('Powering down')
            self.session.console.power_down()
        print('Operation completed')
        return


if __name__ == '__main__':
    while True:
        print('Input')
        if input():
            th = ThreadExecutor()
            th.start()
            print('Thread started')

            time.sleep(5)
            while th.isAlive():
                print('App running')
                time.sleep(5)
            print('Execution finished')

To release the session reliable you should use a try/except/finally construction like this:

try:
   #Your code
except:
   print("something unexpected happend")
finally:
   self.session.console.power_down()

I modified the code (without running it):

  • Fixing (stuff that wasn't right) and some reorganizing
  • Additional printing

in order to work and debug the issue (with no intention to fix it whatsoever - at least not at this stage).

code.py :

#!/usr/bin/env python3

import sys
import virtualbox
import threading
import time


DEFAULT_DEBUG_MSG_INDENT = "    "


def debug(text, indent_count, indent=DEFAULT_DEBUG_MSG_INDENT, leading_eoln_count=0):
    print("{:s}{:s}[TID: {:06d}]: {:s}".format("\n" * leading_eoln_count, indent * indent_count, threading.get_ident(), text))


class ThreadExecutor(threading.Thread):
    def __init__(self):
        super().__init__()
        self.vbox = virtualbox.VirtualBox()
        self.session = virtualbox.Session()
        if not self.vbox or not self.session:
            raise RuntimeError("virtualbox initialization failed")
        self.vm = self.vbox.find_machine("Ubuntu")
        if not self.vm:
            raise ValueError("VM not found")

    def run(self):
        start_wait_time = 15
        debug("Starting VM...", 1)
        self.vm.launch_vm_process(self.session, "gui", "")
        debug("Sleeping {:d} secs...".format(start_wait_time), 1)
        time.sleep(start_wait_time)
        if int(self.session.state) == 1:
            debug("Boot failed!", 1)
            return
        else:
            debug("Powering down", 1)
            self.session.console.power_down()
        debug("Operation completed", 1)


def run(threaded=True):
    debug("RUNNING with{:s} threads".format("" if threaded else "out"), 0, leading_eoln_count=1)
    sleep_time = 5
    while input("{:s}Press ANY key followed by ENTER to continue, ENTER ONLY to queet: ".format(DEFAULT_DEBUG_MSG_INDENT)):
        th = ThreadExecutor()
        if threaded:
            debug("Starting thread...", 0)
            th.start()
            debug("Thread started", 1)
            time.sleep(sleep_time)
            while th.isAlive():
                debug("App running", 1)
                time.sleep(sleep_time)
        else:
            debug("Running...", 0)
            th.run()
        debug("Execution finished", 1)
    debug("Done", 0)


def main():
    run(threaded=False)
    run()


if __name__ == "__main__":
    print("Python {:s} on {:s}\n".format(sys.version, sys.platform))
    main()

and it worked!!!

Output :

 (py35x64_test) e:\\Work\\Dev\\StackOverflow\\q051136288>"e:\\Work\\Dev\\VEnvs\\py35x64_test\\Scripts\\python.exe" code.py Python 3.5.4 (v3.5.4:3f56838, Aug 8 2017, 02:17:05) [MSC v.1900 64 bit (AMD64)] on win32 [TID: 036256]: RUNNING without threads Press ANY key followed by ENTER to continue, ENTER ONLY to queet: a [TID: 036256]: Running... [TID: 036256]: Starting VM... [TID: 036256]: Sleeping 15 secs... [TID: 036256]: Powering down [TID: 036256]: Operation completed [TID: 036256]: Execution finished Press ANY key followed by ENTER to continue, ENTER ONLY to queet: a [TID: 036256]: Running... [TID: 036256]: Starting VM... [TID: 036256]: Sleeping 15 secs... [TID: 036256]: Powering down [TID: 036256]: Operation completed [TID: 036256]: Execution finished Press ANY key followed by ENTER to continue, ENTER ONLY to queet: [TID: 036256]: Done [TID: 036256]: RUNNING with threads Press ANY key followed by ENTER to continue, ENTER ONLY to queet: a [TID: 036256]: Starting thread... [TID: 038520]: Starting VM... [TID: 036256]: Thread started [TID: 038520]: Sleeping 15 secs... [TID: 036256]: App running [TID: 036256]: App running [TID: 036256]: App running [TID: 038520]: Powering down [TID: 038520]: Operation completed [TID: 036256]: Execution finished Press ANY key followed by ENTER to continue, ENTER ONLY to queet: a [TID: 036256]: Starting thread... [TID: 028884]: Starting VM... [TID: 036256]: Thread started [TID: 028884]: Sleeping 15 secs... [TID: 036256]: App running [TID: 036256]: App running [TID: 036256]: App running [TID: 028884]: Powering down [TID: 028884]: Operation completed [TID: 036256]: Execution finished Press ANY key followed by ENTER to continue, ENTER ONLY to queet: [TID: 036256]: Done 

Original code was throwing (only relevant part):

pywintypes.com_error: (-2147221008, 'CoInitialize has not been called.', None, None)

I suspected that moving virualbox init stuff in the initializer might be responsible for the behavior change (although as I was saying, I only moved the code because I considered the initializer the right place for it) - that was correct: moving the code back in run triggered the exception again.

After a brief inspection of virtualbox and vboxapi code, I think it has something to do with the place (thread) where CoInitializeEx takes place, but I can't put my finger on it.

I also tried to call the function manually ( pythoncom.CoInitializeEx(0) ) in the main block, but import pythoncom alone was triggering the exception to appear in the 1 st iteration.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM