Problem z rysowaniem tekstu z wykorzystaniem Aero Glass

0

Witam.
Na formie całej "ze szkła", co jakiś określony czas (np co sekundę) rysuję kilka-kilkanaście napisów (zawsze w tym samym miejscu, zmienia się po prostu tylko tekst). Problem w tym, że po pewnym czasie działania programu użycie procesora ciągle wzrasta, aż w końcu aplikacja przestaje działać. Problem zapewne tkwi w zwalnianiu zasobów... Tylko jak to zrobić w tym wypadku? Jestem kompletnie zielony w temacie rysowania (zwłaszcza na szkle), a klasę Glass znalazłem w sieci i nie wiem dokładnie jak działa metoda DrawTextOnGlass dlatego proszę o jakiekolwiek wskazówki.

Kod mojej formy wygląda w uproszczeniu tak:

Random rnd = new Random();

public frmMain()
        {
            InitializeComponent();
            BackColor = Color.Black;
            Glass.MARGINS m = new Glass.MARGINS(-1, -1, -1, -1);
            Glass.DwmExtendFrameIntoClientArea(this.Handle, ref m);
        }

void timerDraw_Tick(object sender, EventArgs e)
        {
            int y = 0;
            for (int i = 0; i < 15; i++)
            {
                int r = rnd.Next(0, 999); // tekstem niech będzie np. jakaś losowa liczba
                Glass.DrawTextOnGlass(this.Handle, r.ToString(), this.Font, new Rectangle(5, y, 40, 15), 10);
                y += 35;
            }
        }

A tak wygląda istotna część klasy Glass :

        [DllImport("gdi32.dll")]
        private static extern bool BitBlt(IntPtr hdc, int nXDest, int nYDest, int nWidth, int nHeight, IntPtr hdcSrc, int nXSrc, int nYSrc, uint dwRop);
        [DllImport("gdi32.dll", SetLastError = true, ExactSpelling = true)]
        private static extern IntPtr CreateCompatibleDC(IntPtr hDC);
        [DllImport("gdi32.dll", SetLastError = true, ExactSpelling = true)]
        private static extern IntPtr CreateDIBSection(IntPtr hdc, ref BITMAPINFO pbmi, uint iUsage, int ppvBits, IntPtr hSection, uint dwOffset);
        [DllImport("gdi32.dll", SetLastError = true, ExactSpelling = true)]
        private static extern bool DeleteDC(IntPtr hdc);
        [DllImport("gdi32.dll", SetLastError = true, ExactSpelling = true)]
        private static extern bool DeleteObject(IntPtr hObject);

        [DllImport("UxTheme.dll", SetLastError = true, ExactSpelling = true)]
        private static extern int DrawThemeText(IntPtr hTheme, IntPtr hdc, int iPartId, int iStateId, string text, int iCharCount, int dwFlags1, int dwFlags2, ref RECT pRect);
        [DllImport("UxTheme.dll", CharSet = CharSet.Unicode, SetLastError = true, ExactSpelling = true)]
        private static extern int DrawThemeTextEx(IntPtr hTheme, IntPtr hdc, int iPartId, int iStateId, string text, int iCharCount, int dwFlags, ref RECT pRect, ref DTTOPTS pOptions);
        [DllImport("dwmapi.dll", PreserveSig = false)]
        public static extern void DwmEnableComposition(bool bEnable);
        [DllImport("dwmapi.dll")]
        internal static extern void DwmExtendFrameIntoClientArea(IntPtr hWnd, ref MARGINS pMargins);
        [DllImport("dwmapi.dll")]
        internal static extern void DwmIsCompositionEnabled(ref bool isEnabled);

        public static void DrawTextOnGlass(IntPtr hwnd, string text, Font font, Rectangle ctlrct, int iglowSize)
        {
            if (IsCompositionEnabled())
            {
                RECT rect = new RECT();
                RECT pRect = new RECT();
                rect.left = ctlrct.Left;
                rect.right = ctlrct.Right + (2 * iglowSize);
                rect.top = ctlrct.Top;
                rect.bottom = ctlrct.Bottom + (2 * iglowSize);
                pRect.left = 0;
                pRect.top = 0;
                pRect.right = rect.right - rect.left;
                pRect.bottom = rect.bottom - rect.top;
                IntPtr dC = GetDC(hwnd);
                IntPtr hdc = CreateCompatibleDC(dC);
                IntPtr zero = IntPtr.Zero;
                int dwFlags = 0x825;
                BITMAPINFO pbmi = new BITMAPINFO();
                pbmi.bmiHeader.biHeight = -(rect.bottom - rect.top);
                pbmi.bmiHeader.biWidth = rect.right - rect.left;
                pbmi.bmiHeader.biPlanes = 1;
                pbmi.bmiHeader.biSize = Marshal.SizeOf(typeof(BITMAPINFOHEADER));
                pbmi.bmiHeader.biBitCount = 0x20;
                pbmi.bmiHeader.biCompression = 0;
                if (SaveDC(hdc) != 0)
                {
                    IntPtr hObject = CreateDIBSection(hdc, ref pbmi, 0, 0, IntPtr.Zero, 0);
                    if (hObject != IntPtr.Zero)
                    {
                        zero = SelectObject(hdc, hObject);
                        IntPtr ptr6 = font.ToHfont();
                        IntPtr ptr5 = SelectObject(hdc, ptr6);
                        try
                        {
                            VisualStyleRenderer renderer = new VisualStyleRenderer(VisualStyleElement.Window.Caption.Active);
                            DTTOPTS pOptions = new DTTOPTS();
                            pOptions.dwSize = (uint)Marshal.SizeOf(typeof(DTTOPTS));
                            pOptions.dwFlags = 0x2800;
                            pOptions.iGlowSize = iglowSize;
                            DrawThemeTextEx(renderer.Handle, hdc, 0, 0, text, -1, dwFlags, ref pRect, ref pOptions);
                            BitBlt(dC, rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top, hdc, 0, 0, 0xcc0020);
                        }
                        catch (Exception exception)
                        {
                            Trace.WriteLine(exception.Message);
                        }
                        SelectObject(hdc, zero);
                        SelectObject(hdc, ptr5);
                        DeleteObject(hObject);
                        DeleteObject(ptr6);
                        ReleaseDC(hdc, -1);
                        DeleteDC(hdc);
                    }
                }
            }
        }
0

po co robisz SaveDC skoro nigdzie nie robisz RestoreDC?

0

Nie ja. To znalezione w sieci. Jako że nie orientuję się w tym, chciałem żeby ktoś na to rzucił okiem w miarę możliwości ;)
OK, wywaliłem warunek z SaveDC, ale w niczym to nie pomogło, nadal ten sam efekt.

0

możesz dać działającego exeka z kodem gdzieś?

0

Cały projekt jest tutaj: http://www45.zippyshare.com/v/79839678/file.html
Na moim komputerze, system zaczyna wyraźnie zwalniać po ~4min działania aplikacji.

0

zmień kod tak
//if (SaveDC(hdc) != 0)
//{
IntPtr hObject = CreateDIBSection(hdc, ref pbmi, 0, 0, IntPtr.Zero, 0);
if (hObject != IntPtr.Zero)
{
zero = SelectObject(hdc, hObject);
IntPtr ptr6 = font.ToHfont();
IntPtr ptr5 = SelectObject(hdc, ptr6);
try
{
VisualStyleRenderer renderer = new VisualStyleRenderer(VisualStyleElement.Window.Caption.Active);
DTTOPTS pOptions = new DTTOPTS();
pOptions.dwSize = (uint)Marshal.SizeOf(typeof(DTTOPTS));
pOptions.dwFlags = 0x2800;
pOptions.iGlowSize = iglowSize;
DrawThemeTextEx(renderer.Handle, hdc, 0, 0, text, -1, dwFlags, ref pRect, ref pOptions);
BitBlt(dC, rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top, hdc, 0, 0, 0xcc0020);
}
catch (Exception exception)
{
Trace.WriteLine(exception.Message);
}
DeleteObject(hObject);

                    hObject = SelectObject(hdc, zero);
                    DeleteObject(hObject);
                    
                    hObject = SelectObject(hdc, ptr5);
                    DeleteObject(hObject);

                    DeleteObject(ptr6);

                    ReleaseDC(hdc, -1);
                    DeleteDC(hdc);
                //}

nie mam aktualnie zainstalowanego C# więc tego nie przetestuję ale powinno być OK

BTW w metodzie FillBlackRegion też jest babol, który nie zwalnia obiektów GDI - do poprawy analogicznie jak tu - trzeba zwolnić obiekty zwrócone przez SelectObject
0

Ciągle to samo... W kazdym razie dzięki za fatygę. Będę walczył z tym dalej..

EDIT:
ok, znalazłem rozwiązanie problemu, który zresztą był trywialny, bo wystarczyło usuwać jeszcze dC i wszystko śmiga aż miło ;)

1 użytkowników online, w tym zalogowanych: 0, gości: 1