#1
  1. No Profile Picture
    Registered User
    Devshed Newbie (0 - 499 posts)

    Join Date
    Oct 2012
    Posts
    11
    Rep Power
    0

    Win32Com IE readystate sometimes pushes 'Access Is Denied'


    Have to move homes for my forum help, so I hope to find a happy place here!

    So, after much pain, and searching I have a pretty well working implementation of Win32Com and using Internet Explorer. This issue only started when I actually switched up how I was doing my code by implementing makepy.py to pre-call both the "Microsoft HTML Object Library" and "Microsoft Internet Controls Library". From my google searching every reference to the error I got, is not related to my issue, and I should maky it clear this is only periodic. So, here is what happens:

    Code:
    ie = win32com.client.Dispatch("InternetExplorer.Application")
    ie.Visible = 1
    ie.Navigate("https://myurl.com/software/legal_notice.asp")
    while ie.ReadyState != 4:
        sleep(1)
    while ie.Document.readyState != "complete":
        sleep(1)
    
    #navigate to the home page
    print('Navigate to the Home Page')
    ie.Document.getElementsByName("Submit")[0].click()
    while ie.Document.readyState != "complete":
        sleep(1)
    sid = ie.LocationURL.split('=')[1] #retrieves the current session ID
    print sid
    doc = ie.Document
    mFrame = doc.frames('mainFrame')
    
    #go to the "no company name" report inside the main frame
    print('Go to \"No Comapny Name\" report')
    #guid = 4w19lMzs is for all sites
    mFrame.open('/software/show_report.asp?sid=' + sid +
        '&guid=4w19lMzs&rpt=_Software.Builtin.Versions.No.Company/report.html',
        '_self')
    while mFrame.document.readyState != "complete":
        sleep(1)
    The only thing I made obscure about the code above is the actual URLs, since it would not be accessible anyway to external users for testing. I have no control over the site, as that is handled by someone else, who is leasing software from a 3rd party. So I am making an interface to pull information from the page since their current site is terrible (make what you have work right?) Anyway, the error I get is this:

    Code:
    Traceback (most recent call last):
      File "SoftwareReport.py", line 134, in get_no_company_page
        while mFrame.document.readyState != "complete":
      File "python\lib\site-packages\win32com\client\__init__.py", line 463, in __getattr__
        return self._ApplyTypes_(*args)
      File "python\lib\site-packages\win32com\client\__init__.py", line 456, in _ApplyTypes_
        self._oleobj_.InvokeTypes(dispid, 0, wFlags, retType, argTypes, *args),
    com_error: (-2147024891, 'Access is denied.', None, None)
    (again changed some of the pathing above to avoid self identifying details, but the major pieces of the error is here).

    Two things: One, as I said this does not happen every time. Two, if I debug it almost always avoids the issue. For some reason, I am unable to access/read "mFrame.document.readyState" when the open command seems to go, too fast. I can force correct the problem, by inserting a sleep(n) where n is an arbitrary number to make the program wait BEFORE is tries to check the readystate of the document.

    Because this is Frames (yeah, who uses frames these days?) ie.ReadyState() does not ever update/change away from 4 (which means complete). So adding that in will not help.

    From what I gather the error code indicates a DCOM error, but I don't understand how/why this is happening in my case. Everything I have seen points to an access/permission issue. But if this is the case why does it work sometimes? Why when I give it enough time to load is has no issue either?

    Anyway, been scratching my head at this one, anyone with experience with win32com, "Internet Controls", and "HTML Object Library" would be appreciated! (I did not notice this before forcing the import of HTML OL by the way, however I need this library preloaded for two reasons, one to solidify what methods and properties I can use, and two it speeds up the code by a lot when you are searching through thousands of lines of HTML code - if this is the wrong library for this please point me in the right direction )
  2. #2
  3. No Profile Picture
    Registered User
    Devshed Newbie (0 - 499 posts)

    Join Date
    Oct 2012
    Posts
    11
    Rep Power
    0
    Oh also, my contributions for lost souls like me searching google, maybe they will find this quicker than I did by landing here:

    If you want to import the Libraries for win32com BEFORE the script loads inside your win32com/client directory is a makepy.py file. Run this from the command line using python.exe.

    If, like me, you were still lost after this point, you can output the library file that you build with the -o "filepath" option, then place this somewhere you can get to it, and IMPORT it into your code, like so:

    Code:
    python.exe makepy.py -o "msHTMLLib.py"
    select  "Microsoft HTML Object Library" from the popup
    
    #then import into your script
    import msHTMLLib        # Microsoft HTML Object Library
    import msInetCont       # Microsoft Internet Controls Library
    There is a great reason to do this, instead of building to the temp directory... unfortunately if something happens to the temp, or like me, you leave the code alone for a week, and come back, it seems gencache forgets everything.

    The other alternatives (which I do not recommend) are as follows:
    Code:
    #OPTION 1:
    #from command line:
    >python.exe makepy.py -i "Microsoft Internet Controls"
     {EAB22AC0-30C1-11CF-A7EB-0000C05BAE0B}, lcid=0, major=1, minor=1
     >>> # Use these commands in Python code to auto generate .py support
     >>> from win32com.client import gencache
     >>> gencache.EnsureModule('{EAB22AC0-30C1-11CF-A7EB-0000C05BAE0B}', 0, 1, 1)
    #place suggested code in script:
    from win32com.client import gencache
    gencache.EnsureModule('{EAB22AC0-30C1-11CF-A7EB-0000C05BAE0B}', 0, 1, 1)
    
    #Option 2:
    #OR Just run this everytime instead of using client.Dispatch()
    ie = win32com.client.gencache.EnsureDispatch("InternetExplorer.Application")
    These basically forces a mapping on the fly and can be REALLY slow (especially if trying to debug). By building the file and directly importing it, when you call Dispatch() it will automatically make the association like it should from those directly linked libraries. There is NO difference between you importing the file and win32com calling the file from the gencache (at least not that I have seen)

    Hope this helps!

    And for those completely lost, you can find out what methods an object has using an IDE like PyScripter as it will do the shortcut drop down (during run time only!), and the properties can be obtained by the command: _prop_map_get_.keys()

    EX:
    Code:
    >>> ie = win32com.client.Dispatch("InternetExplorer.Application")
    >>> ie._prop_map_get_.keys()
    ['ReadyState',
     'Busy',
     'Container',
     'Silent',
     'Top',
     'RegisterAsDropTarget',
     'LocationName',
     'Application',
     'Offline',
     'Document',
     'Type',
     'ToolBar',
     'MenuBar',
     'FullScreen',
     'Parent',
     'TheaterMode',
     'Path',
     'Name',
     'RegisterAsBrowser',
     'StatusText',
     'Left',
     'TopLevelContainer',
     'Resizable',
     'Width',
     'StatusBar',
     'HWND',
     'Height',
     'Visible',
     'FullName',
     'LocationURL',
     'AddressBar']
    Both of these helpers are only available if you have the library imported with makepy. Finally you get access to that library's constants. So if you want to tell IE to save a document or print, etc. These are loaded into here:

    Code:
    #output a list:
    win32com.client.constants.__dicts__
    #access a constant by name:
    win32com.client.constants.OLECMDID_SAVE
    #will output the value of 3
    Note: that is a lower case "c" on constants, uppercase "C" is a different thing.

    Anyway, there's the win32com stuff which should push you in the right direction if you can't seem to find what you are looking for... cause good luck using MSDN to get any real help... (the documentation on them are there, though, they are just kind bad... and good luck finding the right one.)
  4. #3
  5. No Profile Picture
    Registered User
    Devshed Newbie (0 - 499 posts)

    Join Date
    Oct 2012
    Posts
    11
    Rep Power
    0
    I did find a workaround, that I have employed, but I would prefer to find the reason why the error occurrs instead of just "accomodating" for it. So any assistance here is still requested.

    Workaround:

    Code:
    mFrame.open('/software/show_report.asp?sid=' + sid +
        '&guid=4w19lMzs&rpt=_Software.Builtin.Versions.No.Company/report.html',
        '_self')
    while True:
        try:
            print "X"
            while mFrame.document.readyState != u"complete":
                sleep(1)
            break
        except:
            continue
    Basically since it needs time to load before readystate even exists I implemented an infinate loop, which will only break AFTER the page is loaded.

    By placing the problem code in a try block, I was able to force it to keep trying to read the variable "readyState" until it exists. Once it does exist, then loop on itself, until readyState is "complete". Finally once readState exists, and equals "complete" then I break the loop.

    The print "X" is for testing, to identify how many tries it takes before success. In most cases (whether because time between events is increased by hitting the loop and the try block, or the webpage is just loading fast enough in general) I was only hitting the try once. The extreme end, I was hitting it twice.

    Why I do not like this implemenation, it is bad coding practices to be happy with letting the program throw errors. Even worse, it is throwing an error which I do not know what is causing the error (I mean I have an idea, but nothing to FIX the error). I was always taught, the only errors to "allow" are ones which are caused by the user. In this case, I am allowing my program to recover from a crash because I don't know why it is crashing... this is a bad solution to me.

    I am happy it works, sad to not know WHY it was a problem to begin with.

    Should mention, to anyone who stumbles on this for whatever reason, what I did above is a very USEFUL technique, in general for handling some kind of "triggered" event. Force an infinite loop which goes until whatever is needed is triggered. Always make sure to have something which will either trigger a break or if it is inside a function (for example) you could end the loop by sending a return statement. Anyway, just a neat trick, I hadn't ever seen posted anywhere else before, and thought I would expand on its usefulness.

IMN logo majestic logo threadwatch logo seochat tools logo