Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • World
  • Users
  • Groups
Skins
  • Light
  • Cerulean
  • Cosmo
  • Flatly
  • Journal
  • Litera
  • Lumen
  • Lux
  • Materia
  • Minty
  • Morph
  • Pulse
  • Sandstone
  • Simplex
  • Sketchy
  • Spacelab
  • United
  • Yeti
  • Zephyr
  • Dark
  • Cyborg
  • Darkly
  • Quartz
  • Slate
  • Solar
  • Superhero
  • Vapor

  • Default (No Skin)
  • No Skin
Collapse
Code Project
  1. Home
  2. General Programming
  3. Managed C++/CLI
  4. Saving Bitmap image data to HGLOBAL [modified]

Saving Bitmap image data to HGLOBAL [modified]

Scheduled Pinned Locked Moved Managed C++/CLI
graphicscsharpwinformsdebuggingperformance
34 Posts 3 Posters 0 Views 1 Watching
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • A alleyes 0

    I'm trying to take existing Bitmaps images in memory and save (or copy)the bits data to an HGLOBAL. Is this possible using .NET classes? The Bitmap images in memory use the System::Drawing::Bitmap classes not the GDI+ version. I can use some of the GDI+ methods if needed but wanted to state the Images originate from the non GDI+ kind. I've tried the LockBits function but the data that is extracted does not appear proper when viewed in the debugger. I think it's missing the BITMAPINFOHEADER data. Has anyone done anything like this? It's sort of a reverse of creating an image starting from HGLOBAL and going through the steps to the resulting image.

    modified on Tuesday, January 19, 2010 4:28 PM

    A Offline
    A Offline
    Andreoli Carlo
    wrote on last edited by
    #2

    Actually the lockbits and it's methods give you the opportunity to get the raw information of the bitmap stored sequentially from position Scan0, each line length have a certain Stride dimension and the information is stored according to PixelFormat. http://www.bobpowell.net/lockingbits.htm[^]
    Usually this method is used for fast access to the bitmap so you can easyle manipulate the data within it or copy the data to other portion of memory (marshall copy).
    If you need also the header you can easily create it by yourself...see http://en.wikipedia.org/wiki/BMP_file_format[^]

    modified on Wednesday, January 20, 2010 3:07 AM

    A 1 Reply Last reply
    0
    • A Andreoli Carlo

      Actually the lockbits and it's methods give you the opportunity to get the raw information of the bitmap stored sequentially from position Scan0, each line length have a certain Stride dimension and the information is stored according to PixelFormat. http://www.bobpowell.net/lockingbits.htm[^]
      Usually this method is used for fast access to the bitmap so you can easyle manipulate the data within it or copy the data to other portion of memory (marshall copy).
      If you need also the header you can easily create it by yourself...see http://en.wikipedia.org/wiki/BMP_file_format[^]

      modified on Wednesday, January 20, 2010 3:07 AM

      A Offline
      A Offline
      alleyes 0
      wrote on last edited by
      #3

      Thanks for replying. The problem with this is that I don't need any access to the bit's except to make a reference to it for calling a Save method. There seems to me to be more utility in the GDI+ functions than there are in the .NET classes. Since I am starting out with a .NET image, I would like to stay with the appropriate classes. I know the Global functions are deprecated, but the means of which the images are acquired, are with legacy code in ActiveX controls so Global functions are appropriate. If need be, I'll use GDI+, but not sure how to get there.

      A 1 Reply Last reply
      0
      • A alleyes 0

        Thanks for replying. The problem with this is that I don't need any access to the bit's except to make a reference to it for calling a Save method. There seems to me to be more utility in the GDI+ functions than there are in the .NET classes. Since I am starting out with a .NET image, I would like to stay with the appropriate classes. I know the Global functions are deprecated, but the means of which the images are acquired, are with legacy code in ActiveX controls so Global functions are appropriate. If need be, I'll use GDI+, but not sure how to get there.

        A Offline
        A Offline
        Andreoli Carlo
        wrote on last edited by
        #4

        maybe i don't get the problem but this is waht i understand from your explanation you want to have a pointer to a memory segment which contains bmp header + bmp data row right? if yes you can do so 1) create a pointer of dimension 54+RowSize*Height*3 bytes (a classic 24 bit rgb) example: array ^memoryData=gcnew array<Byte>(54 + RowSize*Height*3); pin_ptr<unsigned char>tmpP1 = &memoryData[0]; unsigned char *np1 = tmpP1; 2) create you personal 54 byte header (http://en.wikipedia.org/wiki/BMP_file_format[^]) or find googling someone that have already done it 3) copy the header in the first part of the memory...use marshall copy and copy to the location memoryData[0] 4) lockbit the image and copy the raw information using marshall copy and copy to the location memoryData[54] the trick is done if i have understand your real problem

        A 2 Replies Last reply
        0
        • A Andreoli Carlo

          maybe i don't get the problem but this is waht i understand from your explanation you want to have a pointer to a memory segment which contains bmp header + bmp data row right? if yes you can do so 1) create a pointer of dimension 54+RowSize*Height*3 bytes (a classic 24 bit rgb) example: array ^memoryData=gcnew array<Byte>(54 + RowSize*Height*3); pin_ptr<unsigned char>tmpP1 = &memoryData[0]; unsigned char *np1 = tmpP1; 2) create you personal 54 byte header (http://en.wikipedia.org/wiki/BMP_file_format[^]) or find googling someone that have already done it 3) copy the header in the first part of the memory...use marshall copy and copy to the location memoryData[0] 4) lockbit the image and copy the raw information using marshall copy and copy to the location memoryData[54] the trick is done if i have understand your real problem

          A Offline
          A Offline
          alleyes 0
          wrote on last edited by
          #5

          I guess I failed to explain better. I have one HGLOBAL. This is used to create an image of type System::Drawing::Bitmap. HGLOBAL hdl = GloabalAlloc(BitmapImageSize); PBITMMAPINFOHEADER bmih = (PBITMAPINFOHEADER)GlobalLock(hdl); LPDWORD ImgBits = (LPDWORD)(bmih + sizeof(BITMAPINFOHEADER)); .... .... .... StretchDIBits()...... That gives me an image from an HGLOBAL If I had an image already in memory, from some other means (loaded from file maybe), I want to then point that image to the HGLOBAL. Hope that was clearer

          1 Reply Last reply
          0
          • A Andreoli Carlo

            maybe i don't get the problem but this is waht i understand from your explanation you want to have a pointer to a memory segment which contains bmp header + bmp data row right? if yes you can do so 1) create a pointer of dimension 54+RowSize*Height*3 bytes (a classic 24 bit rgb) example: array ^memoryData=gcnew array<Byte>(54 + RowSize*Height*3); pin_ptr<unsigned char>tmpP1 = &memoryData[0]; unsigned char *np1 = tmpP1; 2) create you personal 54 byte header (http://en.wikipedia.org/wiki/BMP_file_format[^]) or find googling someone that have already done it 3) copy the header in the first part of the memory...use marshall copy and copy to the location memoryData[0] 4) lockbit the image and copy the raw information using marshall copy and copy to the location memoryData[54] the trick is done if i have understand your real problem

            A Offline
            A Offline
            alleyes 0
            wrote on last edited by
            #6

            OK thanks for that. How then do you copy that to HGLOBAL?

            1 Reply Last reply
            0
            • A alleyes 0

              I'm trying to take existing Bitmaps images in memory and save (or copy)the bits data to an HGLOBAL. Is this possible using .NET classes? The Bitmap images in memory use the System::Drawing::Bitmap classes not the GDI+ version. I can use some of the GDI+ methods if needed but wanted to state the Images originate from the non GDI+ kind. I've tried the LockBits function but the data that is extracted does not appear proper when viewed in the debugger. I think it's missing the BITMAPINFOHEADER data. Has anyone done anything like this? It's sort of a reverse of creating an image starting from HGLOBAL and going through the steps to the resulting image.

              modified on Tuesday, January 19, 2010 4:28 PM

              M Offline
              M Offline
              Mark Salsbery
              wrote on last edited by
              #7

              alleyes wrote:

              The Bitmap images in memory use the System::Drawing::Bitmap classes not the GDI+ version.

              System.Drawing IS the managed version of GDI+. It's using GDI+ in its implementation. So your images ARE GDI+ images. Why do you need to use an HGLOBAL in a managed application? If you need old school GDI BITMAPINFOHEADER stuff you can certainly construct that info yourself from info in your GDI+ System.Drawing.Bitmap objects. For example, to extract 24bpp image data from a System.Drawing.Bitmap:

              using namespace System::Drawing;
              using namespace System::Drawing::Imaging;

              Bitmap ^bmp = ...;

              Rectangle rect = Rectangle(0, 0, bmp->Width, bmp->Height);
              BitmapData ^bmpData = bmp->LockBits(rect, ImageLockMode::Read, PixelFormat::Format24bppRgb);

              BITMAPINFOHEADER bmiHeader;
              bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
              bmiHeader.biWidth = bmp->Width;
              bmiHeader.biHeight = bmp->Height;
              bmiHeader.biPlanes = 1;
              bmiHeader.biBitCount = 24;
              bmiHeader.biCompression = BI_RGB;
              bmiHeader.biSizeImage = abs(bmpData->Stride) * bmpData->Height;
              bmiHeader.biXPelsPerMeter = 0;
              bmiHeader.biYPelsPerMeter = 0;
              bmiHeader.biClrUsed = 0;
              bmiHeader.biClrImportant = 0;

              bmp->UnlockBits(bmpData);

              Mark Salsbery Microsoft MVP - Visual C++ :java:

              A 2 Replies Last reply
              0
              • M Mark Salsbery

                alleyes wrote:

                The Bitmap images in memory use the System::Drawing::Bitmap classes not the GDI+ version.

                System.Drawing IS the managed version of GDI+. It's using GDI+ in its implementation. So your images ARE GDI+ images. Why do you need to use an HGLOBAL in a managed application? If you need old school GDI BITMAPINFOHEADER stuff you can certainly construct that info yourself from info in your GDI+ System.Drawing.Bitmap objects. For example, to extract 24bpp image data from a System.Drawing.Bitmap:

                using namespace System::Drawing;
                using namespace System::Drawing::Imaging;

                Bitmap ^bmp = ...;

                Rectangle rect = Rectangle(0, 0, bmp->Width, bmp->Height);
                BitmapData ^bmpData = bmp->LockBits(rect, ImageLockMode::Read, PixelFormat::Format24bppRgb);

                BITMAPINFOHEADER bmiHeader;
                bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
                bmiHeader.biWidth = bmp->Width;
                bmiHeader.biHeight = bmp->Height;
                bmiHeader.biPlanes = 1;
                bmiHeader.biBitCount = 24;
                bmiHeader.biCompression = BI_RGB;
                bmiHeader.biSizeImage = abs(bmpData->Stride) * bmpData->Height;
                bmiHeader.biXPelsPerMeter = 0;
                bmiHeader.biYPelsPerMeter = 0;
                bmiHeader.biClrUsed = 0;
                bmiHeader.biClrImportant = 0;

                bmp->UnlockBits(bmpData);

                Mark Salsbery Microsoft MVP - Visual C++ :java:

                A Offline
                A Offline
                alleyes 0
                wrote on last edited by
                #8

                Let me clarify what I said and thanks for correcting that Yes you are correct. I was just pointing out that the Images were using the managed version classes. What I hope to accomplish is: I have one HGLOBAL. This is used to create an image of type System::Drawing::Bitmap. HGLOBAL hdl = GloabalAlloc(BitmapImageSize); PBITMMAPINFOHEADER bmih = (PBITMAPINFOHEADER)GlobalLock(hdl); LPDWORD ImgBits = (LPDWORD)(bmih + sizeof(BITMAPINFOHEADER)); .... .... .... StretchDIBits()...... That gives me an image from an HGLOBAL If I had an image already in memory, from some other means (loaded from file maybe), I want to then point that image to the HGLOBAL. The reason for using those deprecated function is the type that is returned from functions in ActiveX controls that handle image acquisition is of HGLOBAL. It is then convenient to use those Global functions and since I am doing a mixed mode app thanks in large part to using C++/CLI I can do this.

                M 1 Reply Last reply
                0
                • A alleyes 0

                  Let me clarify what I said and thanks for correcting that Yes you are correct. I was just pointing out that the Images were using the managed version classes. What I hope to accomplish is: I have one HGLOBAL. This is used to create an image of type System::Drawing::Bitmap. HGLOBAL hdl = GloabalAlloc(BitmapImageSize); PBITMMAPINFOHEADER bmih = (PBITMAPINFOHEADER)GlobalLock(hdl); LPDWORD ImgBits = (LPDWORD)(bmih + sizeof(BITMAPINFOHEADER)); .... .... .... StretchDIBits()...... That gives me an image from an HGLOBAL If I had an image already in memory, from some other means (loaded from file maybe), I want to then point that image to the HGLOBAL. The reason for using those deprecated function is the type that is returned from functions in ActiveX controls that handle image acquisition is of HGLOBAL. It is then convenient to use those Global functions and since I am doing a mixed mode app thanks in large part to using C++/CLI I can do this.

                  M Offline
                  M Offline
                  Mark Salsbery
                  wrote on last edited by
                  #9

                  alleyes wrote:

                  I want to then point that image to the HGLOBAL.

                  What does that mean? You don't point something to an HGLOBAL. You can allocate memory as an HGLOBAL and copy data into that memory, just like you did using an array in the thread below.

                  Mark Salsbery Microsoft MVP - Visual C++ :java:

                  A 1 Reply Last reply
                  0
                  • M Mark Salsbery

                    alleyes wrote:

                    I want to then point that image to the HGLOBAL.

                    What does that mean? You don't point something to an HGLOBAL. You can allocate memory as an HGLOBAL and copy data into that memory, just like you did using an array in the thread below.

                    Mark Salsbery Microsoft MVP - Visual C++ :java:

                    A Offline
                    A Offline
                    alleyes 0
                    wrote on last edited by
                    #10

                    I have ONE store of heap memory with a handle to it - HGLOBAL. What I am not articulating adequately is that instead of creating a new memory block, I would like to use a common one if that's at all possible with what I described. Is that possible using the LockBits method? Like I said previously, I have one block of heap space and assign that to one image from a picture box. I have actually two picturebox objects on my form and want to the ability to copy the image from the second picturebox to the main heap store that was allocated. This is what I feel is the disconnect.

                    M 1 Reply Last reply
                    0
                    • M Mark Salsbery

                      alleyes wrote:

                      The Bitmap images in memory use the System::Drawing::Bitmap classes not the GDI+ version.

                      System.Drawing IS the managed version of GDI+. It's using GDI+ in its implementation. So your images ARE GDI+ images. Why do you need to use an HGLOBAL in a managed application? If you need old school GDI BITMAPINFOHEADER stuff you can certainly construct that info yourself from info in your GDI+ System.Drawing.Bitmap objects. For example, to extract 24bpp image data from a System.Drawing.Bitmap:

                      using namespace System::Drawing;
                      using namespace System::Drawing::Imaging;

                      Bitmap ^bmp = ...;

                      Rectangle rect = Rectangle(0, 0, bmp->Width, bmp->Height);
                      BitmapData ^bmpData = bmp->LockBits(rect, ImageLockMode::Read, PixelFormat::Format24bppRgb);

                      BITMAPINFOHEADER bmiHeader;
                      bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
                      bmiHeader.biWidth = bmp->Width;
                      bmiHeader.biHeight = bmp->Height;
                      bmiHeader.biPlanes = 1;
                      bmiHeader.biBitCount = 24;
                      bmiHeader.biCompression = BI_RGB;
                      bmiHeader.biSizeImage = abs(bmpData->Stride) * bmpData->Height;
                      bmiHeader.biXPelsPerMeter = 0;
                      bmiHeader.biYPelsPerMeter = 0;
                      bmiHeader.biClrUsed = 0;
                      bmiHeader.biClrImportant = 0;

                      bmp->UnlockBits(bmpData);

                      Mark Salsbery Microsoft MVP - Visual C++ :java:

                      A Offline
                      A Offline
                      alleyes 0
                      wrote on last edited by
                      #11

                      I know that I can create from scratch the BITMAPINFOHEADER. Is it a matter of copying the information to the top of the Bitmap array?

                      M 1 Reply Last reply
                      0
                      • A alleyes 0

                        I have ONE store of heap memory with a handle to it - HGLOBAL. What I am not articulating adequately is that instead of creating a new memory block, I would like to use a common one if that's at all possible with what I described. Is that possible using the LockBits method? Like I said previously, I have one block of heap space and assign that to one image from a picture box. I have actually two picturebox objects on my form and want to the ability to copy the image from the second picturebox to the main heap store that was allocated. This is what I feel is the disconnect.

                        M Offline
                        M Offline
                        Mark Salsbery
                        wrote on last edited by
                        #12

                        The HGLOBAL is just a handle to an allocated block of memory (a BYTE array). You get a pointer to that block of memory with GlobalLock(). You can copy whatever you want to it. It's up to you to make sure that block is large enough to hold what you write to it.

                        Mark Salsbery Microsoft MVP - Visual C++ :java:

                        A 1 Reply Last reply
                        0
                        • A alleyes 0

                          I know that I can create from scratch the BITMAPINFOHEADER. Is it a matter of copying the information to the top of the Bitmap array?

                          M Offline
                          M Offline
                          Mark Salsbery
                          wrote on last edited by
                          #13

                          alleyes wrote:

                          Is it a matter of copying the information to the top of the Bitmap array?

                          If that's where you want it, yes. You could also start with a pointer to where you want it so you don't have to copy afterwards... BITMAPINFOHEADER *pbmiHeader = (BITMAPINFOHEADER *)GlobalLock(myhglobal); pbmiHeader->biSize = sizeof(BITMAPINFOHEADER); etc...

                          Mark Salsbery Microsoft MVP - Visual C++ :java:

                          A 1 Reply Last reply
                          0
                          • M Mark Salsbery

                            The HGLOBAL is just a handle to an allocated block of memory (a BYTE array). You get a pointer to that block of memory with GlobalLock(). You can copy whatever you want to it. It's up to you to make sure that block is large enough to hold what you write to it.

                            Mark Salsbery Microsoft MVP - Visual C++ :java:

                            A Offline
                            A Offline
                            alleyes 0
                            wrote on last edited by
                            #14

                            Mark Salsbery wrote:

                            You get a pointer to that block of memory with GlobalLock().

                            That's what I meant by pointer but mis-construed it a bit. To summarize then. I can copy the bitmap data to this HGLOBAL using managed Bitmap classes? I do have the advantage of BITMAPINFOHEADER being available from the image that is to be copied from so I have most of that information which happens to be common to both the images in question If copying to the memory block is the lock still in place or do you call an GlobalUnLock first.

                            M 1 Reply Last reply
                            0
                            • M Mark Salsbery

                              alleyes wrote:

                              Is it a matter of copying the information to the top of the Bitmap array?

                              If that's where you want it, yes. You could also start with a pointer to where you want it so you don't have to copy afterwards... BITMAPINFOHEADER *pbmiHeader = (BITMAPINFOHEADER *)GlobalLock(myhglobal); pbmiHeader->biSize = sizeof(BITMAPINFOHEADER); etc...

                              Mark Salsbery Microsoft MVP - Visual C++ :java:

                              A Offline
                              A Offline
                              alleyes 0
                              wrote on last edited by
                              #15

                              Mark Salsbery wrote:

                              If that's where you want it, yes.

                              Well actually the file header will be at top but I get it.

                              Mark Salsbery wrote:

                              BITMAPINFOHEADER *pbmiHeader = (BITMAPINFOHEADER *)GlobalLock(myhglobal); pbmiHeader->biSize = sizeof(BITMAPINFOHEADER);

                              That's helpful...

                              1 Reply Last reply
                              0
                              • A alleyes 0

                                Mark Salsbery wrote:

                                You get a pointer to that block of memory with GlobalLock().

                                That's what I meant by pointer but mis-construed it a bit. To summarize then. I can copy the bitmap data to this HGLOBAL using managed Bitmap classes? I do have the advantage of BITMAPINFOHEADER being available from the image that is to be copied from so I have most of that information which happens to be common to both the images in question If copying to the memory block is the lock still in place or do you call an GlobalUnLock first.

                                M Offline
                                M Offline
                                Mark Salsbery
                                wrote on last edited by
                                #16

                                alleyes wrote:

                                I can copy the bitmap data to this HGLOBAL using managed Bitmap classes?

                                You can't directly copy from managed to unmanaged memory. You can use Marshal::Copy though. You can also wrap the pointer in an UnmanagedMemoryStream object so you can use any managed functionality that uses a Stream object. For example, you could write a BMP file from a Bitmap to memory in one line of code instead of building the headers manually.

                                alleyes wrote:

                                If copying to the memory block is the lock still in place or do you call an GlobalUnLock first.

                                You use the pointer while it's locked.

                                Mark Salsbery Microsoft MVP - Visual C++ :java:

                                A 2 Replies Last reply
                                0
                                • M Mark Salsbery

                                  alleyes wrote:

                                  I can copy the bitmap data to this HGLOBAL using managed Bitmap classes?

                                  You can't directly copy from managed to unmanaged memory. You can use Marshal::Copy though. You can also wrap the pointer in an UnmanagedMemoryStream object so you can use any managed functionality that uses a Stream object. For example, you could write a BMP file from a Bitmap to memory in one line of code instead of building the headers manually.

                                  alleyes wrote:

                                  If copying to the memory block is the lock still in place or do you call an GlobalUnLock first.

                                  You use the pointer while it's locked.

                                  Mark Salsbery Microsoft MVP - Visual C++ :java:

                                  A Offline
                                  A Offline
                                  alleyes 0
                                  wrote on last edited by
                                  #17

                                  Mark Salsbery wrote:

                                  You can't directly copy from managed to unmanaged memory. You can use Marshal::Copy though

                                  I fully intended using the Marshal class for copying.

                                  Mark Salsbery wrote:

                                  You can also wrap the pointer in an UnmanagedMemoryStream object so you can use any managed functionality that uses a Stream object.

                                  Now you threw me a bit. One of the things I was considering was saving the image to a managed memory stream object. Why consider unmanaged? By calling the Save method and then specifying BMP as the image type, I do get the BITMAPHEADERINFO. This is what I'm building upon without doing the Save to Stream technique:

                                  		System::Drawing::Rectangle imgRect = 
                                  			System::Drawing::Rectangle(0, 0, 
                                  			MyImage->Width, MyImage->Height);
                                  		System::Drawing::Imaging::BitmapData^ bmpData =
                                  			MyImage->LockBits(imgRect, 
                                  			System::Drawing::Imaging::ImageLockMode::ReadOnly,
                                  			System::Drawing::Imaging::PixelFormat::Format32bppRgb);
                                  		int byteCount = bmpData->Stride \* MyImage->Height;
                                  		array<Byte>^ bmpBytes = gcnew array<Byte>(byteCount);
                                  		Marshal::Copy(bmpData->Scan0, bmpBytes, 0, byteCount);
                                  		MyImage->UnlockBits(bmpData);
                                  

                                  Once I have the image in an array shouldn't I be copying it to the HGLOBAL? Or should the destination be the HGLOBAL and forget about the array?

                                  modified on Wednesday, January 20, 2010 2:42 PM

                                  1 Reply Last reply
                                  0
                                  • M Mark Salsbery

                                    alleyes wrote:

                                    I can copy the bitmap data to this HGLOBAL using managed Bitmap classes?

                                    You can't directly copy from managed to unmanaged memory. You can use Marshal::Copy though. You can also wrap the pointer in an UnmanagedMemoryStream object so you can use any managed functionality that uses a Stream object. For example, you could write a BMP file from a Bitmap to memory in one line of code instead of building the headers manually.

                                    alleyes wrote:

                                    If copying to the memory block is the lock still in place or do you call an GlobalUnLock first.

                                    You use the pointer while it's locked.

                                    Mark Salsbery Microsoft MVP - Visual C++ :java:

                                    A Offline
                                    A Offline
                                    alleyes 0
                                    wrote on last edited by
                                    #18

                                    I think I have the solution:

                                    MemoryStream^ ms = gcnew MemoryStream();
                                    MyImage->Save(ms, System::Drawing::Imaging::ImageFormat::Bmp);
                                    array<Byte>^ bits = gcnew array<Byte>(MyHeader->biSizeImage);
                                    bits = ms->GetBuffer();
                                    ms->Close();
                                    Marshal::Copy(bits, 0, static_cast<IntPtr>(MyHGlobal), bits->Length);

                                    Where: MyHeader->biSizeImage is the member from the BITMAPINFOHEADER MyHGlobal is the handle to the locked memory block. I then throw an AccessViolationException at the copy call. I think that perhaps the array size may be bigger than the memory block. I appreciate your help so far - I'm close!

                                    M 1 Reply Last reply
                                    0
                                    • A alleyes 0

                                      I think I have the solution:

                                      MemoryStream^ ms = gcnew MemoryStream();
                                      MyImage->Save(ms, System::Drawing::Imaging::ImageFormat::Bmp);
                                      array<Byte>^ bits = gcnew array<Byte>(MyHeader->biSizeImage);
                                      bits = ms->GetBuffer();
                                      ms->Close();
                                      Marshal::Copy(bits, 0, static_cast<IntPtr>(MyHGlobal), bits->Length);

                                      Where: MyHeader->biSizeImage is the member from the BITMAPINFOHEADER MyHGlobal is the handle to the locked memory block. I then throw an AccessViolationException at the copy call. I think that perhaps the array size may be bigger than the memory block. I appreciate your help so far - I'm close!

                                      M Offline
                                      M Offline
                                      Mark Salsbery
                                      wrote on last edited by
                                      #19

                                      I said UnmanagedMemoryStream, not MemoryStream. And you don't cast an HGLOBAL to a pointer - GlobalLock returns the pointer. And Bitmap::Save() saves everything - BITMAPFILEHEADER, BITMAPINFO, and the pixel bits. You're trying to make it harder than it is :)

                                      void *pMyGlobalMemory = GlobalLock(MyHGlobal);
                                      UnmanagedMemoryStream^ ms = gcnew UnmanagedMemoryStream(IntPtr(pMyGlobalMemory), GlobalSize(MyHGlobal));
                                      MyImage->Save(ms, System::Drawing::Imaging::ImageFormat::Bmp);
                                      GlobalUnlock(MyHGlobal);

                                      Mark Salsbery Microsoft MVP - Visual C++ :java:

                                      A 2 Replies Last reply
                                      0
                                      • M Mark Salsbery

                                        I said UnmanagedMemoryStream, not MemoryStream. And you don't cast an HGLOBAL to a pointer - GlobalLock returns the pointer. And Bitmap::Save() saves everything - BITMAPFILEHEADER, BITMAPINFO, and the pixel bits. You're trying to make it harder than it is :)

                                        void *pMyGlobalMemory = GlobalLock(MyHGlobal);
                                        UnmanagedMemoryStream^ ms = gcnew UnmanagedMemoryStream(IntPtr(pMyGlobalMemory), GlobalSize(MyHGlobal));
                                        MyImage->Save(ms, System::Drawing::Imaging::ImageFormat::Bmp);
                                        GlobalUnlock(MyHGlobal);

                                        Mark Salsbery Microsoft MVP - Visual C++ :java:

                                        A Offline
                                        A Offline
                                        alleyes 0
                                        wrote on last edited by
                                        #20

                                        I get an error when trying that: Error C2664: 'System::IO::UnmanagedMemoryStream::UnmanagedMemoryStream(unsigned char *,__int64)' : cannot convert parameter 1 from 'System::IntPtr' to 'unsigned char *' I didn't consider the UnmanagedMemoryStream

                                        Mark Salsbery wrote:

                                        You're trying to make it harder than it is Smile

                                        Yeah it seems that way :doh:

                                        M 1 Reply Last reply
                                        0
                                        • A alleyes 0

                                          I get an error when trying that: Error C2664: 'System::IO::UnmanagedMemoryStream::UnmanagedMemoryStream(unsigned char *,__int64)' : cannot convert parameter 1 from 'System::IntPtr' to 'unsigned char *' I didn't consider the UnmanagedMemoryStream

                                          Mark Salsbery wrote:

                                          You're trying to make it harder than it is Smile

                                          Yeah it seems that way :doh:

                                          M Offline
                                          M Offline
                                          Mark Salsbery
                                          wrote on last edited by
                                          #21

                                          Oops wrong constructor :)

                                          unsigned char *pMyGlobalMemory = (unsigned char *)GlobalLock(MyHGlobal);
                                          UnmanagedMemoryStream^ ms = gcnew UnmanagedMemoryStream(pMyGlobalMemory, GlobalSize(MyHGlobal));

                                          Note you're still resonsible for making sure the allocated global memory is large enough to write to. GlobalSize() will give you the allocated size, but if you don't know how many bytes will be written, you'll need to write to a growable memory stream first, check how many bytes were written, compare it to the globally allocated size, and reallocate if you need more room.

                                          Mark Salsbery Microsoft MVP - Visual C++ :java:

                                          1 Reply Last reply
                                          0
                                          Reply
                                          • Reply as topic
                                          Log in to reply
                                          • Oldest to Newest
                                          • Newest to Oldest
                                          • Most Votes


                                          • Login

                                          • Don't have an account? Register

                                          • Login or register to search.
                                          • First post
                                            Last post
                                          0
                                          • Categories
                                          • Recent
                                          • Tags
                                          • Popular
                                          • World
                                          • Users
                                          • Groups