IMAGE-PRO PREMIER 9.2 ERROR -- GDI OBJECT LIMIT EXCEEDED . . .

All --

I wrote a very large and very complicated macro for a customer.

They find that if they run the macro for a long period of time (6 or 8 hours) that their PREMIER SYSTEM crashes.

One of the errors that they see is shown below even though there are no images "open".

In QUESTION 2030 -- Batch processing - Limitations there seems to be mention of a similar issue but I don't see a solution there.

The customer is using PREMIER 9.2.

Should the first step be upgrading one of their 3 systems to 9.3 to see if this is resolved or is there a better first step?

Thanks.

-- Matt

*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-





Answers

  • Hi Matt,

    It looks like some temporary images or objects created by the macro are not closed. You can use CountImages macro from the Debugging project (installed in the Scripts folder) to check if your macro releases all images after processing (load one image, run your macro 2 or 3 times, close the image and check CountImages macro - you should have no images detected).

    If something is created, but not closed by the macro, the program may run out of resources running long batches.

    Yuri

  • 2017-10-26-091236

    Yuri --

    Thank you for the information.

    Is there a way to CLOSE ALL or FLUSH ALL to clean up any GDI OBJECTS that need some extra house keeping done?

    Thanks.

    -- Matt
  • Matt,

    There is a command (recordable) that can close all visible windows/images, but it will not close images that are created invisible or there are references kept in your macro to these images. So you have to be sure that you release all the references to images./documents/windows in the end of your macro (set every variable to Nothing, e.g. "MyTmpImage=Nothing).

    Also, that assumes that MediaCy objects might be leaking. GDI objects may also be leaking if you create and not release some other (non-MediaCy) objects in your code (e.g. Bitmap, Font).

    Yuri

  • 2017-10-27-101646

    Yuri --

    Thanks for the additional information.

    I have closed all of the visible windows/images and have not (to my knowledge) generated any invisible windows/images.

    The connections/references with windows/images are normally defined and created within functions and subroutines.  I would think that they would be released when the subroutine terminates.  Is this not the case?

    I do not believe that I am generating any non-Mediacy objects like BITMAPS or FONTS.

    I believe that the best path forward may be to modify your COUNTIMAGES MACRO so that it runs every 5 seconds or so and shows its results in a dialog box.  We should be able to see where the GDI OBJECT BUILDUP or the LEAK happens.

    Thanks.

    -- Matt
  • 2017-11-06-174245

    Yuri --

    I am working to create a TOOL for the PREMIER CUSTOMER that is having the issue.

    I have opened up and looked at

        Debugging.ipp

    I will set up the

        Sub CountImages()

    so that we can see if there is a FEATURE or FUNCTION of the APP that I wrote that is not performing the correct housekeeping functions.

    Looking through DEBUGGING, I see

        Public Sub GarbageCollect()

    This is not called by any of the other routines so is it a routine that can be used to eliminate UNWANTED GDI OBJECTS?

    Also . . .

    If all of my links to images are generated by variables that are local to subroutines and functions, shouldn't the links evaporate when the subroutines and functions end?

    Thanks.

    -- Matt

  • 2017-11-06-182445

    Yuri --

    I have created a copy of the IPP file that I can modify and I have added a FORM to the PROJECT.

    Within the FORM, I have created a BUTTON.

    Behind the BUTTON I have created the following function

        Private Sub button_CountImages_Click(ByVal sender As System.Object,ByVal e As System.EventArgs) Handles button_CountImages.Click
    
            Dim My_CollectionImagesCount As Integer = 999
            Dim My_AllImagesCount As Integer = 999
    
            Debug.Clear
    
            Call CountImages2(My_CollectionImagesCount,My_AllImagesCount)
    
            Debug.Print ("My_CollectionImagesCount")
            Debug.Print (My_CollectionImagesCount)
    
            Debug.Print ("My_AllImagesCount")
            Debug.Print (My_AllImagesCount)
    
        End Sub

    The COUNTIMAGES2 is a modified version of COUNTIMAGES as shown below.

        Sub CountImages2(CollectionImagesCount As Integer, AllImagesCount As Integer)
    
            Debug.Print ("CollectionImagesCount")
            Debug.Print (CollectionImagesCount)
    
            Debug.Print ("AllImagesCount")
            Debug.Print (AllImagesCount)
    
            With ThisApplication.Engine
                Dim strOutput As String
                Dim lCollectionCount As Integer, lAllImagesCount As Integer
                lCollectionCount = .Images.Count
                strOutput = "---> Images in Images collection: " & CStr(lCollectionCount)
                Dim nI As Integer
                For nI = 0 To lCollectionCount - 1
                    strOutput = strOutput + vbCrLf + CStr(nI) & " Image Name: " & .Images(nI).Name
                Next nI
                .McObjects.SetEnumFilters(mcobjRegCategories.McCatImage, , , , .McObject(.Images))
                lAllImagesCount = .McObjects.Count
                strOutput = strOutput + vbCrLf + "--> All images: " & CStr(lAllImagesCount)
                Dim mcobjImage As McObject, nO As Integer = 0
                For Each mcobjImage In .McObjects
                    'Dim im As McImage = .Images.Item(nO) 'mcobjImage..ShadowMcObject
                    strOutput = strOutput + vbCrLf + CStr(nO) & " McObject Name: " & mcobjImage.Name '& " (" & CType(mcobjImage.ShadowMcObject, McImage).Name '.N.IsCompatibleType("McImage").ToString '.Name '.ParentMcObject.Name '.VectorLength.ToString '.Width & " x " & im.Height & ")"
                    nO = nO + 1
                Next mcobjImage
                'For Each im As McImage In .Images
                '    strOutput = strOutput + vbCrLf + CStr(nO) & " McObject Name: " & im.Name & " (" & im.Width & " x " & im.Height & ")"
                '    nO = nO + 1
                'Next 'mcobjImage
                MsgBox(strOutput, , "CountImages")
    
                CollectionImagesCount = nI
    
                AllImagesCount = nO
    
                Debug.Print ("CollectionImagesCount")
                Debug.Print (CollectionImagesCount)
    
                Debug.Print ("AllImagesCount")
                Debug.Print (AllImagesCount)
    
            End With 'ThisApplication.Engine
        End Sub 'CountImages

    When I press the COUNT IMAGES BUTTON with 2 images open, the MSGBOX that appears is



    and the DEBUG WINDOW contains

    CollectionImagesCount
    999
    AllImagesCount
    999
    CollectionImagesCount
    2
    AllImagesCount
    2
    My_CollectionImagesCount
    999
    My_AllImagesCount
    999


    Why aren't the COUNTS being transferred to
    button_CountImages_Click
    from
    CountImages2
    via
    (My_CollectionImagesCount,My_AllImagesCount)
    and
    (CollectionImagesCount As Integer, AllImagesCount As Integer)

    Thanks.

    -- Matt

  • Hi Matt,

    You have to declare sub parameters as ByRef to receive values, like this:

        Sub CountImages2(ByRef CollectionImagesCount As Integer, ByRef AllImagesCount As Integer)
    

    Yuri

  • Matt,

    Regarding the links in local variables. Yes, the links to local variables should "evaporate" when the sub exits, but they may not "evaporate " immediately, but only when the Windows decides that it needs to clear up the RAM. The call to GarbageCollect forces cleanup immediately, though it may not be necessary.
    Also, the COM objects, such as McImage or McWindow are not GDI objects. GDI objects might be linked to them, so ensuring that all COM objects are released may be a sign that GDI objects are released too. (though GDI objects can be created by something else, e.g. icons, panels, tables,...)

    Yuri

  • 2017-11-07-110707

    Yuri --

    Thank you for the information about

        ByRef

    I have added that to the two VARIABLES on the PARAMETER LIST in
    CountImages2
    and now the VARIABLES are TWO WAY rather than ONE WAY.

    I'll get the COUNT IMAGES stuff wired up to see what is generating the GDI OBJECTS and I'll set up a BUTTON to trigger the
    GarbageCollect
    to see if that will resolve the problem.

    I'll let you know how it goes.

    A thought!

    Would it be "good housekeeping" to set up an equivalent to GARBAGE COLLECT that runs when

        Private Sub MyControl_AppUnloading() Handles MyControl.AppUnloading

    runs to ?

    Thanks.

    -- Matt
  • edited November 2017
    2017-11-07-143555

    Yuri --

    I found out a moment ago that I did not press the POST COMMENT button on the COMMENT tagged 2017-11-07-110707 so I just fixed that.

    I have added a UI to the COUNT IMAGES and GARBAGE COLLECT functions in DEBUGGING.

    I did this via a FORM.

    I have attached the IPX file that I created from this project.

    There seem to be some differences between FORMS and APPS.  One of those differences seems to be keeping my functions that change the BUTTON COLOR and the BUTTON TEXT from appearing on the UI.

    Can you look at this and see if there is a tweak that would allow my CODE to change the BUTTON COLOR or BUTTON TEXT to run so that it shows within the UI when the COUNT IMAGES FUNCTION is running?

    Thanks.

    -- Matt


  • Hi Matt,

    I had some problems loading your IPX file. It looks like you just zipped the project folder and then renamed the ZIP to IPX. So, after extracting the zip to a folder and then loading IPP file the project was loaded correctly and it worked properly.

    The reason that you don't see change of button color and text is that the change is too quick and you restore original color and text in the same call. If you disable restoring the color and text:

            'Restore BUTTON COLOR
            'button_CountImages.BackColor = myorginalcolor
    
            'Change BUTTON TEXT
            'button_CountImages.text = Replace (button_CountImages.text," * * * ","")
    

    you should see the change.

    Yuri
  • 2017-11-08-151849

    Yuri --

    Thank you for your response.

    The IPX FILE was generated by PREMIER 3D.  The version was not 9.3 but may be 9.2.  It is on a computer that is not turned on right now. With the individual files in FOLDER A, I did a

        FILE + PACKAGE + AS PROJECT PACKAGE

    and directed the IPX FILE to be saved in a FOLDER NAMED

        IPX FILE

    within the A FOLDER.

    After generating the IPX FILE, I removed the PROJECT from PREMIER, then rebooted PREMIER and added the PROJECT back to PREMIER from the IPX FILE and everything worked the same as from the individual files.

    A mystery.

    On the BUTTON COLOR and BUTTON TEXT . . .

    I did not consider that the routine was running so fast that the UI would not show some response to the COLOR and TEXT changes.

    Thank you for solving that mystery.

    I have sent the IPX FILE to the customer with the GDI OBJECTS ISSUE.  I'll see if her machine has an issue reading the file also and let you know.

    I may throw a bit of a DELAY into the ROUTINE that includes the COLOR / TEXT CHANGE so that there is an indication on the screen when a COUNT and a GARBAGE COLLECTION is happening.

    I'll create and post a V1B here if I do that.

    Thanks again.

    -- Matt
  • 2017-11-20-193210

    Yuri --

    I attempted to make the BUTTONS change color as shown above but the color change is not reflected on the FORM until the SUB finishes even if there is a WAIT embedded within the SUB.

    I did find that if I embed
            'Refresh FORM to allow the BUTTON COLOR CHANGE to happen
            myform.Refresh
    
            'Pause a SECOND
            Wait (1)
    
    within a sub with

            'Remember BUTTON COLOR
            Dim myorginalcolor = _
                button_A.BackColor
    
            'Change BUTTON COLOR
            button_A.BackColor = _
                System.Drawing.Color.FromArgb(CType(128, Byte),CType(255, Byte),CType(128, Byte))
    
    at the beginning and
            'Reset BUTTON COLOR
            button_A.BackColor = _
                myorginalcolor
    
    at the end then the BUTTON is GREEN while the SUB is active and its ORIGINAL COLOR when the SUB is inactive.

    I hope this information is helpful to you and other folks here on the forum.

    Thanks for your assistance.

    -- Matt
Sign In or Register to comment.