Announcement

Collapse
No announcement yet.

Isolated Error with GdipCreateHBITMAPFromBitmap

Collapse
X
 
  • Filter
  • Time
  • Show
Clear All
new posts

  • Isolated Error with GdipCreateHBITMAPFromBitmap

    I am using GDI+ to load a JPG image and convert it to a bitmap handle I can use in my program. It works perfectly on every computer I have tried it with, but one of my users is receiving an error. Here is a stripped down copy of the code I am using:

    Code:
      LOCAL bm AS BITMAP
      LOCAL hr AS LONG
      LOCAL strFileName AS STRING
      LOCAL pBitmap AS DWORD
      LOCAL hBitmap AS DWORD
      LOCAL token AS DWORD
      LOCAL nStatus AS LONG
      LOCAL StartupInput AS GdiplusStartupInput
      LOCAL nRect AS RECTL
      LOCAL bmpData AS BitmapData
      LOCAL origwidth AS SINGLE
      LOCAL origheight AS SINGLE
    
    
      '** Start GDI+ - Returns 0: Success
    
      StartupInput.GdiplusVersion = 1
      nStatus = GdiplusStartup(token, StartupInput, BYVAL 0)
    
      '** Load the JPG image file - Returns 0: Success
    
      strFilename = UCODE$(f$)
      hr = GdipCreateBitmapFromFile (strFileName, pBitmap)
    
      '** Obtain image dimensions - Returns proper dimensions
    
      l=GdipGetImageDimension (BYVAL pBitmap, BYREF origwidth, BYREF origheight)
    
      '** Get a bitmap handle for the object - Returns error 7: Win32Error
      '** Works fine on every machine I have, but customer machine returns error
    
      hr2=GdipCreateHBITMAPFromBitmap(pBitmap,hBitmap,0)
    Any ideas why she is getting Error 7 for the GdipCreateHBITMAPFromBitmap call? I think she is using Windows Vista Ultimate, but am waiting for her to confirm.

    Thanks,

    Anthony
    Anthony Watson, Mountain Software
    www.mountainsoftware.com

  • #2
    >strFilename = UCODE$(f$)

    I have found that when you use UCODE$(), you don't always get a DOUBLE-null termination, which means the WinAPI functions don't know the string has ended. It does not matter if LEN(string to be converted ) MOD (allocation granularity) <> 1, but if it does you can have sporadic problems.

    Since you are dealing with file names, the length may vary on any user's system.

    You can try 'strFilename = UCODE$(f$ & $NUL)' or 'strFilename = UCODE$(f$) & CHR$(0,0)'
    to ensure the unicode string is unicode-nul-terminated.

    MCM
    Michael Mattias
    Tal Systems (retired)
    Port Washington WI USA
    [email protected]
    http://www.talsystems.com

    Comment


    • #3
      Michael,

      I'm not sure why it would work on my XP and Vista machines and fail on a Vista Ultimate machine, but it's worth a try. Thanks for the suggestion...

      Take care,

      Anthony
      Anthony Watson, Mountain Software
      www.mountainsoftware.com

      Comment


      • #4
        >you don't always get a DOUBLE-null termination

        Wow, that would be serious imo, example?
        hellobasic

        Comment


        • #5
          I don't have any specifics, but I have run into this a couple of times over the years, and I mean going back to PB/DLL version 5.0 and PB/CC 1.0. (For the pre-ACODE$/UCODE$ era, using MultiByteToWideChar())

          Now it's automatic for me do ensure double-null termination by adding $NUL to my source strings so it doesn't happen anymore.

          For all I know the current version of the compiler no longer allows this to happen (and if you think about how the compiler creates its "string" variable types, you know exactly how it can happen).

          I suppose one could manufacture a test by
          Code:
            FOR nCHar = 1 TO Somenumber 
                  s  =   STRING$ (nChar, "X") 
                  u  =   UCODE$(S) 
                  lu  = LstrLenW(BYVAL STRPTR(u) 
                  IF    lu <> Len(s) * 2 THEN 
                      string not created correctly 
                      ......
          Something like that, anyway.

          Well, maybe not "string not created correctly" but "string not created with double-null termination at desired point."

          In any event it's a simple thing to try.
          Last edited by Michael Mattias; 24 Aug 2009, 09:14 AM.
          Michael Mattias
          Tal Systems (retired)
          Port Washington WI USA
          [email protected]
          http://www.talsystems.com

          Comment


          • #6
            Yep, that's something to bear in mind with Windows APIs. They're often going to be expecting UnicodeZ strings, which are Unicode strings with a wide nul character ($NUL + $NUL). UCODE$ just returns a normal Unicode string. If you forget to add the double-null terminator, you may get lucky and have it work anyway, but that's not guaranteed.

            Comment


            • #7
              Which has nothing to do with the problem because the function that is failing, GdipCreateHBITMAPFromBitmap, has not any string parameter. Unfortunately, M$ has chosen to return a generic error (Win32Error), leaving us without a clue.
              Forum: http://www.jose.it-berater.org/smfforum/index.php

              Comment


              • #8
                I suppose one could manufacture a test by

                Code:
                  FOR nCHar = 1 TO Somenumber 
                        s  =   STRING$ (nChar, "X") 
                        u  =   UCODE$(S) 
                        lu  = LstrLenW(BYVAL STRPTR(u) 
                        IF    lu <> Len(s) * 2 THEN 
                            string not created correctly 
                            ......
                Better change it to:

                Code:
                            ......
                        IF    lu <> Len(s) THEN 
                            string not created correctly 
                            ......
                or your test will report that ALL the strings are created incorrectly, since LstrLenW returns the length in wide characters.
                Forum: http://www.jose.it-berater.org/smfforum/index.php

                Comment


                • #9
                  BTW GDI+ uses BSTRs, not unicode asciiz strings, so neither the ending double null nor lstrlenW applies. The length of a BSTR is retrieved using SysStringByteLen, that does the following:

                  Code:
                  UINT WINAPI SysStringByteLen(BSTR str)
                  {
                      DWORD* bufferPointer;
                   
                       if (!str) return 0;
                      /*
                       * The length of the string (in bytes) is contained in a DWORD placed
                       * just before the BSTR pointer
                       */
                      bufferPointer = (DWORD*)str;
                  
                      bufferPointer--;
                  
                      return (int)(*bufferPointer);
                  }
                  Therefore, if the parameter is a BSTR, you don't have to add ending nul(s).
                  Last edited by José Roca; 24 Aug 2009, 05:01 PM.
                  Forum: http://www.jose.it-berater.org/smfforum/index.php

                  Comment


                  • #10
                    >GdipCreateHBITMAPFromBitmap, has not any string parameter

                    I know that. However...
                    Code:
                      strFilename = UCODE$(f$)
                      hr = GdipCreateBitmapFromFile (strFileName, pBitmap)
                    Hr was never interrogated for success or failure before continuing. If StrFileName is "not right" causing this call to fail then all the rest of the calls will fail because pbitmap will be invalid.

                    Come to think of it, I should have simply suggested that hr be checked before willy-nilly proceeding.

                    MCM
                    Michael Mattias
                    Tal Systems (retired)
                    Port Washington WI USA
                    [email protected]
                    http://www.talsystems.com

                    Comment


                    • #11
                      My suggestion is to use:

                      Code:
                      hr2=GdipCreateHBITMAPFromBitmap(pBitmap,hBitmap,0)
                      IF hr2 = 7 THEN hr = GetLastError
                      GetLastError should return the Windows error code.
                      Forum: http://www.jose.it-berater.org/smfforum/index.php

                      Comment


                      • #12
                        "Interrogating return codes" must be a dying art. I'd like a nickel for every time I've seen a request for help here which the poster could have solved had he simply checked either the WinAPI return or the PB "ERR" system variable.
                        Michael Mattias
                        Tal Systems (retired)
                        Port Washington WI USA
                        [email protected]
                        http://www.talsystems.com

                        Comment


                        • #13
                          UCODE$ just returns a normal Unicode string. If you forget to add the double-null terminator, you may get lucky and have it work anyway, but that's not guaranteed.
                          I will try adding the double-null terminator and see if it makes a difference.

                          GetLastError should return the Windows error code.
                          I didn't realize GetLastError would work with GDI+, but will add that to my error logging to see if it reveals any additional clues.

                          Thanks!

                          Anthony
                          Anthony Watson, Mountain Software
                          www.mountainsoftware.com

                          Comment


                          • #14
                            OK, I have a new test version out to the customer and am waiting to hear her results.

                            However, I was testing the subroutine on my own system, and while the GdipCreateHBITMAPFromBitmap() call completes successfully and returns a "successful" status of Zero, the GetLastError() call reports:

                            "Not enough storage is available to process this command."

                            For all other GDI+ calls it reports: "The operation completed successfully."?

                            I have 4 gigs of RAM available, and the task manager shows less than 1 gig is in use. The JPG photo is only 33K, and should be less than 1 Meg as a BMP. I also have over 130Gig free disk space. So, I obviously have plenty of storage space.

                            I will have to wait to hear from the customer, but so far GetLastError() only adds to the confusion... Any ideas?

                            Thanks,

                            Anthony
                            Anthony Watson, Mountain Software
                            www.mountainsoftware.com

                            Comment


                            • #15
                              Calling GetLastError when GdipCreateHBITMAPFromBitmap doesn't return error 7 is useless.
                              Forum: http://www.jose.it-berater.org/smfforum/index.php

                              Comment


                              • #16
                                I will try adding the double-null terminator and see if it makes a difference.
                                At best, it won't make any difference. At worst, it could cause the function to fail because you're passing an string that contains the path and double nuls and has a length longer than the real path.

                                If the parameter is a BSTR, you don't have to add any nuls, because the length is not retrieved by searching for the nuls, but looking at the length prefix that contains it. You have to add nuls if the parameter is an Unicode ASCIIZ string because we are using a BSTR (PB strings are BSTRs) as a workaround since the current version of the compilers doesn't support Unicode ASCIIZ strings.
                                Forum: http://www.jose.it-berater.org/smfforum/index.php

                                Comment


                                • #17
                                  Calling GetLastError when GdipCreateHBITMAPFromBitmap doesn't return error 7 is useless.
                                  Agreed, I just thought it was interesting it did not report a successful operation like other GDI+ calls.

                                  it could cause the function to fail because you're passing an string that contains the path and double nuls and has a length longer than the real path
                                  .

                                  The GdipCreateBitmapFromFile() call asks for a pointer to a null terminated string (no length description), so it shouldn't hurt anything.

                                  Thanks,

                                  Anthony
                                  Anthony Watson, Mountain Software
                                  www.mountainsoftware.com

                                  Comment


                                  • #18
                                    The GdipCreateBitmapFromFile() call asks for a pointer to a null terminated string (no length description), so it shouldn't hurt anything.
                                    Sorry, I thought that the parameter was a BSTR, but I have checked it (should have done it before posting) and it is GDIPCONST WCHAR*.

                                    However, the difference between BSTR and Unicode ASCIIZ strings applies, that is, you should no add nuls when it is a BSTR and you should add them when it is an Unicode ASCIIZ string.
                                    Forum: http://www.jose.it-berater.org/smfforum/index.php

                                    Comment


                                    • #19
                                      OK, I got the error log back from my customer.

                                      GdipCreateHBITMAPFromBitmap() returns error 7 (Win32Error).

                                      When I call GetLastError() to get more detail, it reports "The operation completed successfully".

                                      So which is it, error or no error???

                                      Still baffled...

                                      Anthony
                                      Anthony Watson, Mountain Software
                                      www.mountainsoftware.com

                                      Comment


                                      • #20
                                        Show EXACT code. If it's as Jose showed with the call IMMEDIATELY after the GdipCreate... then something weird is going on.

                                        However, if you did anything between that call and the call to GetLastError you could have upset the value used by GetLastError.

                                        Me, I'd use
                                        Code:
                                         hr =  GdipCreateHbitmap.... (NO EXPRESSIONS OR STRING LITERAL PARAMS, VARS ONLY, NO BYVAL OR BYCOPY OVERRIDES!)
                                         LE  = GetLastError 
                                         IF hr = 7 THEN 
                                              now LE is meaningful
                                         ELSE
                                           deal with other returns 
                                         ...
                                        MCM
                                        Michael Mattias
                                        Tal Systems (retired)
                                        Port Washington WI USA
                                        [email protected]
                                        http://www.talsystems.com

                                        Comment

                                        Working...
                                        X