[RESOLVED] How to make GdipRecordMetafile sets of API work?
I am playing with GdipRecordMetafile sets of API But failed to draw. I think I miss something. Any idea?
Code:
Private Sub cmdFillRECT_Click()
InitGDIPlus
Dim rc1 As RECT
rc1.Left = 20
rc1.Top = 150
rc1.Right = rc1.Left + 250
rc1.Bottom = rc1.Top + 200
picCanvas.AutoRedraw = True
Dim lR As Long
Dim hMetaImage As Long
Dim rctF As RECTF
rctF.Width = 500: rctF.Height = 500
Dim hdc As Long
hdc = CreateCompatibleDC(0)
lR = GdipRecordMetafile(hdc, EmfTypeEmfPlusOnly, rctF, MetafileFrameUnitPixel, StrPtr("TestingStuff"), hMetaImage) 'lR=0 OK
DeleteDC hdc
Dim hMteaGraphics As Long, hMetafileDC As Long
lR = GdipGetImageGraphicsContext(hMetaImage, hMteaGraphics) 'lR=0 OK
lR = GdipGetDC(hMteaGraphics, hMetafileDC) 'lR=0 OK
Dim hBrush As Long, hOldBrush As Long
hBrush = CreateSolidBrush(vbRed)
'hOldBrush = SelectObject(hMetafileDC, hBrush)
FillRect hMetafileDC, rc1, hBrush
'SelectObject hMetafileDC, hOldBrush
DeleteObject hBrush
DrawTextW hMetafileDC, StrPtr("GDI Draw String : testing"), -1, rc1, 0
Dim picGraphics As Long
GdipCreateFromHDC picCanvas.hdc, picGraphics
GdipDrawImage picGraphics, hMetaImage, 0, 0 'Nothing show in picturebox
GdipDeleteGraphics picGraphics
Dim hEmf As Long
lR = GdipGetHemfFromMetafile(hMetaImage, hEmf) 'Failed
GdipReleaseDC hMteaGraphics, hMetafileDC
GdipDeleteGraphics hMteaGraphics
GdipDisposeImage hMetaImage
picCanvas.Refresh
picCanvas.AutoRedraw = False
TerminateGDIPlus
End Sub
Last edited by Jonney; Oct 22nd, 2015 at 01:18 AM.
Re: How to make GdipRecordMetafile sets of API work?
Jonney, just a quick look...
1. Maybe release the GDI+ DC before trying to do anything else (rendering, converting, etc) with the metafile
2. I still might expect GdipGetHemfFromMetafile to fail if releasing the DC first did not fix the problem. EmfTypeEmfPlusOnly is incompatible with Windows metafiles, it is GDI+ only, correct?
Originally Posted by msdn
EmfTypeEmfPlusOnly
Specifies that all of the records in the metafile are EMF+ records, which can be displayed by GDI+ but not by GDI.
Insomnia is just a byproduct of, "It can't be done"
Re: How to make GdipRecordMetafile sets of API work?
Originally Posted by LaVolpe
Jonney, just a quick look...
1. Maybe release the GDI+ DC before trying to do anything else (rendering, converting, etc) with the metafile
You are true. Should call GdipReleaseDC after GDI rendering,otherwise,GDI+ rendering failed (lR = 4 : ObjectBusy)
I still might expect GdipGetHemfFromMetafile to fail if releasing the DC first did not fix the problem.
1. GdipGetHemfFromMetafile failed always. Don't know the reason.
2. I saw nothing because GdipDrawImage can't support hMteaGraphics?
I did see DrawTextW and GdipFillRectangle success.
lR = DrawTextW(hMetafileDC, StrPtr("GDI Draw String : testing"), -1, rc1, 0) 'lR=16: the height of the text in logical units
lR = GdipFillRectangle(hMteaGraphics, hgdipBrush, 10, 10, 100, 100) ' lR = 0
3. I Don't know how to use GdipPlayMetafileRecord API.
Code:
Private Sub cmdFillRECT_Click()
InitGDIPlus
Dim rc1 As RECT
rc1.Left = 20
rc1.Top = 150
rc1.Right = rc1.Left + 250
rc1.Bottom = rc1.Top + 200
picCanvas.AutoRedraw = True
Dim lR As Long
Dim hMetaImage As Long
Dim rctF As RECTF
rctF.Width = 500: rctF.Height = 500
Dim hdc As Long
hdc = CreateCompatibleDC(0)
lR = GdipRecordMetafile(hdc, EmfTypeEmfPlusOnly, rctF, MetafileFrameUnitPixel, StrPtr("TestingStuff"), hMetaImage)
DeleteDC hdc
Dim hMteaGraphics As Long, hMetafileDC As Long
lR = GdipGetImageGraphicsContext(hMetaImage, hMteaGraphics)
Dim eUnit As GpUnit, dpi As Single
GdipGetPageUnit hMteaGraphics, eUnit '1: UnitDisplay
GdipGetDpiX hMteaGraphics, dpi '96dpi
GdipSetPageUnit hMteaGraphics, UnitPixel
lR = GdipGetDC(hMteaGraphics, hMetafileDC)
Dim hBrush As Long, hOldBrush As Long
hBrush = CreateSolidBrush(vbRed)
hOldBrush = SelectObject(hMetafileDC, hBrush)
FillRect hMetafileDC, rc1, hBrush
SelectObject hMetafileDC, hOldBrush
DeleteObject hBrush
DrawTextW hMetafileDC, StrPtr("GDI Draw String : testing"), -1, rc1, 0
GdipReleaseDC hMteaGraphics, hMetafileDC
Dim hgdipBrush As Long
lR = GdipCreateSolidFill(RGBtoARGB(vbRed, 255), hgdipBrush)
lR = GdipFillRectangle(hMteaGraphics, hgdipBrush, 10, 10, 100, 100)
lR = GdipDeleteBrush(hgdipBrush)
Dim picGraphics As Long
lR = GdipCreateFromHDC(picCanvas.hdc, picGraphics)
lR = GdipDrawImage(picGraphics, hMetaImage, 0, 0)
lR = GdipDeleteGraphics(picGraphics)
Dim hEmf As Long
lR = GdipGetHemfFromMetafile(hMetaImage, hEmf)
'GdipReleaseDC hMteaGraphics, hMetafileDC
GdipDeleteGraphics hMteaGraphics
GdipDisposeImage hMetaImage
picCanvas.Refresh
picCanvas.AutoRedraw = False
TerminateGDIPlus
End Sub
Last edited by Jonney; Oct 22nd, 2015 at 10:14 AM.
Re: How to make GdipRecordMetafile sets of API work?
Code:
Public Declare Function GdipEnumerateMetafileSrcRectDestPoints _
Lib "gdiplus" (ByVal graphics As Long, _
ByVal metafile As Long, _
destPoints As POINTF, _
ByVal count As Long, _
srcRect As RECTF, _
ByVal srcUnit As GpUnit, _
ByVal lpEnumerateMetafileProc As Long, _
ByVal callbackData As Long, _
ByVal imageAttributes As Long) As GpStatus
destPoints should be destPoints() ? I think so. But GdipEnumerateMetafileSrcRectDestPoints still failed.
The last second is pointer of callbackData. I don't know how to use it because I don't understand CALLBACK.
Code:
Private Sub cmdFillRECT_Click()
InitGDIPlus
Dim rc1 As RECT
rc1.Left = 20
rc1.Top = 150
rc1.Right = rc1.Left + 250
rc1.Bottom = rc1.Top + 200
picCanvas.AutoRedraw = True
Dim lR As Long
Dim hMetaImage As Long
Dim rctF As RECTF
rctF.Width = 500: rctF.Height = 500
Dim hdc As Long
hdc = CreateCompatibleDC(0)
lR = GdipRecordMetafile(hdc, EmfTypeEmfPlusOnly, rctF, MetafileFrameUnitPixel, StrPtr("TestingStuff"), hMetaImage)
DeleteDC hdc
Dim hMetaGraphics As Long, hMetafileDC As Long
lR = GdipGetImageGraphicsContext(hMetaImage, hMetaGraphics)
Dim eUnit As GpUnit, dpi As Single
GdipGetPageUnit hMetaGraphics, eUnit '1: UnitDisplay
GdipGetDpiX hMetaGraphics, dpi '96dpi
GdipSetPageUnit hMetaGraphics, UnitPixel
lR = GdipGetDC(hMetaGraphics, hMetafileDC)
Dim hBrush As Long, hOldBrush As Long
hBrush = CreateSolidBrush(vbRed)
hOldBrush = SelectObject(hMetafileDC, hBrush)
FillRect hMetafileDC, rc1, hBrush
SelectObject hMetafileDC, hOldBrush
DeleteObject hBrush
lR = DrawTextW(hMetafileDC, StrPtr("GDI Draw String : testing"), -1, rc1, 0)
GdipReleaseDC hMetaGraphics, hMetafileDC
Dim hgdipBrush As Long
lR = GdipCreateSolidFill(RGBtoARGB(vbRed, 255), hgdipBrush)
lR = GdipFillRectangle(hMetaGraphics, hgdipBrush, 10, 10, 100, 100)
lR = GdipDeleteBrush(hgdipBrush)
Dim hBitmap As Long, hGraphics As Long
lR = CreateBitmap(hBitmap, 500, 500, PixelFormat32bppARGB)
lR = GdipGetImageGraphicsContext(hBitmap, hGraphics)
Dim picGraphics As Long
lR = GdipCreateFromHDC(picCanvas.hdc, picGraphics)
Dim dst_points(3) As POINTF
dst_points(0).x = 0: dst_points(0).y = 0
dst_points(1).x = 500: dst_points(1).y = 0
dst_points(2).x = 0: dst_points(2).y = 500
dst_points(3).x = 500: dst_points(3).y = 500
play_metafile hGraphics, hMetaImage, StrPtr("fillrect metafile"), dst_points, rctF, UnitPixel
lR = GdipDrawImage(picGraphics, hBitmap, 0, 0)
'play_metafile picGraphics, hMetaImage, StrPtr("fillrect metafile"), dst_points, rctF, UnitPixel
lR = GdipDeleteGraphics(picGraphics)
GdipDeleteGraphics hGraphics
GdipDisposeImage hBitmap
Dim hEmf As Long
lR = GdipGetHemfFromMetafile(hMetaImage, hEmf)
'GdipReleaseDC hMetaGraphics, hMetafileDC
GdipDeleteGraphics hMetaGraphics
GdipDisposeImage hMetaImage
picCanvas.Refresh
picCanvas.AutoRedraw = False
TerminateGDIPlus
End Sub
Private Sub play_metafile(ByVal graphics As Long, ByVal metafile As Long, ByVal desc As Long, dst_points() As POINTF, scr_rect As RECTF, src_unit As GpUnit)
Dim lR As Long
lR = GdipEnumerateMetafileSrcRectDestPoints(graphics, metafile, dst_points, 4, scr_rect, src_unit, 0&, 0&, 0&)
End Sub
Last edited by Jonney; Oct 22nd, 2015 at 09:12 PM.
Re: How to make GdipRecordMetafile sets of API work?
After GdipRecordMetafile being called,udtMetafileHeader return something:
Code:
Public Type MetafileHeader
mType As MetafileType
Size As Long ' Size of the metafile (in bytes)
Version As Long ' EMF+, EMF, or WMF version
EmfPlusFlags As Long
DpiX As Single
DpiY As Single
x As Long ' Bounds in device units
y As Long
Width As Long
Height As Long
EmfHeader As ENHMETAHEADER3 ' NOTE: You'll have to use CopyMemory to view the METAHEADER type
EmfPlusHeaderSize As Long ' size of the EMF+ header in file
LogicalDpiX As Long ' Logical Dpi of reference Hdc
LogicalDpiY As Long ' usually valid only for EMF+
End Type
Dim udtMetafileHeader As MetafileHeader
lR = GdipGetMetafileHeaderFromMetafile(hMetaImage, udtMetafileHeader)
/// <summary>
/// Plays an individual metafile record.
/// </summary>
/// <param name="recordType">
/// Element of the <see cref="T:System.Drawing.Imaging.EmfPlusRecordType" /> that specifies the type of metafile record being played.
/// </param>
/// <param name="flags">
/// A set of flags that specify attributes of the record.
/// </param>
/// <param name="dataSize">
/// The number of bytes in the record data.
/// </param>
/// <param name="data">
/// An array of bytes that contains the record data.
/// </param>
public void PlayRecord(EmfPlusRecordType recordType, int flags, int dataSize, byte[] data)
{
int num = SafeNativeMethods.Gdip.GdipPlayMetafileRecord(new HandleRef(this, this.nativeImage), recordType, flags, dataSize, data);
if (num != 0)
{
throw SafeNativeMethods.Gdip.StatusException(num);
}
}
C# is very easy to create a WMF file and draw something:
Code:
Metafile curMetafile = null;
// Create a Graphics object
Graphics g = this.CreateGraphics();
// Get HDC
IntPtr hdc = g.GetHdc();
// Create a rectangle
Rectangle rect = new Rectangle(0, 0, 200, 200);
// Use HDC to create a metafile with a name
try
{
curMetafile = new Metafile(@"d:\newFile.wmf", hdc);
}
catch (Exception exp)
{
MessageBox.Show(exp.Message);
g.ReleaseHdc(hdc);
g.Dispose();
return;
}
// Create a Graphics object from the Metafile object
Graphics g1 = Graphics.FromImage(curMetafile);
// Set smooting mode
g1.SmoothingMode = SmoothingMode.HighQuality;
// Fill a rectangle on the Metafile object
g1.FillRectangle(Brushes.Green, rect);
rect.Y += 110;
// Draw an ellipse on the Metafile object
LinearGradientBrush lgBrush =
new LinearGradientBrush(
rect, Color.Red, Color.Blue, 45.0f);
g1.FillEllipse(lgBrush, rect);
// Draw text on the Metafile object
rect.Y += 110;
g1.DrawString("MetaFile Sample",
new Font("Verdana", 20),
lgBrush, 200, 200,
StringFormat.GenericTypographic);
// Release objects
g.ReleaseHdc(hdc);
g1.Dispose();
g.Dispose();
But why VB code doesn't work? GdipRecordMetafileFileName failed.
Code:
Private Sub cmdFillRECT_Click()
InitGDIPlus
picCanvas.AutoRedraw = True
Dim lR As Long
Dim rctF As RECTF
rctF.Width = 5000: rctF.Height = 5000
Dim hMetaFile As Long
lR = GdipRecordMetafileFileName(StrPtr(App.Path & "\testWMF2.wmf"), Printer.hdc, EmfTypeEmfPlusOnly, rctF, MetafileFrameUnitPixel, StrPtr(vbNullString), hMetaFile) 'the 2nd argument can be any valid hdc such as picCanvas.hdc
Dim hMetaGraphics As Long, hMetafileDC As Long
lR = GdipGetImageGraphicsContext(hMetaFile, hMetaGraphics)
'sets the unit of measure for this Graphics object from UnitDisplay to UnitPixel
'GdipSetPageUnit hMetaGraphics, UnitPixel
GdipSetSmoothingMode hMetaGraphics, SmoothingModeAntiAlias
lR = GdipGetDC(hMetaGraphics, hMetafileDC)
'GDI draw
Dim rc1 As RECT
rc1.Left = 20
rc1.Top = 150
rc1.Right = rc1.Left + 500
rc1.Bottom = rc1.Top + 600
Dim hBrush As Long
hBrush = CreateSolidBrush(vbGreen)
lR = FillRect(hMetafileDC, rc1, hBrush)
DeleteObject hBrush
GdipReleaseDC hMetaGraphics, hMetafileDC
'GDI+ draw
Dim hgdipBrush As Long
lR = GdipCreateSolidFill(RGBtoARGB(vbRed, 200), hgdipBrush)
lR = GdipFillRectangle(hMetaGraphics, hgdipBrush, 10, 10, 100, 100)
lR = GdipDeleteBrush(hgdipBrush)
lR = GdipCreateSolidFill(RGBtoARGB(vbBlue, 150), hgdipBrush)
lR = GdipFillPie(hMetaGraphics, hgdipBrush, 45, 10, 150, 150, -90, 245)
lR = GdipDeleteBrush(hgdipBrush)
GdipDeleteGraphics hMetaGraphics
Dim picGraphics As Long
GdipCreateFromHDC picCanvas.hdc, picGraphics
GdipDrawImage picGraphics, hMetaFile, 0, 0
GdipDeleteGraphics picGraphics
GdipDisposeImage hMetaFile
picCanvas.Refresh
picCanvas.AutoRedraw = False
TerminateGDIPlus
End Sub
Edited:
oh, my God, I have no idea what is the right API Declare. After Changed the 3rd argument etype to ByVal, GdipRecordMetafileFileName is successful.
Code:
lR = GdipRecordMetafileFileName(StrPtr("d:\testWMF.wmf"), hdc, EmfTypeEmfPlusDual, rctF, MetafileFrameUnitPixel, StrPtr(vbNullString), hMetaFile)
Public Declare Function GdipRecordMetafileFileName _
Lib "gdiplus" (ByVal FileName As Long, _
ByVal referenceHdc As Long, _
ByVal etype As emfType, _
frameRect As RECTF, _
ByVal frameUnit As MetafileFrameUnit, _
ByVal description As Long, _
metafile As Long) As GpStatus
Last edited by Jonney; Oct 23rd, 2015 at 06:49 AM.
Dim hMetaGraphics As Long, hMetafileDC As Long
lR = GdipGetImageGraphicsContext(hMetaFile, hMetaGraphics)
hMetaGraphics=0??
Public Declare Function GdipRecordMetafileFileName _
Lib "gdiplus" (ByVal FileName As Long, _
ByVal referenceHdc As Long, _
ByVal etype As emfType, _
frameRect As RECTF, _
ByVal frameUnit As MetafileFrameUnit, _
ByVal description As Long, _
metafile As Long) As GpStatus
now it's ok
How to achieve gradient color and gradient transparency in drawing?
Last edited by xiaoyao; Jun 12th, 2025 at 10:35 PM.
Re: [RESOLVED] How to make GdipRecordMetafile sets of API work?
how to create memorydc,draw once,and show to picture1.hdc
draw other, show to picture1.hdc
draw other, show to picture1.hdc
save efm+ file to disk?
Code:
for show to picture1.hdc,need GdipDeleteGraphics ,
but can't draw new item and can't update new items to emf file
Sub DrawToHdc(hdc As Long)
GdipDeleteGraphics hMetaGraphics
hMetaGraphics = 0
' ?????????DC
Dim picGraphics As Long
GdipCreateFromHDC hdc, picGraphics
GdipDrawImage picGraphics, hMetaFile, 0, 0
GdipDeleteGraphics picGraphics
End Sub
Last edited by xiaoyao; Jun 13th, 2025 at 04:00 AM.