Autor
|
Tema: Problema con BitBlt y C++/CLI (Leído 1,919 veces)
|
SARGE553413
Desconectado
Mensajes: 176
|
Hola a todos. Tengo que usar la función BitBlt() en código C++/CLI. Lo he intentado de muchas formas y no consigo que funcione. Me da el error código 6 (invalid handle). He leído bastantes posts etc. por internet, y para empezar veo que nadie que use esta función tiene que hacer un casting de IntPtr a HDC. Adjunto el código (comentado en inglés) /* 1 - Get a bmp image from hard drive( i have it). 2 - Copy it to byte array, or get its internal array, i have tested both ways (method1 and method2 in comments). 3 - Prepare a PicutreBox and obtain from it my context device. 4 - Use BitBlt function to copy only first 50 lines of the initial bitmap. 5 - Display it in a windows form. */ #include "stdafx.h" #include <Windows.h> #include "MyForm.h" #include "string.h" using namespace System; using namespace System::Runtime::InteropServices; using namespace System::Runtime::CompilerServices; using namespace System::IO; using namespace System::Windows::Forms; using namespace System::Drawing; using namespace System::Drawing::Imaging; using namespace ConsoleApplication1; [DllImport("gdi32.dll", CallingConvention = CallingConvention::StdCall, SetLastError = true)] extern bool BitBlt(IntPtr hdcDest, int nXDest, int nYDest, int nWidth, int nHeight, IntPtr hdcSrc, int nXSrc, int nYSrc, long dwRop); int main(array<System::String ^> ^args){ Graphics ^gph = nullptr; try{ //Get a test image and it's parameters Bitmap ^image = gcnew Bitmap("./img/Simple_tux0.bmp"); int iWidth = image->Width; int iHeigth = image->Height; PixelFormat pxF = image->PixelFormat; //Prepare a PictureBo, whici will be given as parameter to Windows Form. PictureBox ^pb = gcnew PictureBox(); pb->SizeMode = PictureBoxSizeMode::StretchImage; pb->Size = Drawing::Size(iWidth + 10, iHeigth + 10); pb->Location = Drawing::Point(3, 3); //Get bitmap IntPtr prueba = image->GetHbitmap(); //Create my device context, where i will paint my lines. gph = pb->CreateGraphics(); IntPtr deviceContext = gph->GetHdc(); //Paint only 50 lines of the source Bitmap. BOOL b = BitBlt((HDC)deviceContext.ToPointer(), 0, 0, iWidth, 50, (HDC)prueba.ToPointer(), 0, 0, SRCCOPY); //Get the error: unsigned long err = GetLastError(); Console::WriteLine("error: {0}", err); //error 6 : Invalid Handle //Create windows form with the PictureBox to display my 50 lines. MyForm ^f = gcnew MyForm(pb); Application::Run(f); Application::Exit(); } finally{ if (gph != nullptr){ gph->ReleaseHdc(); delete gph; } } return 0; }
He intentado usar también esto: [DllImport("coredll.dll", EntryPoint = "CreateCompatibleDC")] extern IntPtr CreateCompatibleDC(IntPtr hdc); [DllImport("coredll.dll", EntryPoint = "GetDC")] extern IntPtr GetDC(IntPtr hwnd); int main(){ //... //... IntPtr dc = GetDC(deviceContext); IntPtr compDc = CreateCompatibleDC(dc); //Paint only 50 lines of the source Bitmap. BOOL b = BitBlt((HDC)compDc.ToPointer(), 0, 0, iWidth, 50, (HDC)prueba.ToPointer(), 0, 0, SRCCOPY);
La primera pregunta que me surge es por qué yo tengo que hacer esto: (HDC)deviceContext.ToPointer()
Y en todos los post que leo nadie lo hace. Saludos, gracias.
|
|
« Última modificación: 18 Octubre 2014, 08:17 am por Eleкtro »
|
En línea
|
|
|
|
kub0x
Enlightenment Seeker
Moderador
Desconectado
Mensajes: 1.486
S3C M4NI4C
|
Muy buenas SARGE553413, ¿los posts que has revisado por internet son de C++/CLI? IntPtr es una clase del Framework, lo cual no pertenece a la WinAPI y por lo tanto no se puede castear a HDC, por lo cual debes de optener un pointer, a void (void*) supongo, y luego castear a HDC que realmente es lo que estás haciendo. Aun así podrías hacer override al evento WM_PAINT del PictureBox, dentro de ahí haces la llamada a la siguiente función, la cual dibuja tu imagen: void FromImageImage( PaintEventArgs^ e ) { // Create image. Image^ imageFile = Image::FromFile( "tuimagen.jpg" ); // Create graphics object for alteration. Graphics^ newGraphics = Graphics::FromImage( imageFile ); // Alter image. newGraphics->FillRectangle( gcnew SolidBrush( Color::Black ), 100, 50, 100, 100 ); // Draw image to screen. e->Graphics->DrawImage( imageFile, PointF(0.0F,0.0F) ); // Dispose of graphics object. delete newGraphics; }
Saludos!
|
|
|
En línea
|
|
|
|
SARGE553413
Desconectado
Mensajes: 176
|
Hola de nuevo, respecto al IntPtr, tiene un método toPointer() que devuelve void*, y HDC es un void* realmente. De todas formas ya he solucionado el error, el problema es que ahora no veo por pantalla lo que dibujo. Adjunto el nuevo código en el que BitBlt() da error 0 (todo ok), por algún motivo el PictureBox no se actualiza bien: [DllImport("gdi32.dll", CallingConvention = CallingConvention::StdCall, SetLastError = true)] extern bool BitBlt(IntPtr hdcDest, int nXDest, int nYDest, int nWidth, int nHeight, IntPtr hdcSrc, int nXSrc, int nYSrc, long dwRop); int main(array<System::String ^> ^args){ Graphics ^gph = nullptr; try{ //Get a test image and it's parameters Bitmap ^image = gcnew Bitmap("./img/Simple_tux0.bmp"); int iWidth = image->Width; int iHeigth = image->Height; PixelFormat pxF = image->PixelFormat; //Prepare a PictureBox, which will be given as parameter to Windows Form. //It has an image that's my "draw area". PictureBox ^pb = gcnew PictureBox(); pb->SizeMode = PictureBoxSizeMode::Normal; pb->Size = Drawing::Size(iWidth, iHeigth); pb->Location = Drawing::Point(0, 0); Bitmap ^drawArea = gcnew Bitmap(pb->Width, pb->Height); pb->Image = drawArea; //Get bitmap IntPtr prueba = image->GetHbitmap(); //Create my device context, where i will paint my lines. gph = Graphics::FromImage(drawArea); IntPtr deviceContext = gph->GetHdc(); //Paint only 50 lines of the source Bitmap. BOOL b = BitBlt((HDC)deviceContext.ToPointer(), 0, 0, iWidth, 50, (HDC)prueba.ToPointer(), 0, 0, SRCCOPY); //Get the error: unsigned long err = GetLastError(); Console::WriteLine("error: {0}", err); //error 6 : Invalid Handle //Refresh pb->Invalidate(); pb->Refresh(); //Create windows form with the PictureBox to display my 50 lines. MyForm ^f = gcnew MyForm(pb); Application::Run(f); Application::Exit(); } finally{ if (gph != nullptr){ gph->ReleaseHdc(); delete gph; } } return 0; }
¿Qué hago mal? Saludos, gracias.
|
|
« Última modificación: 19 Octubre 2014, 16:29 pm por Eleкtro »
|
En línea
|
|
|
|
kub0x
Enlightenment Seeker
Moderador
Desconectado
Mensajes: 1.486
S3C M4NI4C
|
Hola de nuevo, respecto al IntPtr, tiene un método toPointer() que devuelve void*, y HDC es un void* realmente.
Exactamente igual que lo que te dije arriba. Si no encuentras posts por la red que usen toPointer() es que no es C++/CLI, ya que HDC es unmanaged e IntPtr es managed. Por lo demás el code está bien, quizá te falte el añadir el PictureBox al formulario, espero sea eso, pues error 0 indica que todo fue bien. f->Controls->Add(pb);
Aun así el otro código que te dí es funcional, haciendo override al WM_PAINT. Saludos!
|
|
|
En línea
|
|
|
|
|
|