From: AliR (VC++ MVP) on 12 Aug 2008 11:50 Hi everyone, I need to draw some rft to the screen. And I found some code out there that uses a Richedit control and sends it an EM_FORMATRANGE to do exactly that. Now I need to add scaling to this code. What I'm trying to do is to have the richedit control draw to a metafile and then I can set the ScaleTrasform of the Graphics object and draw the metafile. But everytime I call Metafile.GetHenhmetafile() it throws a "Parameter is not valid" execption. I haven't been able to find a solution to this problem anywhere. public void Draw(Graphics graphics, RectangleF layoutArea, float xFactor) { //Calculate the area to render. SafeNativeMethods.RECT rectLayoutArea; rectLayoutArea.Top = (int)(layoutArea.Top * anInch); rectLayoutArea.Bottom = (int)(layoutArea.Bottom * anInch); rectLayoutArea.Left = (int)(layoutArea.Left * anInch); rectLayoutArea.Right = (int)(layoutArea.Right * anInch); IntPtr hdc = graphics.GetHdc(); Metafile metafile = new Metafile(hdc, layoutArea); //Release the device context handle obtained by a previous call graphics.ReleaseHdc(hdc); IntPtr hDCEMF = metafile.GetHenhmetafile(); <-------- I can't get passed this line! SafeNativeMethods.FORMATRANGE fmtRange; fmtRange.chrg.cpMax = -1; //Indicate character from to character to fmtRange.chrg.cpMin = 0; fmtRange.hdc = hDCEMF; //Use the same DC for measuring and rendering fmtRange.hdcTarget = hDCEMF; //Point at printer hDC fmtRange.rc = rectLayoutArea; //Indicate the area on page to print fmtRange.rcPage = rectLayoutArea; //Indicate size of page IntPtr wParam = IntPtr.Zero; wParam = new IntPtr(1); //Get the pointer to the FORMATRANGE structure in memory IntPtr lParam = IntPtr.Zero; lParam = Marshal.AllocCoTaskMem(Marshal.SizeOf(fmtRange)); Marshal.StructureToPtr(fmtRange, lParam, false); SafeNativeMethods.SendMessage(this.Handle, SafeNativeMethods.EM_FORMATRANGE, wParam, lParam); //Free the block of memory allocated Marshal.FreeCoTaskMem(lParam); graphics.ScaleTransform(xFactor, xFactor); graphics.DrawImage(metafile, layoutArea.Location); } AliR.
From: Peter Duniho on 12 Aug 2008 12:30 On Tue, 12 Aug 2008 08:50:36 -0700, AliR (VC++ MVP) <AliR(a)online.nospam> wrote: > Hi everyone, > > I need to draw some rft to the screen. And I found some code out there > that > uses a Richedit control and sends it an EM_FORMATRANGE to do exactly > that. > > Now I need to add scaling to this code. What I'm trying to do is to have > the richedit control draw to a metafile and then I can set the > ScaleTrasform > of the Graphics object and draw the metafile. > > But everytime I call Metafile.GetHenhmetafile() it throws a "Parameter is > not valid" execption. Why not use Graphics.FromImage() to get a Graphics instance from the Metafile, and then Graphics.GetHdc() to get the HDC to assign to fmtRange.chrg.hdc? By the way, the class "SafeNativeMethods" looks very much like code from the .NET Framework itself. I don't know where you got that, but you may want to be very careful to not be using code copied from .NET. Microsoft's published the code, but I'm pretty sure the license is for debugging purposes only, not for reuse within your own code. Pete
From: AliR (VC++ MVP) on 12 Aug 2008 14:27 "Peter Duniho" <NpOeStPeAdM(a)nnowslpianmk.com> wrote in message news:op.ufr745wz8jd0ej(a)petes-computer.local... > Why not use Graphics.FromImage() to get a Graphics instance from the > Metafile, and then Graphics.GetHdc() to get the HDC to assign to > fmtRange.chrg.hdc? > > By the way, the class "SafeNativeMethods" looks very much like code from > the .NET Framework itself. I don't know where you got that, but you may > want to be very careful to not be using code copied from .NET. > Microsoft's published the code, but I'm pretty sure the license is for > debugging purposes only, not for reuse within your own code. > > Pete I got the code from here http://www.andrewvos.com/?p=392 which is pretty much the same code as http://support.microsoft.com/kb/812425/en-us Which .Net code are you refering to? Am I reinventing the wheele? Is there built-in code that does this already? I don't really see how GraphicFromImage is going to help. Under native c++ code, I have to draw to a meta file and then I can use world transformations to scale the text in a way that would not case detering and things like that. I tried your suggestion but it didn't draw anything. public void Draw(Graphics graphics, RectangleF layoutArea, float xFactor) { //Calculate the area to render. SafeNativeMethods.RECT rectLayoutArea; rectLayoutArea.Top = (int)(layoutArea.Top * anInch); rectLayoutArea.Bottom = (int)(layoutArea.Bottom * anInch); rectLayoutArea.Left = (int)(layoutArea.Left * anInch); rectLayoutArea.Right = (int)(layoutArea.Right * anInch); IntPtr hdc = graphics.GetHdc(); Metafile metafile = new Metafile(hdc, layoutArea); Graphics metagraphic = Graphics.FromImage(metafile); IntPtr hDCEMF = metagraphic.GetHdc(); SafeNativeMethods.FORMATRANGE fmtRange; fmtRange.chrg.cpMax = -1; //Indicate character from to character to fmtRange.chrg.cpMin = 0; fmtRange.hdc = hDCEMF; //Use the same DC for measuring and rendering fmtRange.hdcTarget = hDCEMF; //Point at printer hDC fmtRange.rc = rectLayoutArea; //Indicate the area on page to print fmtRange.rcPage = rectLayoutArea; //Indicate size of page IntPtr wParam = IntPtr.Zero; wParam = new IntPtr(1); //Get the pointer to the FORMATRANGE structure in memory IntPtr lParam = IntPtr.Zero; lParam = Marshal.AllocCoTaskMem(Marshal.SizeOf(fmtRange)); Marshal.StructureToPtr(fmtRange, lParam, false); SafeNativeMethods.SendMessage(this.Handle, SafeNativeMethods.EM_FORMATRANGE, wParam, lParam); //Free the block of memory allocated Marshal.FreeCoTaskMem(lParam); metagraphic.ReleaseHdc(hDCEMF); //Release the device context handle obtained by a previous call graphics.ReleaseHdc(hdc); graphics.ScaleTransform(xFactor, xFactor); graphics.DrawImage(metafile, layoutArea.Location); }
From: AliR (VC++ MVP) on 12 Aug 2008 14:35 "AliR (VC++ MVP)" <AliR(a)online.nospam> wrote in message news:iCkok.18061$mh5.2592(a)nlpi067.nbdc.sbc.com... > "Peter Duniho" <NpOeStPeAdM(a)nnowslpianmk.com> wrote in message > news:op.ufr745wz8jd0ej(a)petes-computer.local... >> Why not use Graphics.FromImage() to get a Graphics instance from the >> Metafile, and then Graphics.GetHdc() to get the HDC to assign to >> fmtRange.chrg.hdc? >> >> By the way, the class "SafeNativeMethods" looks very much like code from >> the .NET Framework itself. I don't know where you got that, but you may >> want to be very careful to not be using code copied from .NET. >> Microsoft's published the code, but I'm pretty sure the license is for >> debugging purposes only, not for reuse within your own code. >> >> Pete > > I got the code from here http://www.andrewvos.com/?p=392 > which is pretty much the same code as > http://support.microsoft.com/kb/812425/en-us > Which .Net code are you refering to? Am I reinventing the wheele? Is > there built-in code that does this already? > > I don't really see how GraphicFromImage is going to help. Under native > c++ code, I have to draw to a meta file and then I can use world > transformations to scale the text in a way that would not case detering > and things like that. > > I tried your suggestion but it didn't draw anything. > > public void Draw(Graphics graphics, RectangleF layoutArea, float > xFactor) > { > //Calculate the area to render. > SafeNativeMethods.RECT rectLayoutArea; > rectLayoutArea.Top = (int)(layoutArea.Top * anInch); > rectLayoutArea.Bottom = (int)(layoutArea.Bottom * anInch); > rectLayoutArea.Left = (int)(layoutArea.Left * anInch); > rectLayoutArea.Right = (int)(layoutArea.Right * anInch); > > IntPtr hdc = graphics.GetHdc(); > > Metafile metafile = new Metafile(hdc, layoutArea); > > Graphics metagraphic = Graphics.FromImage(metafile); > IntPtr hDCEMF = metagraphic.GetHdc(); > > SafeNativeMethods.FORMATRANGE fmtRange; > fmtRange.chrg.cpMax = -1; //Indicate character from > to character to > fmtRange.chrg.cpMin = 0; > fmtRange.hdc = hDCEMF; //Use the same DC for > measuring and rendering > fmtRange.hdcTarget = hDCEMF; //Point at printer hDC > fmtRange.rc = rectLayoutArea; //Indicate the area on > page to print > fmtRange.rcPage = rectLayoutArea; //Indicate size of page > > IntPtr wParam = IntPtr.Zero; > wParam = new IntPtr(1); > > //Get the pointer to the FORMATRANGE structure in memory > IntPtr lParam = IntPtr.Zero; > lParam = Marshal.AllocCoTaskMem(Marshal.SizeOf(fmtRange)); > Marshal.StructureToPtr(fmtRange, lParam, false); > > SafeNativeMethods.SendMessage(this.Handle, > SafeNativeMethods.EM_FORMATRANGE, wParam, lParam); > > //Free the block of memory allocated > Marshal.FreeCoTaskMem(lParam); > > metagraphic.ReleaseHdc(hDCEMF); > //Release the device context handle obtained by a previous call > graphics.ReleaseHdc(hdc); > > graphics.ScaleTransform(xFactor, xFactor); > > graphics.DrawImage(metafile, layoutArea.Location); > } > > Here is the MFC version of this: // setup rectangles for metafile fiddling DC->DPtoHIMETRIC(&cTargetSize); // from MM_Text to MM_HIMETRIC CRect cHiMetricRect(0,0,cTargetSize.cx,cTargetSize.cy); CRect cTwipsRect(0,0,(TWIPS_INCH * cTargetSize.cx + HIMETRIC_INCH / 2) / HIMETRIC_INCH, (TWIPS_INCH * cTargetSize.cy + HIMETRIC_INCH / 2) / HIMETRIC_INCH); // create the enhanced metafile HDC hDCEMF = CreateEnhMetaFile(DC->m_hDC,NULL,cHiMetricRect,NULL); // setup the format struct and do the RTF range formatting call FORMATRANGE stFR; stFR.hdcTarget = stFR.hdc = hDCEMF; // render to the memory helper EMF stFR.rcPage = stFR.rc = cTwipsRect; // using this rectangle (in twips) stFR.chrg.cpMin = 0; // and render all of the text stFR.chrg.cpMax = -1; pCtrl->SendMessage(EM_FORMATRANGE,TRUE,(LPARAM) &stFR); pCtrl->SendMessage(EM_FORMATRANGE,TRUE,NULL); // this call clears the cache // drawing into the metafile is done, get ourselves an handle to it (used for the replay) HENHMETAFILE hEMF = CloseEnhMetaFile(hDCEMF); // calculate the automagic fudge factors by getting the device metrics int nHorzSize = DC->GetDeviceCaps(HORZSIZE ); // width in millimeters int nVertSize = DC->GetDeviceCaps(VERTSIZE ); // height in millimeters int nHorzRes = DC->GetDeviceCaps(HORZRES ); // width in pixels int nVertRes = DC->GetDeviceCaps(VERTRES ); // height in pixels int nLogPixelsX = DC->GetDeviceCaps(LOGPIXELSX); // # of pixels per inch horizontally int nLogPixelsY = DC->GetDeviceCaps(LOGPIXELSY); // # of pixels per inch vertically float fHorzSizeInches = nHorzSize / 25.4f; float fVertSizeInches = nVertSize / 25.4f; float fHorzFudgeFactor = (nHorzRes / fHorzSizeInches) / nLogPixelsX; // divide expected DPI with actual DPI float fVertFudgeFactor = (nVertRes / fVertSizeInches) / nLogPixelsY; // // do the world transforms, first apply the scale and fudge factors XFORM stX; ZeroMemory(&stX,sizeof(stX)); stX.eM11 = fHorzFudgeFactor * (m_XFactor); stX.eM22 = fVertFudgeFactor * (m_XFactor); SetWorldTransform(DC->m_hDC,&stX); long Top = WinRect.top; long Left = WinRect.left; WinRect.OffsetRect(-Left,-Top); WinRect.OffsetRect((int)(Left/fHorzFudgeFactor),int(Top/fVertFudgeFactor)); DC->PlayMetaFile(hEMF,&WinRect); // that's it, kiss the metafile goodbye DeleteEnhMetaFile(hEMF);
From: Peter Duniho on 12 Aug 2008 16:49 On Tue, 12 Aug 2008 11:27:29 -0700, AliR (VC++ MVP) <AliR(a)online.nospam> wrote: > I got the code from here http://www.andrewvos.com/?p=392 > which is pretty much the same code as > http://support.microsoft.com/kb/812425/en-us > Which .Net code are you refering to? Am I reinventing the wheele? Is > there > built-in code that does this already? That I know of, no. I was simply commenting on the class "SafeNativeMethods", because that's the exact name used in the .NET Framework's implementation. Could be that the original source lifted it from the .NET source code, or just the name. Personally, it doesn't concern me one way or the other. It's just that someone using that code should be careful if they are at all concerned about running afoul of Microsoft's legal department (which, while not as rabid as those found in other corporations, do still need to justify their existence). > I don't really see how GraphicFromImage is going to help. The Graphics instance you get from that wraps the Metafile itself, so any DC you get from that Graphics instance is for the Metafile. In other words, the HDC that you get from the Graphics instance returned by that method returns exactly the thing you need to assign to the FORMATRANGE.hdc field. I don't know why the call to Metafile.GetHenhmetafile() doesn't work, other than the fact that I personally have had trouble with the .NET Metafile implementation in the past (in other words, things that you'd think would work based on how the unmanaged version works, wind up not working). But I do know that you can get an HDC that draws into the Metafile by using Graphics.FromImage() and the Graphics.GetHdc(). I'm pretty sure I've done that before and had it work (for sure it works with Bitmaps, and I'm pretty sure I've used it with Metafiles too). > Under native c++ > code, I have to draw to a meta file and then I can use world > transformations > to scale the text in a way that would not case detering and things like > that. > > I tried your suggestion but it didn't draw anything. Well, it at least didn't cause an error, right? I can't say exactly what's wrong with the code you're using. But I suspect you're closer to a solution now than you were before. :) You'll probably have to break the problem down into smaller parts and see what's not working as expected. The code you're using is almost, but not exactly, like the MSDN code, so one place to start would be to start with _exactly_ the code in the MSDN sample and see if you can get that to work. You should also check to see whether you're able to create a Metafile via more conventional means that does what you want, to double-check that your Metafile-specific code is valid. And of course, I hope this is a silly question, but you are in fact putting that code in a control that inherits RichTextBox, right? Pete
|
Next
|
Last
Pages: 1 2 Prev: Adding an IP address to a network card Next: Unable to load DLL 'webengine.dll' |