473,405 Members | 2,349 Online
Bytes | Software Development & Data Engineering Community
Post Job

Home Posts Topics Members FAQ

Join Bytes to post your question to a community of 473,405 software developers and data experts.

RTF Render with Scale

I'm trying to write a RTF render code in C#. I have the code in C++/MFC and
it works fine, but I have run into a problem with the C# code. I think the
C# code is from Microsoft, and I added scaling to it. The C# code is
working fine on my desktop PC but it cuts off some of the text when I run it
on my laptop. The MFC code works fine both on the laptop and the PC. I
have looked at all the numbers used in the MFC and the C# code and they are
identical. Both PC and Laptop are at 1440x900 96dpi font size.

I have been looking at the code for 3 or 4 days now without any improvment.
Was wondering if anyone here wants to take a stab at it.

You can download both sample projects:
http://www.learnstar.com/AliR/RTFScaler.zip
http://www.learnstar.com/AliR/RTFScalerMFC.zip
Thanks
AliR.
Here is the MFC code
// *** copying/scaling/rotating and shearing the text is done here
void CRTFScalerDlg::RenderText(int nScalePercent,int nRotationDegrees,int
nHorzShearPercent,int nVertShearPercent)
{
// validate the arguments
if (nScalePercent < 1)
nScalePercent = 1;
if (nScalePercent 10000)
nScalePercent = 10000;
if (nRotationDegrees < 0)
nRotationDegrees = 0;
if (nRotationDegrees 360)
nRotationDegrees = 360;
if (nHorzShearPercent < 0)
nHorzShearPercent = 0;
if (nHorzShearPercent 100)
nHorzShearPercent = 100;
if (nVertShearPercent < 0)
nVertShearPercent = 0;
if (nVertShearPercent 100)
nVertShearPercent = 100;

// setup target window, rect and DC
CWnd* pTargetWin = GetDlgItem(IDC_EDIT1);
CRect crTarget;
pTargetWin->GetClientRect(&crTarget);
crTarget.OffsetRect(0,20);
CDC* pTargetDC = pTargetWin->GetDC();
pTargetDC->IntersectClipRect(&crTarget); // so we don't clobber the parent
dialog
pTargetDC->SetBkMode(TRANSPARENT); // so the legend doesn't erase too
much

// also need advanced graphics mode for the world transform stuff
if (!SetGraphicsMode(pTargetDC->m_hDC,GM_ADVANCED))
{
pTargetDC->DrawText("Nice try but I need Windows NT, 2000, XP or 2003 for
this.",crTarget,DT_SINGLELINE | DT_VCENTER | DT_CENTER);
return;
}

// erase previous contents
FillRect(pTargetDC->m_hDC,crTarget,(HBRUSH)(COLOR_WINDOW + 1));
CString Temp;
Temp.Format("crTarget %d,%d
%d,%d\n",crTarget.left,crTarget.top,crTarget.Width (),crTarget.Height());
TRACE(Temp);

// setup rectangles for metafile fiddling
CSize cTargetSize = crTarget.Size();
pTargetDC->DPtoHIMETRIC(&cTargetSize); // from MM_Text to MM_HIMETRIC
CSize TopLeft;
TopLeft.cx = crTarget.left;
TopLeft.cy = crTarget.top;
pTargetDC->DPtoHIMETRIC(&TopLeft); // 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);

Temp.Format("MetaSize
%d,%d\n",cHiMetricRect.Width(),cHiMetricRect.Heigh t());
TRACE(Temp);
Temp.Format("cTwipsRect %d,%d\n",cTwipsRect.Width(),cTwipsRect.Height());
TRACE(Temp);
// create the enhanced metafile
HDC hDCEMF = CreateEnhMetaFile(pTargetDC->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;
GetDlgItem(IDC_RICHEDIT1)->SendMessage(EM_FORMATRANGE,TRUE,(LPARAM) &stFR);
GetDlgItem(IDC_RICHEDIT1)->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 = pTargetDC->GetDeviceCaps(HORZSIZE ); // width in
millimeters
int nVertSize = pTargetDC->GetDeviceCaps(VERTSIZE ); // height in
millimeters
int nHorzRes = pTargetDC->GetDeviceCaps(HORZRES ); // width in pixels
int nVertRes = pTargetDC->GetDeviceCaps(VERTRES ); // height in
pixels
int nLogPixelsX = pTargetDC->GetDeviceCaps(LOGPIXELSX); // # of pixels per
inch horizontally
int nLogPixelsY = pTargetDC->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; //

Temp.Format("Fudgfactor %.2f %.2f\n",fHorzFudgeFactor,fVertFudgeFactor);
TRACE(Temp);

// change from degrees to radians
// (also need to change sign since page space is upside down)
float fRotationInRadians = (PI * (0 - nRotationDegrees)) / 180.0F;

// do the world transforms, first apply the scale and fudge factors
XFORM stX;
ZeroMemory(&stX,sizeof(stX));
stX.eM11 = fHorzFudgeFactor * (nScalePercent / 100.0f);
stX.eM22 = fVertFudgeFactor * (nScalePercent / 100.0f);
SetWorldTransform(pTargetDC->m_hDC,&stX);

// then apply the rotation
ZeroMemory(&stX,sizeof(stX));
stX.eM11 = (float) cos(fRotationInRadians);
stX.eM12 = (float) sin(fRotationInRadians);
stX.eM21 = 0 - (float) sin(fRotationInRadians);
stX.eM22 = (float) cos(fRotationInRadians);
ModifyWorldTransform(pTargetDC->m_hDC,&stX,MWT_LEFTMULTIPLY);

// finally apply the horizontal and vertical shearing
ZeroMemory(&stX,sizeof(stX));
stX.eM11 = 1.0f;
stX.eM12 = nHorzShearPercent / 100.0f;
stX.eM21 = nVertShearPercent / 100.0f;
stX.eM22 = 1.0f;
ModifyWorldTransform(pTargetDC->m_hDC,&stX,MWT_LEFTMULTIPLY);

crTarget.OffsetRect(0,-20);
crTarget.OffsetRect(0,20 / (nScalePercent / 100.0f) * fVertFudgeFactor);
// play the metafile
pTargetDC->PlayMetaFile(hEMF,&crTarget);

// that's it, kiss the metafile goodbye
DeleteEnhMetaFile(hEMF);

// also show a legend
ModifyWorldTransform(pTargetDC->m_hDC,NULL,MWT_IDENTITY);
CString sLegend;
sLegend.Format("Scale: %d%% rotation: %dº horizontal shear: %d%%
vertical shear: %d%%.",
nScalePercent,nRotationDegrees,nHorzShearPercent,n VertShearPercent);
pTargetDC->SetTextColor(RGB(55,111,111));
pTargetDC->DrawText(sLegend,crTarget,DT_SINGLELINE | DT_VCENTER |
DT_CENTER);
}
Here is the C# code:

using System;
using System.Drawing;
using System.Runtime.InteropServices;
using System.Windows.Forms;
using System.Drawing.Imaging;
using System.Text;

public static class Graphics_DrawRtfText
{
private static RichTextBoxDrawer rtfDrawer;
public static void DrawRtfText(this Graphics graphics, string rtf,
RectangleF layoutArea,float xFactor)
{
if (Graphics_DrawRtfText.rtfDrawer == null)
{
Graphics_DrawRtfText.rtfDrawer = new RichTextBoxDrawer();
}
Graphics_DrawRtfText.rtfDrawer.Rtf = rtf;
Graphics_DrawRtfText.rtfDrawer.Draw(graphics, layoutArea,xFactor);
}

private class RichTextBoxDrawer : RichTextBox
{
//Code converted from code found here:
http://support.microsoft.com/kb/812425/en-us

//Convert the unit used by the .NET framework (1/100 inch)
//and the unit used by Win32 API calls (twips 1/1440 inch)
private const double anInch = 14.4;

protected override CreateParams CreateParams
{
get
{
CreateParams createParams = base.CreateParams;
if (SafeNativeMethods.LoadLibrary("msftedit.dll") !=
IntPtr.Zero)
{
createParams.ExStyle |=
SafeNativeMethods.WS_EX_TRANSPARENT; // transparent
createParams.ClassName = "RICHEDIT50W";
}
return createParams;
}
}

private void DPToHIMETRIC(Graphics graphics,ref SizeF size)
{
size.Width = (size.Width * 2540.0f) / graphics.DpiX;
size.Height = (size.Height * 2540.0f) / graphics.DpiY;
}

public void Draw(Graphics graphics, RectangleF layoutArea, float
xFactor)
{
System.Diagnostics.Debug.WriteLine("LayoutArea " + layoutArea);

SizeF metaSize = layoutArea.Size;
DPToHIMETRIC(graphics, ref metaSize);

System.Diagnostics.Debug.WriteLine("MetaSize " + metaSize);

IntPtr hdc = graphics.GetHdc();

//create a metafile, convert the size to himetrics
Metafile metafile = new Metafile(hdc, new
RectangleF(0,0,metaSize.Width,metaSize.Height));

graphics.ReleaseHdc(hdc);

Graphics g = Graphics.FromImage(metafile);
IntPtr hDCEMF = g.GetHdc();

//Calculate the area to render.
SafeNativeMethods.RECT rectLayoutArea;
rectLayoutArea.Left = 0;
rectLayoutArea.Top = 0;
rectLayoutArea.Right = (int)((1440 * metaSize.Width + 2540 / 2)
/ 2540);
rectLayoutArea.Bottom = (int)((1440 * metaSize.Height + 2540 /
2) / 2540);

System.Diagnostics.Debug.WriteLine(String.Format(" RectLayoutArea
({0},{1})",rectLayoutArea.Right,rectLayoutArea.Bot tom));

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);
SafeNativeMethods.SendMessage(this.Handle,
SafeNativeMethods.EM_FORMATRANGE, wParam, IntPtr.Zero);

//Free the block of memory allocated
Marshal.FreeCoTaskMem(lParam);

//Release the device context handle obtained by a previous call
g.ReleaseHdc(hDCEMF);
g.Dispose();

hdc = graphics.GetHdc();
int nHorzSize = SafeNativeMethods.GetDeviceCaps(hdc,
SafeNativeMethods.DeviceCap.HORZSIZE);
int nVertSize = SafeNativeMethods.GetDeviceCaps(hdc,
SafeNativeMethods.DeviceCap.VERTSIZE);
int nHorzRes = SafeNativeMethods.GetDeviceCaps(hdc,
SafeNativeMethods.DeviceCap.HORZRES);
int nVertRes = SafeNativeMethods.GetDeviceCaps(hdc,
SafeNativeMethods.DeviceCap.VERTRES);
int nLogPixelsX = SafeNativeMethods.GetDeviceCaps(hdc,
SafeNativeMethods.DeviceCap.LOGPIXELSX);
int nLogPixelsY = SafeNativeMethods.GetDeviceCaps(hdc,
SafeNativeMethods.DeviceCap.LOGPIXELSY);
graphics.ReleaseHdc(hdc);

float fHorzSizeInches = nHorzSize / 25.4f;
float fVertSizeInches = nVertSize / 25.4f;
float fHorzFudgeFactor = (nHorzRes / fHorzSizeInches) /
nLogPixelsX;
float fVertFudgeFactor = (nVertRes / fVertSizeInches) /
nLogPixelsY;

System.Diagnostics.Debug.WriteLine("Fudge Factor " +
fHorzFudgeFactor.ToString() + " " + fVertFudgeFactor.ToString() + " XFactor
" + xFactor.ToString());

Pen RedPen = new Pen(Color.Red);
graphics.DrawRectangle(RedPen, layoutArea.X * xFactor,
layoutArea.Y * xFactor, layoutArea.Width * xFactor, layoutArea.Height *
xFactor);

float Left = layoutArea.Left;
float Top = layoutArea.Top;
//layoutArea.X = layoutArea.Y = 0;
layoutArea.Offset(-Left, -Top);
layoutArea.Offset(Left / fHorzFudgeFactor, Top /
fVertFudgeFactor);

System.Drawing.Drawing2D.GraphicsState state = graphics.Save();
graphics.ScaleTransform(fHorzFudgeFactor * xFactor,
fVertFudgeFactor * xFactor);
graphics.DrawImage(metafile, layoutArea);
graphics.Restore(state);
System.Diagnostics.Debug.WriteLine("Layout Aread :
"+layoutArea);
}

#region SafeNativeMethods
private static class SafeNativeMethods
{
[DllImport("USER32.dll")]
public static extern IntPtr SendMessage(IntPtr hWnd, int msg,
IntPtr wp, IntPtr lp);

[DllImport("kernel32.dll", CharSet = CharSet.Auto)]
public static extern IntPtr LoadLibrary(string lpFileName);

[DllImport("gdi32.dll")]
public static extern int GetDeviceCaps(IntPtr hdc, DeviceCap
nIndex);

[StructLayout(LayoutKind.Sequential)]
public struct RECT
{
public int Left;
public int Top;
public int Right;
public int Bottom;
}

[StructLayout(LayoutKind.Sequential)]
public struct CHARRANGE
{
public int cpMin; //First character of range (0 for
start of doc)
public int cpMax; //Last character of range (-1 for
end of doc)
}

[StructLayout(LayoutKind.Sequential)]
public struct FORMATRANGE
{
public IntPtr hdc; //Actual DC to draw on
public IntPtr hdcTarget; //Target DC for determining text
formatting
public RECT rc; //Region of the DC to
draw to (in twips)
public RECT rcPage; //Region of the whole DC
(page size) (in twips)
public CHARRANGE chrg; //Range of text to draw (see
earlier declaration)
}

public enum DeviceCap : int
{
/// <summary>
/// Device driver version
/// </summary>
DRIVERVERSION = 0,
/// <summary>
/// Device classification
/// </summary>
TECHNOLOGY = 2,
/// <summary>
/// Horizontal size in millimeters
/// </summary>
HORZSIZE = 4,
/// <summary>
/// Vertical size in millimeters
/// </summary>
VERTSIZE = 6,
/// <summary>
/// Horizontal width in pixels
/// </summary>
HORZRES = 8,
/// <summary>
/// Vertical height in pixels
/// </summary>
VERTRES = 10,
/// <summary>
/// Number of bits per pixel
/// </summary>
BITSPIXEL = 12,
/// <summary>
/// Number of planes
/// </summary>
PLANES = 14,
/// <summary>
/// Number of brushes the device has
/// </summary>
NUMBRUSHES = 16,
/// <summary>
/// Number of pens the device has
/// </summary>
NUMPENS = 18,
/// <summary>
/// Number of markers the device has
/// </summary>
NUMMARKERS = 20,
/// <summary>
/// Number of fonts the device has
/// </summary>
NUMFONTS = 22,
/// <summary>
/// Number of colors the device supports
/// </summary>
NUMCOLORS = 24,
/// <summary>
/// Size required for device descriptor
/// </summary>
PDEVICESIZE = 26,
/// <summary>
/// Curve capabilities
/// </summary>
CURVECAPS = 28,
/// <summary>
/// Line capabilities
/// </summary>
LINECAPS = 30,
/// <summary>
/// Polygonal capabilities
/// </summary>
POLYGONALCAPS = 32,
/// <summary>
/// Text capabilities
/// </summary>
TEXTCAPS = 34,
/// <summary>
/// Clipping capabilities
/// </summary>
CLIPCAPS = 36,
/// <summary>
/// Bitblt capabilities
/// </summary>
RASTERCAPS = 38,
/// <summary>
/// Length of the X leg
/// </summary>
ASPECTX = 40,
/// <summary>
/// Length of the Y leg
/// </summary>
ASPECTY = 42,
/// <summary>
/// Length of the hypotenuse
/// </summary>
ASPECTXY = 44,
/// <summary>
/// Shading and Blending caps
/// </summary>
SHADEBLENDCAPS = 45,

/// <summary>
/// Logical pixels inch in X
/// </summary>
LOGPIXELSX = 88,
/// <summary>
/// Logical pixels inch in Y
/// </summary>
LOGPIXELSY = 90,

/// <summary>
/// Number of entries in physical palette
/// </summary>
SIZEPALETTE = 104,
/// <summary>
/// Number of reserved entries in palette
/// </summary>
NUMRESERVED = 106,
/// <summary>
/// Actual color resolution
/// </summary>
COLORRES = 108,

// Printing related DeviceCaps. These replace the
appropriate Escapes
/// <summary>
/// Physical Width in device units
/// </summary>
PHYSICALWIDTH = 110,
/// <summary>
/// Physical Height in device units
/// </summary>
PHYSICALHEIGHT = 111,
/// <summary>
/// Physical Printable Area x margin
/// </summary>
PHYSICALOFFSETX = 112,
/// <summary>
/// Physical Printable Area y margin
/// </summary>
PHYSICALOFFSETY = 113,
/// <summary>
/// Scaling factor x
/// </summary>
SCALINGFACTORX = 114,
/// <summary>
/// Scaling factor y
/// </summary>
SCALINGFACTORY = 115,

/// <summary>
/// Current vertical refresh rate of the display device (for
displays only) in Hz
/// </summary>
VREFRESH = 116,
/// <summary>
/// Horizontal width of entire desktop in pixels
/// </summary>
DESKTOPVERTRES = 117,
/// <summary>
/// Vertical height of entire desktop in pixels
/// </summary>
DESKTOPHORZRES = 118,
/// <summary>
/// Preferred blt alignment
/// </summary>
BLTALIGNMENT = 119
}
public const int WM_USER = 0x0400;
public const int EM_FORMATRANGE = WM_USER + 57;
public const int WS_EX_TRANSPARENT = 0x20;

}
#endregion
}
}

Oct 27 '08 #1
2 5523
Let me also mention that the laptop that is having the funny results is
running Vista 64, the other machines which everything works fine on is
running Vista 32 or XP.

AliR.
"AliR (VC++ MVP)" <Al**@online.nospamwrote in message
news:pq****************@nlpi068.nbdc.sbc.com...
I'm trying to write a RTF render code in C#. I have the code in C++/MFC
and it works fine, but I have run into a problem with the C# code. I
think the C# code is from Microsoft, and I added scaling to it. The C#
code is working fine on my desktop PC but it cuts off some of the text
when I run it on my laptop. The MFC code works fine both on the laptop
and the PC. I have looked at all the numbers used in the MFC and the C#
code and they are identical. Both PC and Laptop are at 1440x900 96dpi
font size.

I have been looking at the code for 3 or 4 days now without any
improvment. Was wondering if anyone here wants to take a stab at it.

You can download both sample projects:
http://www.learnstar.com/AliR/RTFScaler.zip
http://www.learnstar.com/AliR/RTFScalerMFC.zip
Thanks
AliR.
Here is the MFC code
// *** copying/scaling/rotating and shearing the text is done here
void CRTFScalerDlg::RenderText(int nScalePercent,int nRotationDegrees,int
nHorzShearPercent,int nVertShearPercent)
{
// validate the arguments
if (nScalePercent < 1)
nScalePercent = 1;
if (nScalePercent 10000)
nScalePercent = 10000;
if (nRotationDegrees < 0)
nRotationDegrees = 0;
if (nRotationDegrees 360)
nRotationDegrees = 360;
if (nHorzShearPercent < 0)
nHorzShearPercent = 0;
if (nHorzShearPercent 100)
nHorzShearPercent = 100;
if (nVertShearPercent < 0)
nVertShearPercent = 0;
if (nVertShearPercent 100)
nVertShearPercent = 100;

// setup target window, rect and DC
CWnd* pTargetWin = GetDlgItem(IDC_EDIT1);
CRect crTarget;
pTargetWin->GetClientRect(&crTarget);
crTarget.OffsetRect(0,20);
CDC* pTargetDC = pTargetWin->GetDC();
pTargetDC->IntersectClipRect(&crTarget); // so we don't clobber the parent
dialog
pTargetDC->SetBkMode(TRANSPARENT); // so the legend doesn't erase too
much

// also need advanced graphics mode for the world transform stuff
if (!SetGraphicsMode(pTargetDC->m_hDC,GM_ADVANCED))
{
pTargetDC->DrawText("Nice try but I need Windows NT, 2000, XP or 2003 for
this.",crTarget,DT_SINGLELINE | DT_VCENTER | DT_CENTER);
return;
}

// erase previous contents
FillRect(pTargetDC->m_hDC,crTarget,(HBRUSH)(COLOR_WINDOW + 1));
CString Temp;
Temp.Format("crTarget %d,%d
%d,%d\n",crTarget.left,crTarget.top,crTarget.Width (),crTarget.Height());
TRACE(Temp);

// setup rectangles for metafile fiddling
CSize cTargetSize = crTarget.Size();
pTargetDC->DPtoHIMETRIC(&cTargetSize); // from MM_Text to MM_HIMETRIC
CSize TopLeft;
TopLeft.cx = crTarget.left;
TopLeft.cy = crTarget.top;
pTargetDC->DPtoHIMETRIC(&TopLeft); // 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);

Temp.Format("MetaSize
%d,%d\n",cHiMetricRect.Width(),cHiMetricRect.Heigh t());
TRACE(Temp);
Temp.Format("cTwipsRect %d,%d\n",cTwipsRect.Width(),cTwipsRect.Height());
TRACE(Temp);
// create the enhanced metafile
HDC hDCEMF = CreateEnhMetaFile(pTargetDC->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;
GetDlgItem(IDC_RICHEDIT1)->SendMessage(EM_FORMATRANGE,TRUE,(LPARAM)
&stFR);
GetDlgItem(IDC_RICHEDIT1)->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 = pTargetDC->GetDeviceCaps(HORZSIZE ); // width in
millimeters
int nVertSize = pTargetDC->GetDeviceCaps(VERTSIZE ); // height in
millimeters
int nHorzRes = pTargetDC->GetDeviceCaps(HORZRES ); // width in
pixels
int nVertRes = pTargetDC->GetDeviceCaps(VERTRES ); // height in
pixels
int nLogPixelsX = pTargetDC->GetDeviceCaps(LOGPIXELSX); // # of pixels
per inch horizontally
int nLogPixelsY = pTargetDC->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; //

Temp.Format("Fudgfactor %.2f %.2f\n",fHorzFudgeFactor,fVertFudgeFactor);
TRACE(Temp);

// change from degrees to radians
// (also need to change sign since page space is upside down)
float fRotationInRadians = (PI * (0 - nRotationDegrees)) / 180.0F;

// do the world transforms, first apply the scale and fudge factors
XFORM stX;
ZeroMemory(&stX,sizeof(stX));
stX.eM11 = fHorzFudgeFactor * (nScalePercent / 100.0f);
stX.eM22 = fVertFudgeFactor * (nScalePercent / 100.0f);
SetWorldTransform(pTargetDC->m_hDC,&stX);

// then apply the rotation
ZeroMemory(&stX,sizeof(stX));
stX.eM11 = (float) cos(fRotationInRadians);
stX.eM12 = (float) sin(fRotationInRadians);
stX.eM21 = 0 - (float) sin(fRotationInRadians);
stX.eM22 = (float) cos(fRotationInRadians);
ModifyWorldTransform(pTargetDC->m_hDC,&stX,MWT_LEFTMULTIPLY);

// finally apply the horizontal and vertical shearing
ZeroMemory(&stX,sizeof(stX));
stX.eM11 = 1.0f;
stX.eM12 = nHorzShearPercent / 100.0f;
stX.eM21 = nVertShearPercent / 100.0f;
stX.eM22 = 1.0f;
ModifyWorldTransform(pTargetDC->m_hDC,&stX,MWT_LEFTMULTIPLY);

crTarget.OffsetRect(0,-20);
crTarget.OffsetRect(0,20 / (nScalePercent / 100.0f) * fVertFudgeFactor);
// play the metafile
pTargetDC->PlayMetaFile(hEMF,&crTarget);

// that's it, kiss the metafile goodbye
DeleteEnhMetaFile(hEMF);

// also show a legend
ModifyWorldTransform(pTargetDC->m_hDC,NULL,MWT_IDENTITY);
CString sLegend;
sLegend.Format("Scale: %d%% rotation: %dº horizontal shear: %d%%
vertical shear: %d%%.",
nScalePercent,nRotationDegrees,nHorzShearPercent,n VertShearPercent);
pTargetDC->SetTextColor(RGB(55,111,111));
pTargetDC->DrawText(sLegend,crTarget,DT_SINGLELINE | DT_VCENTER |
DT_CENTER);
}
Here is the C# code:

using System;
using System.Drawing;
using System.Runtime.InteropServices;
using System.Windows.Forms;
using System.Drawing.Imaging;
using System.Text;

public static class Graphics_DrawRtfText
{
private static RichTextBoxDrawer rtfDrawer;
public static void DrawRtfText(this Graphics graphics, string rtf,
RectangleF layoutArea,float xFactor)
{
if (Graphics_DrawRtfText.rtfDrawer == null)
{
Graphics_DrawRtfText.rtfDrawer = new RichTextBoxDrawer();
}
Graphics_DrawRtfText.rtfDrawer.Rtf = rtf;
Graphics_DrawRtfText.rtfDrawer.Draw(graphics, layoutArea,xFactor);
}

private class RichTextBoxDrawer : RichTextBox
{
//Code converted from code found here:
http://support.microsoft.com/kb/812425/en-us

//Convert the unit used by the .NET framework (1/100 inch)
//and the unit used by Win32 API calls (twips 1/1440 inch)
private const double anInch = 14.4;

protected override CreateParams CreateParams
{
get
{
CreateParams createParams = base.CreateParams;
if (SafeNativeMethods.LoadLibrary("msftedit.dll") !=
IntPtr.Zero)
{
createParams.ExStyle |=
SafeNativeMethods.WS_EX_TRANSPARENT; // transparent
createParams.ClassName = "RICHEDIT50W";
}
return createParams;
}
}

private void DPToHIMETRIC(Graphics graphics,ref SizeF size)
{
size.Width = (size.Width * 2540.0f) / graphics.DpiX;
size.Height = (size.Height * 2540.0f) / graphics.DpiY;
}

public void Draw(Graphics graphics, RectangleF layoutArea, float
xFactor)
{
System.Diagnostics.Debug.WriteLine("LayoutArea " + layoutArea);

SizeF metaSize = layoutArea.Size;
DPToHIMETRIC(graphics, ref metaSize);

System.Diagnostics.Debug.WriteLine("MetaSize " + metaSize);

IntPtr hdc = graphics.GetHdc();

//create a metafile, convert the size to himetrics
Metafile metafile = new Metafile(hdc, new
RectangleF(0,0,metaSize.Width,metaSize.Height));

graphics.ReleaseHdc(hdc);

Graphics g = Graphics.FromImage(metafile);
IntPtr hDCEMF = g.GetHdc();

//Calculate the area to render.
SafeNativeMethods.RECT rectLayoutArea;
rectLayoutArea.Left = 0;
rectLayoutArea.Top = 0;
rectLayoutArea.Right = (int)((1440 * metaSize.Width + 2540 / 2)
/ 2540);
rectLayoutArea.Bottom = (int)((1440 * metaSize.Height + 2540 /
2) / 2540);
System.Diagnostics.Debug.WriteLine(String.Format(" RectLayoutArea
({0},{1})",rectLayoutArea.Right,rectLayoutArea.Bot tom));

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);
SafeNativeMethods.SendMessage(this.Handle,
SafeNativeMethods.EM_FORMATRANGE, wParam, IntPtr.Zero);

//Free the block of memory allocated
Marshal.FreeCoTaskMem(lParam);

//Release the device context handle obtained by a previous call
g.ReleaseHdc(hDCEMF);
g.Dispose();

hdc = graphics.GetHdc();
int nHorzSize = SafeNativeMethods.GetDeviceCaps(hdc,
SafeNativeMethods.DeviceCap.HORZSIZE);
int nVertSize = SafeNativeMethods.GetDeviceCaps(hdc,
SafeNativeMethods.DeviceCap.VERTSIZE);
int nHorzRes = SafeNativeMethods.GetDeviceCaps(hdc,
SafeNativeMethods.DeviceCap.HORZRES);
int nVertRes = SafeNativeMethods.GetDeviceCaps(hdc,
SafeNativeMethods.DeviceCap.VERTRES);
int nLogPixelsX = SafeNativeMethods.GetDeviceCaps(hdc,
SafeNativeMethods.DeviceCap.LOGPIXELSX);
int nLogPixelsY = SafeNativeMethods.GetDeviceCaps(hdc,
SafeNativeMethods.DeviceCap.LOGPIXELSY);
graphics.ReleaseHdc(hdc);

float fHorzSizeInches = nHorzSize / 25.4f;
float fVertSizeInches = nVertSize / 25.4f;
float fHorzFudgeFactor = (nHorzRes / fHorzSizeInches) /
nLogPixelsX;
float fVertFudgeFactor = (nVertRes / fVertSizeInches) /
nLogPixelsY;

System.Diagnostics.Debug.WriteLine("Fudge Factor " +
fHorzFudgeFactor.ToString() + " " + fVertFudgeFactor.ToString() + "
XFactor " + xFactor.ToString());

Pen RedPen = new Pen(Color.Red);
graphics.DrawRectangle(RedPen, layoutArea.X * xFactor,
layoutArea.Y * xFactor, layoutArea.Width * xFactor, layoutArea.Height *
xFactor);

float Left = layoutArea.Left;
float Top = layoutArea.Top;
//layoutArea.X = layoutArea.Y = 0;
layoutArea.Offset(-Left, -Top);
layoutArea.Offset(Left / fHorzFudgeFactor, Top /
fVertFudgeFactor);

System.Drawing.Drawing2D.GraphicsState state = graphics.Save();
graphics.ScaleTransform(fHorzFudgeFactor * xFactor,
fVertFudgeFactor * xFactor);
graphics.DrawImage(metafile, layoutArea);
graphics.Restore(state);
System.Diagnostics.Debug.WriteLine("Layout Aread :
"+layoutArea);
}

#region SafeNativeMethods
private static class SafeNativeMethods
{
[DllImport("USER32.dll")]
public static extern IntPtr SendMessage(IntPtr hWnd, int msg,
IntPtr wp, IntPtr lp);

[DllImport("kernel32.dll", CharSet = CharSet.Auto)]
public static extern IntPtr LoadLibrary(string lpFileName);

[DllImport("gdi32.dll")]
public static extern int GetDeviceCaps(IntPtr hdc, DeviceCap
nIndex);

[StructLayout(LayoutKind.Sequential)]
public struct RECT
{
public int Left;
public int Top;
public int Right;
public int Bottom;
}

[StructLayout(LayoutKind.Sequential)]
public struct CHARRANGE
{
public int cpMin; //First character of range (0 for
start of doc)
public int cpMax; //Last character of range (-1 for
end of doc)
}

[StructLayout(LayoutKind.Sequential)]
public struct FORMATRANGE
{
public IntPtr hdc; //Actual DC to draw on
public IntPtr hdcTarget; //Target DC for determining
text formatting
public RECT rc; //Region of the DC
to draw to (in twips)
public RECT rcPage; //Region of the whole DC
(page size) (in twips)
public CHARRANGE chrg; //Range of text to draw (see
earlier declaration)
}

public enum DeviceCap : int
{
/// <summary>
/// Device driver version
/// </summary>
DRIVERVERSION = 0,
/// <summary>
/// Device classification
/// </summary>
TECHNOLOGY = 2,
/// <summary>
/// Horizontal size in millimeters
/// </summary>
HORZSIZE = 4,
/// <summary>
/// Vertical size in millimeters
/// </summary>
VERTSIZE = 6,
/// <summary>
/// Horizontal width in pixels
/// </summary>
HORZRES = 8,
/// <summary>
/// Vertical height in pixels
/// </summary>
VERTRES = 10,
/// <summary>
/// Number of bits per pixel
/// </summary>
BITSPIXEL = 12,
/// <summary>
/// Number of planes
/// </summary>
PLANES = 14,
/// <summary>
/// Number of brushes the device has
/// </summary>
NUMBRUSHES = 16,
/// <summary>
/// Number of pens the device has
/// </summary>
NUMPENS = 18,
/// <summary>
/// Number of markers the device has
/// </summary>
NUMMARKERS = 20,
/// <summary>
/// Number of fonts the device has
/// </summary>
NUMFONTS = 22,
/// <summary>
/// Number of colors the device supports
/// </summary>
NUMCOLORS = 24,
/// <summary>
/// Size required for device descriptor
/// </summary>
PDEVICESIZE = 26,
/// <summary>
/// Curve capabilities
/// </summary>
CURVECAPS = 28,
/// <summary>
/// Line capabilities
/// </summary>
LINECAPS = 30,
/// <summary>
/// Polygonal capabilities
/// </summary>
POLYGONALCAPS = 32,
/// <summary>
/// Text capabilities
/// </summary>
TEXTCAPS = 34,
/// <summary>
/// Clipping capabilities
/// </summary>
CLIPCAPS = 36,
/// <summary>
/// Bitblt capabilities
/// </summary>
RASTERCAPS = 38,
/// <summary>
/// Length of the X leg
/// </summary>
ASPECTX = 40,
/// <summary>
/// Length of the Y leg
/// </summary>
ASPECTY = 42,
/// <summary>
/// Length of the hypotenuse
/// </summary>
ASPECTXY = 44,
/// <summary>
/// Shading and Blending caps
/// </summary>
SHADEBLENDCAPS = 45,

/// <summary>
/// Logical pixels inch in X
/// </summary>
LOGPIXELSX = 88,
/// <summary>
/// Logical pixels inch in Y
/// </summary>
LOGPIXELSY = 90,

/// <summary>
/// Number of entries in physical palette
/// </summary>
SIZEPALETTE = 104,
/// <summary>
/// Number of reserved entries in palette
/// </summary>
NUMRESERVED = 106,
/// <summary>
/// Actual color resolution
/// </summary>
COLORRES = 108,

// Printing related DeviceCaps. These replace the
appropriate Escapes
/// <summary>
/// Physical Width in device units
/// </summary>
PHYSICALWIDTH = 110,
/// <summary>
/// Physical Height in device units
/// </summary>
PHYSICALHEIGHT = 111,
/// <summary>
/// Physical Printable Area x margin
/// </summary>
PHYSICALOFFSETX = 112,
/// <summary>
/// Physical Printable Area y margin
/// </summary>
PHYSICALOFFSETY = 113,
/// <summary>
/// Scaling factor x
/// </summary>
SCALINGFACTORX = 114,
/// <summary>
/// Scaling factor y
/// </summary>
SCALINGFACTORY = 115,

/// <summary>
/// Current vertical refresh rate of the display device
(for displays only) in Hz
/// </summary>
VREFRESH = 116,
/// <summary>
/// Horizontal width of entire desktop in pixels
/// </summary>
DESKTOPVERTRES = 117,
/// <summary>
/// Vertical height of entire desktop in pixels
/// </summary>
DESKTOPHORZRES = 118,
/// <summary>
/// Preferred blt alignment
/// </summary>
BLTALIGNMENT = 119
}
public const int WM_USER = 0x0400;
public const int EM_FORMATRANGE = WM_USER + 57;
public const int WS_EX_TRANSPARENT = 0x20;

}
#endregion
}
}

Oct 28 '08 #2
I setup another machine with Vista 64 and it is happening there too. So it
looks like Vista 64 is the problem!

AliR.

"AliR (VC++ MVP)" <Al**@online.nospamwrote in message
news:5c****************@flpi144.ffdc.sbc.com...
Let me also mention that the laptop that is having the funny results is
running Vista 64, the other machines which everything works fine on is
running Vista 32 or XP.

AliR.
"AliR (VC++ MVP)" <Al**@online.nospamwrote in message
news:pq****************@nlpi068.nbdc.sbc.com...
>I'm trying to write a RTF render code in C#. I have the code in C++/MFC
and it works fine, but I have run into a problem with the C# code. I
think the C# code is from Microsoft, and I added scaling to it. The C#
code is working fine on my desktop PC but it cuts off some of the text
when I run it on my laptop. The MFC code works fine both on the laptop
and the PC. I have looked at all the numbers used in the MFC and the C#
code and they are identical. Both PC and Laptop are at 1440x900 96dpi
font size.

I have been looking at the code for 3 or 4 days now without any
improvment. Was wondering if anyone here wants to take a stab at it.

You can download both sample projects:
http://www.learnstar.com/AliR/RTFScaler.zip
http://www.learnstar.com/AliR/RTFScalerMFC.zip
Thanks
AliR.
Here is the MFC code
// *** copying/scaling/rotating and shearing the text is done here
void CRTFScalerDlg::RenderText(int nScalePercent,int nRotationDegrees,int
nHorzShearPercent,int nVertShearPercent)
{
// validate the arguments
if (nScalePercent < 1)
nScalePercent = 1;
if (nScalePercent 10000)
nScalePercent = 10000;
if (nRotationDegrees < 0)
nRotationDegrees = 0;
if (nRotationDegrees 360)
nRotationDegrees = 360;
if (nHorzShearPercent < 0)
nHorzShearPercent = 0;
if (nHorzShearPercent 100)
nHorzShearPercent = 100;
if (nVertShearPercent < 0)
nVertShearPercent = 0;
if (nVertShearPercent 100)
nVertShearPercent = 100;

// setup target window, rect and DC
CWnd* pTargetWin = GetDlgItem(IDC_EDIT1);
CRect crTarget;
pTargetWin->GetClientRect(&crTarget);
crTarget.OffsetRect(0,20);
CDC* pTargetDC = pTargetWin->GetDC();
pTargetDC->IntersectClipRect(&crTarget); // so we don't clobber the
parent dialog
pTargetDC->SetBkMode(TRANSPARENT); // so the legend doesn't erase too
much

// also need advanced graphics mode for the world transform stuff
if (!SetGraphicsMode(pTargetDC->m_hDC,GM_ADVANCED))
{
pTargetDC->DrawText("Nice try but I need Windows NT, 2000, XP or 2003
for this.",crTarget,DT_SINGLELINE | DT_VCENTER | DT_CENTER);
return;
}

// erase previous contents
FillRect(pTargetDC->m_hDC,crTarget,(HBRUSH)(COLOR_WINDOW + 1));
CString Temp;
Temp.Format("crTarget %d,%d
%d,%d\n",crTarget.left,crTarget.top,crTarget.Widt h(),crTarget.Height());
TRACE(Temp);

// setup rectangles for metafile fiddling
CSize cTargetSize = crTarget.Size();
pTargetDC->DPtoHIMETRIC(&cTargetSize); // from MM_Text to MM_HIMETRIC
CSize TopLeft;
TopLeft.cx = crTarget.left;
TopLeft.cy = crTarget.top;
pTargetDC->DPtoHIMETRIC(&TopLeft); // 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);

Temp.Format("MetaSize
%d,%d\n",cHiMetricRect.Width(),cHiMetricRect.Heig ht());
TRACE(Temp);
Temp.Format("cTwipsRect %d,%d\n",cTwipsRect.Width(),cTwipsRect.Height());
TRACE(Temp);
// create the enhanced metafile
HDC hDCEMF = CreateEnhMetaFile(pTargetDC->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;
GetDlgItem(IDC_RICHEDIT1)->SendMessage(EM_FORMATRANGE,TRUE,(LPARAM)
&stFR);
GetDlgItem(IDC_RICHEDIT1)->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 = pTargetDC->GetDeviceCaps(HORZSIZE ); // width in
millimeters
int nVertSize = pTargetDC->GetDeviceCaps(VERTSIZE ); // height in
millimeters
int nHorzRes = pTargetDC->GetDeviceCaps(HORZRES ); // width in
pixels
int nVertRes = pTargetDC->GetDeviceCaps(VERTRES ); // height in
pixels
int nLogPixelsX = pTargetDC->GetDeviceCaps(LOGPIXELSX); // # of pixels
per inch horizontally
int nLogPixelsY = pTargetDC->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; //

Temp.Format("Fudgfactor %.2f %.2f\n",fHorzFudgeFactor,fVertFudgeFactor);
TRACE(Temp);

// change from degrees to radians
// (also need to change sign since page space is upside down)
float fRotationInRadians = (PI * (0 - nRotationDegrees)) / 180.0F;

// do the world transforms, first apply the scale and fudge factors
XFORM stX;
ZeroMemory(&stX,sizeof(stX));
stX.eM11 = fHorzFudgeFactor * (nScalePercent / 100.0f);
stX.eM22 = fVertFudgeFactor * (nScalePercent / 100.0f);
SetWorldTransform(pTargetDC->m_hDC,&stX);

// then apply the rotation
ZeroMemory(&stX,sizeof(stX));
stX.eM11 = (float) cos(fRotationInRadians);
stX.eM12 = (float) sin(fRotationInRadians);
stX.eM21 = 0 - (float) sin(fRotationInRadians);
stX.eM22 = (float) cos(fRotationInRadians);
ModifyWorldTransform(pTargetDC->m_hDC,&stX,MWT_LEFTMULTIPLY);

// finally apply the horizontal and vertical shearing
ZeroMemory(&stX,sizeof(stX));
stX.eM11 = 1.0f;
stX.eM12 = nHorzShearPercent / 100.0f;
stX.eM21 = nVertShearPercent / 100.0f;
stX.eM22 = 1.0f;
ModifyWorldTransform(pTargetDC->m_hDC,&stX,MWT_LEFTMULTIPLY);

crTarget.OffsetRect(0,-20);
crTarget.OffsetRect(0,20 / (nScalePercent / 100.0f) * fVertFudgeFactor);
// play the metafile
pTargetDC->PlayMetaFile(hEMF,&crTarget);

// that's it, kiss the metafile goodbye
DeleteEnhMetaFile(hEMF);

// also show a legend
ModifyWorldTransform(pTargetDC->m_hDC,NULL,MWT_IDENTITY);
CString sLegend;
sLegend.Format("Scale: %d%% rotation: %dº horizontal shear: %d%%
vertical shear: %d%%.",
nScalePercent,nRotationDegrees,nHorzShearPercent,n VertShearPercent);
pTargetDC->SetTextColor(RGB(55,111,111));
pTargetDC->DrawText(sLegend,crTarget,DT_SINGLELINE | DT_VCENTER |
DT_CENTER);
}
Here is the C# code:

using System;
using System.Drawing;
using System.Runtime.InteropServices;
using System.Windows.Forms;
using System.Drawing.Imaging;
using System.Text;

public static class Graphics_DrawRtfText
{
private static RichTextBoxDrawer rtfDrawer;
public static void DrawRtfText(this Graphics graphics, string rtf,
RectangleF layoutArea,float xFactor)
{
if (Graphics_DrawRtfText.rtfDrawer == null)
{
Graphics_DrawRtfText.rtfDrawer = new RichTextBoxDrawer();
}
Graphics_DrawRtfText.rtfDrawer.Rtf = rtf;
Graphics_DrawRtfText.rtfDrawer.Draw(graphics, layoutArea,xFactor);
}

private class RichTextBoxDrawer : RichTextBox
{
//Code converted from code found here:
http://support.microsoft.com/kb/812425/en-us

//Convert the unit used by the .NET framework (1/100 inch)
//and the unit used by Win32 API calls (twips 1/1440 inch)
private const double anInch = 14.4;

protected override CreateParams CreateParams
{
get
{
CreateParams createParams = base.CreateParams;
if (SafeNativeMethods.LoadLibrary("msftedit.dll") !=
IntPtr.Zero)
{
createParams.ExStyle |=
SafeNativeMethods.WS_EX_TRANSPARENT; // transparent
createParams.ClassName = "RICHEDIT50W";
}
return createParams;
}
}

private void DPToHIMETRIC(Graphics graphics,ref SizeF size)
{
size.Width = (size.Width * 2540.0f) / graphics.DpiX;
size.Height = (size.Height * 2540.0f) / graphics.DpiY;
}

public void Draw(Graphics graphics, RectangleF layoutArea, float
xFactor)
{
System.Diagnostics.Debug.WriteLine("LayoutArea " +
layoutArea);

SizeF metaSize = layoutArea.Size;
DPToHIMETRIC(graphics, ref metaSize);

System.Diagnostics.Debug.WriteLine("MetaSize " + metaSize);

IntPtr hdc = graphics.GetHdc();

//create a metafile, convert the size to himetrics
Metafile metafile = new Metafile(hdc, new
RectangleF(0,0,metaSize.Width,metaSize.Height)) ;

graphics.ReleaseHdc(hdc);

Graphics g = Graphics.FromImage(metafile);
IntPtr hDCEMF = g.GetHdc();

//Calculate the area to render.
SafeNativeMethods.RECT rectLayoutArea;
rectLayoutArea.Left = 0;
rectLayoutArea.Top = 0;
rectLayoutArea.Right = (int)((1440 * metaSize.Width + 2540 /
2) / 2540);
rectLayoutArea.Bottom = (int)((1440 * metaSize.Height + 2540 /
2) / 2540);
System.Diagnostics.Debug.WriteLine(String.Format( "RectLayoutArea
({0},{1})",rectLayoutArea.Right,rectLayoutArea.Bo ttom));

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);
SafeNativeMethods.SendMessage(this.Handle,
SafeNativeMethods.EM_FORMATRANGE, wParam, IntPtr.Zero);

//Free the block of memory allocated
Marshal.FreeCoTaskMem(lParam);

//Release the device context handle obtained by a previous
call
g.ReleaseHdc(hDCEMF);
g.Dispose();

hdc = graphics.GetHdc();
int nHorzSize = SafeNativeMethods.GetDeviceCaps(hdc,
SafeNativeMethods.DeviceCap.HORZSIZE);
int nVertSize = SafeNativeMethods.GetDeviceCaps(hdc,
SafeNativeMethods.DeviceCap.VERTSIZE);
int nHorzRes = SafeNativeMethods.GetDeviceCaps(hdc,
SafeNativeMethods.DeviceCap.HORZRES);
int nVertRes = SafeNativeMethods.GetDeviceCaps(hdc,
SafeNativeMethods.DeviceCap.VERTRES);
int nLogPixelsX = SafeNativeMethods.GetDeviceCaps(hdc,
SafeNativeMethods.DeviceCap.LOGPIXELSX);
int nLogPixelsY = SafeNativeMethods.GetDeviceCaps(hdc,
SafeNativeMethods.DeviceCap.LOGPIXELSY);
graphics.ReleaseHdc(hdc);

float fHorzSizeInches = nHorzSize / 25.4f;
float fVertSizeInches = nVertSize / 25.4f;
float fHorzFudgeFactor = (nHorzRes / fHorzSizeInches) /
nLogPixelsX;
float fVertFudgeFactor = (nVertRes / fVertSizeInches) /
nLogPixelsY;

System.Diagnostics.Debug.WriteLine("Fudge Factor " +
fHorzFudgeFactor.ToString() + " " + fVertFudgeFactor.ToString() + "
XFactor " + xFactor.ToString());

Pen RedPen = new Pen(Color.Red);
graphics.DrawRectangle(RedPen, layoutArea.X * xFactor,
layoutArea.Y * xFactor, layoutArea.Width * xFactor, layoutArea.Height *
xFactor);

float Left = layoutArea.Left;
float Top = layoutArea.Top;
//layoutArea.X = layoutArea.Y = 0;
layoutArea.Offset(-Left, -Top);
layoutArea.Offset(Left / fHorzFudgeFactor, Top /
fVertFudgeFactor);

System.Drawing.Drawing2D.GraphicsState state =
graphics.Save();
graphics.ScaleTransform(fHorzFudgeFactor * xFactor,
fVertFudgeFactor * xFactor);
graphics.DrawImage(metafile, layoutArea);
graphics.Restore(state);
System.Diagnostics.Debug.WriteLine("Layout Aread :
"+layoutArea);
}

#region SafeNativeMethods
private static class SafeNativeMethods
{
[DllImport("USER32.dll")]
public static extern IntPtr SendMessage(IntPtr hWnd, int msg,
IntPtr wp, IntPtr lp);

[DllImport("kernel32.dll", CharSet = CharSet.Auto)]
public static extern IntPtr LoadLibrary(string lpFileName);

[DllImport("gdi32.dll")]
public static extern int GetDeviceCaps(IntPtr hdc, DeviceCap
nIndex);

[StructLayout(LayoutKind.Sequential)]
public struct RECT
{
public int Left;
public int Top;
public int Right;
public int Bottom;
}

[StructLayout(LayoutKind.Sequential)]
public struct CHARRANGE
{
public int cpMin; //First character of range (0 for
start of doc)
public int cpMax; //Last character of range (-1 for
end of doc)
}

[StructLayout(LayoutKind.Sequential)]
public struct FORMATRANGE
{
public IntPtr hdc; //Actual DC to draw on
public IntPtr hdcTarget; //Target DC for determining
text formatting
public RECT rc; //Region of the DC
to draw to (in twips)
public RECT rcPage; //Region of the whole
DC (page size) (in twips)
public CHARRANGE chrg; //Range of text to draw (see
earlier declaration)
}

public enum DeviceCap : int
{
/// <summary>
/// Device driver version
/// </summary>
DRIVERVERSION = 0,
/// <summary>
/// Device classification
/// </summary>
TECHNOLOGY = 2,
/// <summary>
/// Horizontal size in millimeters
/// </summary>
HORZSIZE = 4,
/// <summary>
/// Vertical size in millimeters
/// </summary>
VERTSIZE = 6,
/// <summary>
/// Horizontal width in pixels
/// </summary>
HORZRES = 8,
/// <summary>
/// Vertical height in pixels
/// </summary>
VERTRES = 10,
/// <summary>
/// Number of bits per pixel
/// </summary>
BITSPIXEL = 12,
/// <summary>
/// Number of planes
/// </summary>
PLANES = 14,
/// <summary>
/// Number of brushes the device has
/// </summary>
NUMBRUSHES = 16,
/// <summary>
/// Number of pens the device has
/// </summary>
NUMPENS = 18,
/// <summary>
/// Number of markers the device has
/// </summary>
NUMMARKERS = 20,
/// <summary>
/// Number of fonts the device has
/// </summary>
NUMFONTS = 22,
/// <summary>
/// Number of colors the device supports
/// </summary>
NUMCOLORS = 24,
/// <summary>
/// Size required for device descriptor
/// </summary>
PDEVICESIZE = 26,
/// <summary>
/// Curve capabilities
/// </summary>
CURVECAPS = 28,
/// <summary>
/// Line capabilities
/// </summary>
LINECAPS = 30,
/// <summary>
/// Polygonal capabilities
/// </summary>
POLYGONALCAPS = 32,
/// <summary>
/// Text capabilities
/// </summary>
TEXTCAPS = 34,
/// <summary>
/// Clipping capabilities
/// </summary>
CLIPCAPS = 36,
/// <summary>
/// Bitblt capabilities
/// </summary>
RASTERCAPS = 38,
/// <summary>
/// Length of the X leg
/// </summary>
ASPECTX = 40,
/// <summary>
/// Length of the Y leg
/// </summary>
ASPECTY = 42,
/// <summary>
/// Length of the hypotenuse
/// </summary>
ASPECTXY = 44,
/// <summary>
/// Shading and Blending caps
/// </summary>
SHADEBLENDCAPS = 45,

/// <summary>
/// Logical pixels inch in X
/// </summary>
LOGPIXELSX = 88,
/// <summary>
/// Logical pixels inch in Y
/// </summary>
LOGPIXELSY = 90,

/// <summary>
/// Number of entries in physical palette
/// </summary>
SIZEPALETTE = 104,
/// <summary>
/// Number of reserved entries in palette
/// </summary>
NUMRESERVED = 106,
/// <summary>
/// Actual color resolution
/// </summary>
COLORRES = 108,

// Printing related DeviceCaps. These replace the
appropriate Escapes
/// <summary>
/// Physical Width in device units
/// </summary>
PHYSICALWIDTH = 110,
/// <summary>
/// Physical Height in device units
/// </summary>
PHYSICALHEIGHT = 111,
/// <summary>
/// Physical Printable Area x margin
/// </summary>
PHYSICALOFFSETX = 112,
/// <summary>
/// Physical Printable Area y margin
/// </summary>
PHYSICALOFFSETY = 113,
/// <summary>
/// Scaling factor x
/// </summary>
SCALINGFACTORX = 114,
/// <summary>
/// Scaling factor y
/// </summary>
SCALINGFACTORY = 115,

/// <summary>
/// Current vertical refresh rate of the display device
(for displays only) in Hz
/// </summary>
VREFRESH = 116,
/// <summary>
/// Horizontal width of entire desktop in pixels
/// </summary>
DESKTOPVERTRES = 117,
/// <summary>
/// Vertical height of entire desktop in pixels
/// </summary>
DESKTOPHORZRES = 118,
/// <summary>
/// Preferred blt alignment
/// </summary>
BLTALIGNMENT = 119
}
public const int WM_USER = 0x0400;
public const int EM_FORMATRANGE = WM_USER + 57;
public const int WS_EX_TRANSPARENT = 0x20;

}
#endregion
}
}


Oct 28 '08 #3

This thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

2
by: John Fouhy | last post by:
So I've got a horizontal scale widget in my GUI. When I click the mouse in the area to the right of the GUI, the scale advances by 1. 13 +-------------------------+ |<| X |>|...
4
by: codecraig | last post by:
Hi, I am using Tkinter and I have a Label and a Scale. I want to update my label everytime the Scale value changes. What is the best way of doing this? Do i have to bind for every event type? ...
5
by: Guess | last post by:
The situation is as follows: 1. I would like to serve a web page that takes considerable time to process. 2. While the page is processing, the client displays an appropriate wait message. What...
3
by: John Bonds | last post by:
I'm looking for some sort of digital scale to integrate into .NET. Does anybody know of anything (like a postal scale) that attaches to USB, serial or whatever that comes with a DLL or an API...
3
by: Jay Patel | last post by:
Hello, I need to write visual basic.net code to interface with a Mettler Toledo Shipping Scale that interfaces with a PC via USB or a serial port. I have seen example code on how to communicate...
3
by: Jerry Spence1 | last post by:
A very useful feature was added in 2.0 of .NET framework which was the scaling of a form and all the controls within it. This is really useful but I am finding very little information of how to use...
0
by: TonyJ | last post by:
Hello! We have a pc running a form application. If I push some buttons in this application I want to send some commands to a scale which is connected to a specific IP address. When I sent a...
19
by: Matteo Migliore | last post by:
Hi! I've to scale a vector of numbers of size N to a vector of size M. The trasformation is like a zoom on images but I need on a vector. The second size can be M >= N or M <= N, M 0. The...
22
by: Jesse Burns | last post by:
I'm about to start working on my first large scale site (in my opinion) that will hopefully have 1000+ users a day. ok, this isn't on the google/facebook scale, but it's going to be have more hits...
0
by: Charles Arthur | last post by:
How do i turn on java script on a villaon, callus and itel keypad mobile phone
0
BarryA
by: BarryA | last post by:
What are the essential steps and strategies outlined in the Data Structures and Algorithms (DSA) roadmap for aspiring data scientists? How can individuals effectively utilize this roadmap to progress...
1
by: nemocccc | last post by:
hello, everyone, I want to develop a software for my android phone for daily needs, any suggestions?
1
by: Sonnysonu | last post by:
This is the data of csv file 1 2 3 1 2 3 1 2 3 1 2 3 2 3 2 3 3 the lengths should be different i have to store the data by column-wise with in the specific length. suppose the i have to...
0
by: Hystou | last post by:
There are some requirements for setting up RAID: 1. The motherboard and BIOS support RAID configuration. 2. The motherboard has 2 or more available SATA protocol SSD/HDD slots (including MSATA, M.2...
0
by: Hystou | last post by:
Most computers default to English, but sometimes we require a different language, especially when relocating. Forgot to request a specific language before your computer shipped? No problem! You can...
0
Oralloy
by: Oralloy | last post by:
Hello folks, I am unable to find appropriate documentation on the type promotion of bit-fields when using the generalised comparison operator "<=>". The problem is that using the GNU compilers,...
0
jinu1996
by: jinu1996 | last post by:
In today's digital age, having a compelling online presence is paramount for businesses aiming to thrive in a competitive landscape. At the heart of this digital strategy lies an intricately woven...
0
by: Hystou | last post by:
Overview: Windows 11 and 10 have less user interface control over operating system update behaviour than previous versions of Windows. In Windows 11 and 10, there is no way to turn off the Windows...

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.