हम "पिक्सेल परफेक्ट" के लिए प्रयास करते हैं + RDP से विंडो छिपाते हैं!

यह उपसर्ग "15000 एफपीएस" के साथ पदों की एक श्रृंखला का एक सिलसिला है, यहां शुरुआत:
भाग 1 और
भाग 1.5 । इस विंडो के लिए 15K FPS को प्राप्त करना संभव है, लेकिन यहां एक उचित दृष्टिकोण FPS को रेंडर () चक्र में हथौड़ा करने के लिए नहीं है, लेकिन केवल यदि आवश्यक हो, तो फिर से शुरू करने के लिए है, और विंडोज हमारे लिए अधिकांश आराम करेगा। स्क्रीनशॉट को देखते हुए, एनकोडर का पहला विचार "हा है, लेकिन हम सभी कस्टम विंडो कर सकते हैं!"
लेकिन डिजाइनर को संदेह होने की अधिक संभावना है कि कुछ गलत था: खिड़की से छाया किसी तरह विंडोज नहीं है, और सामान्य तौर पर ग्रेडिएंट और अल्फा मिश्रण होते हैं, अल्फा चैनल पर कुछ ईमानदार 8 बिट्स थे। कैसे?
और आपको केवल Win32 API + System.Drawing.Bitmap की जरूरत है, यह .net 2.0 के साथ
Win2K पर भी काम करेगा, और यह विंडो बहुत ही शानदार है और जल्दी से स्केल और बिना ग्लिट्स के चलती है।
"क्या कस्टम अल्फा-मिक्सिंग विंडो डेस्कटॉप पर है और धीमा नहीं है?" क्या तुम मजाक कर रहे हो? ”
मैं बिल्कुल मजाक नहीं कर रहा हूं। तो, शुरुआत के लिए, इस खिड़की की भविष्य की त्वचा के लिए एक कट तैयार करें।

चूंकि लेख डिजाइन ब्लॉग पर भी प्रकाशित हुआ है, इसलिए मैं डिजाइनरों से कहता हूं कि वे मुझे पिक्सेल परफेक्ट की कमी के लिए लात न मारें - मैंने खुद इस धागे को बनाया था ... मेरे जैसे कोडर्स उम्र के हिसाब से अपने फोटोशॉप को जानने और लॉजिक में संगीत लिखने का तरीका सीखते हैं। , और बड़ी जरूरत के मामले में, मैं खुद एक चित्रफलक और पियानो का मालिक हूं, जहां तक मैं कर सकता हूं।
लेकिन आप तुरंत नोटिस कर सकते हैं कि कोनों को गोल करना पहले से ही देशी खिड़कियों की तुलना में बेहतर परिमाण का एक क्रम है - और सभी क्योंकि विंडोज वेक्टर क्षेत्र का उपयोग करता है, जो कभी भी विरोधी नहीं है, और मैं एक धोखेबाज़ हूं।
लेकिन निश्चित रूप से, आप एक बेहतर परिणाम प्राप्त कर सकते हैं यदि आप एक सच्चे असतत डिजाइनर को आकर्षित करते हैं। किसी भी डिजाइनर के लिए जो आगे के पाठ को उबाऊ पाते हैं, आप तुरंत लेख के अंत में सोर्स कोड और कोडप्लेक्स पर एक नमूना के साथ एक पूर्ण परियोजना के लिए जा सकते हैं। और अपने कोडर्स को पीड़ा दें कि आपके पास विंडोज़ के लिए सैकड़ों विचार और चिप्स हैं और फ़ोटोशॉप से 32-बिट पीएनजी तक सही नियंत्रण है (बस यह मत कहो कि आपने इसके बारे में किससे सीखा, इस तरह के रोमांच के लिए एनकोडर मुझे नहीं बताएंगे)।
जैसा कि आप देख सकते हैं, हमारे पास 4 कोने तत्व हैं, जिनके बीच में हम मध्य तत्वों को फैलाएंगे, और मुख्य विंडो पृष्ठभूमि को इसके माध्यम से भरेंगे:
GFX.Clear(WindowFillColor);
हां, हमारी पूरी विंडो बेवकूफ है। सिस्टमिंग। बिटमैप, लेकिन जो लोग लेख के आखिरी हिस्सों को पढ़ते हैं, वे जानते हैं कि मैं इसके लिए कितना आंशिक हूं। ग्राफिक्स पर सरल ऑपरेशन द्वारा त्वचा के टुकड़ों से खिड़की की पृष्ठभूमि को आसानी से इकट्ठा किया जाता है।
(शीर्षक में स्क्रीनशॉट के लिए, मैंने इसके बजाय ग्रेडिएंटब्रश फिल का उपयोग किया है, लेकिन यह केवल स्क्रीनशॉट में विशेष प्रभाव के लिए है)
मैं लेख के मुख्य बिंदुओं को छूऊंगा, और मैंने बहुत अधिक विवरणों का वर्णन नहीं किया है - मैं ट्यूटोरियल का दिखावा नहीं करता, सार कोडप्लेक्स प्रकार के साथ अधिक है, वहाँ के स्रोत, पिछले भागों की तरह, एक बूट के रूप में सरल हैं, मैंने कोशिश की।
बस थोड़ा सा धोखा। पिछले भागों में, मैं एक पूर्ण अल्फा चैनल के लिए था, लेकिन यहां, इसके विपरीत। चूंकि त्वचा के शुरुआती बिटमैप्स प्रत्येक रिड्रा के साथ नहीं बदलते हैं, आप सुरक्षित रूप से प्रीमोल्टिप्लीड अल्फा का उपयोग कर सकते हैं, और आवेदन की शुरुआत में ऐसा करते हैं:
internal static Bitmap Shadow_L = Resources.Shadow_L.Clone( new Rectangle(0, 0, Resources.Shadow_L.Width, Resources.Shadow_L.Height), PixelFormat.Format32bppPArgb);
यानी हम एप्लिकेशन के संसाधनों से त्वचा का एक टुकड़ा लेते हैं, और इसे एक बार पंप करते हैं, "सही शब्द" अल्फा के लिए पूर्व-अनुकूलित "?] और फिर इसे स्थिर वर्ग से उपयोग करें, और यह एफपीएस को बहुत बढ़ाता है। लाभ।
इस अजीब खिड़की को कैसे खींचना है?
पिछले समय की तरह, हमें Win32 API की आवश्यकता होगी।
हम कुछ "जादू स्थिरांक" की जरूरत है:
public const Int32 ULW_COLORKEY = 0x00000001; public const Int32 ULW_ALPHA = 0x00000002; public const Int32 ULW_OPAQUE = 0x00000004; public const byte AC_SRC_OVER = 0x00; public const byte AC_SRC_ALPHA = 0x01; public const uint WM_SYSCOMMAND = 0x0112; public const uint DOMOVE = 0xF012; public const uint DOSIZE1 = 0xF001;
कुछ पूछेंगे: "क्या Win32 वास्तव में वहाँ कुछ नंबरों पर पकड़ है?" लेकिन अधिकांश भाग के लिए, यह निहितार्थ रूपांतरणों के माध्यम से हल किया गया था। 486 के समय में, "सब कुछ एक वस्तु है" की अवधारणा निषेधात्मक अपशिष्ट रही होगी!
और कुछ आयात:
[DllImport("user32.dll", ExactSpelling = true, SetLastError = true)] public static extern IntPtr GetDC(IntPtr hWnd); [DllImport("user32.dll", ExactSpelling = true)] public static extern int ReleaseDC(IntPtr hWnd, IntPtr hDC); [DllImport("gdi32.dll", ExactSpelling = true, SetLastError = true)] public static extern IntPtr CreateCompatibleDC(IntPtr hDC); [DllImport("gdi32.dll", ExactSpelling = true, SetLastError = true)] public static extern TBool DeleteDC(IntPtr hdc);
विंडो फॉर्म बनाते समय
कुंजी विधि # 1 है:
protected override CreateParams CreateParams { get { CreateParams cp = base.CreateParams; if (!DesignMode) cp.ExStyle |= 0x00080000; return cp; } }
गंभीर MFC एन्कोडर खुशी से परिचित "CreateParams" को पहचानते हैं, लेकिन स्टाइल स्थिरांक से आश्चर्यचकित होते हैं।
लेकिन अब हमारी खिड़की एक नपुंसक खिड़की की तरह हो गई है।
मुख्य विधि # 2 । कल्पना करें कि इससे पहले हमने बिटमैप में अपनी खिड़की का एक दृश्य पहले ही याद में खींच लिया था। उससे समझ बनाने के लिए:
private void AssignGFX() { IntPtr screenDc = Win32Helper.GetDC(IntPtr.Zero); IntPtr memDc = Win32Helper.CreateCompatibleDC(screenDc); IntPtr hBitmap = IntPtr.Zero; IntPtr objBitmap = IntPtr.Zero; try { hBitmap = BMP.GetHbitmap(Color.FromArgb(0)); objBitmap = Win32Helper.SelectObject(memDc, hBitmap); TSize size = new TSize(Width, Height); TPoint pointSource = new TPoint(0, 0); TPoint topPos = new TPoint(Left, Top); Win32Helper.UpdateLayeredWindow(Handle, screenDc, ref topPos, ref size, memDc, ref pointSource, 0, ref blend, Win32Helper.ULW_ALPHA); } finally { Win32Helper.ReleaseDC(IntPtr.Zero, screenDc); if (hBitmap != IntPtr.Zero) { Win32Helper.DeleteObject(objBitmap); Win32Helper.DeleteObject(hBitmap); } Win32Helper.DeleteDC(memDc); } }
"हमारे System.Drawing.Bitmap
BMP की सामग्री को विंडो पर ले जाएं।
ताकि हम विंडो को हिला सकें और उसका आकार बदल सकें, यह इतना डरावना नहीं है:
private void Form1_MouseDown(object sender, MouseEventArgs e) { if (.. ...) { Win32Helper.ReleaseCapture(); Win32Helper.PostMessage(Handle, Win32Helper.WM_SYSCOMMAND, Win32Helper.DOSIZE8, 0); } else if (eY < 28) { Win32Helper.ReleaseCapture(); Win32Helper.PostMessage(Handle, Win32Helper.WM_SYSCOMMAND, Win32Helper.DOMOVE, 0); } }
नियंत्रण के बारे में क्या? सामान्य नियंत्रण के बारे में भूल जाओ, विंडोज उन्हें किसी भी तरह से हमारे अंडर-विंडो पर प्रदर्शित नहीं करेगा। इसलिए, हम इंटरफ़ेस से अपना नियंत्रण बनाते हैं,
interface ISkinnableControl { void RedrawControl(Graphics GFX); }
जिसमें प्रत्येक नियंत्रण मुख्य विंडो से GFX पर प्रसन्न होने के साथ-साथ खुद को "ड्रॉ" करेगा - मैंने ग्राफिक्सपैथ से बटन खींचे, और मैं पीएनजी से कुछ ले सकता हूं।
लेकिन मेरे स्क्रीनशॉट में सामान्य बटन कैसे बना? हाँ, जैसे ही उसने एक कील निकाली, उसने आकर्षित किया:
for (int cnt = Controls.Count - 1; cnt >= 0; cnt--) if (Controls[cnt] is ISkinnableControl && Controls[cnt].Visible) ((ISkinnableControl)Controls[cnt]).RedrawControl(GFX); else Controls[cnt].DrawToBitmap(BMP, new Rectangle());
बेशक, दुर्भाग्य से, मानक Control.DrawToBitmap () विधि हमें केवल नियंत्रण का "स्क्रीनशॉट" बनाती है, लेकिन अब नियंत्रण दिखाई देता है, हालांकि इसे थोड़ा अतिरिक्त चाहिए। अपनी तरह के गतिशील अपडेट के लिए बैकएंड कोड। हालाँकि, यह ISkinnableControl के वारिसों पर भी लागू होता है।
क्या यह तेजी से काम करता है? धिक्कार है तेजी से। सोर्स्की और टेस्ट एप्लिकेशन के बाइनरी, हमेशा की तरह कोडप्लेक्स पर, फिर से एमआईटी लाइसेंस के तहत हैं, अर्थात। जो भी हो, किसी भी चीज के लिए। मैंने पिछली परियोजना के साथ संयोजन नहीं किया, थोड़ा अलग विषय।
यह विंडो RDP पर क्यों नहीं दिखाई देती है? क्योंकि इसे ड्राइंग करते समय, विंडोज कुछ मुश्किल स्क्रीन ओवरले का उपयोग करता है, इसलिए यह आरडीपी के लिए तेज और उपलब्ध नहीं है।
आरडीपी के अनुसार, कोई भी चमक और काली आयतें नहीं हैं, बस यह खिड़की बिल्कुल भी मौजूद नहीं है, इसके नीचे और ऊपर की सभी सामान्य खिड़कियां दिखाई देती हैं और पूरी तरह से काम करती हैं। मुझे गलती से यह कुछ साल बाद मिला, समाप्त आवेदन के जारी होने के बाद, मैं तीसरी मंजिल से 1 और पीछे तक थक गया था, मैंने सोचा कि उपयोगकर्ता उपहास कर रहे थे, मुझे 3 रन चाहिए थे, मैंने ओवरले के बारे में सोचा। शायद अब, Win7 के दिनों में, कुछ बदल गया है, और अब यह खिड़की दिखाई देती है।
यदि पिछले लेख के बारे में Microsoft इंजीलवादी केवल एक उंगली से धमकी दे सकते हैं: "
आपको ऐसा नहीं करना चाहिए ", अब वे कहेंगे:
"
हाँ, आप आम तौर पर जिद्दी हैं। इसलिए एपीआई का उपयोग करें जो मूल रूप से माउस कर्सर के नीचे छाया बनाने के लिए बनाया गया था? "
हाँ, हाँ। मुझे यह एपीआई तब मिला जब माउस और मेनू के लिए छाया विंडोज में दिखाई दी। हेहे। उन्होंने खोदना शुरू किया, जैसा कि वे खींचे जाते हैं, फिर यह तकनीक और आकार की बात थी। खैर, अब मैं निश्चित रूप से Microsoft द्वारा कभी भी काम पर नहीं रखा जा सकता।
https://alphawindow.codeplex.com/सभी को शुक्रवार की शुभकामनाएं दें!
PS चित्र Imageban.ru पर, Habré में Q & A में से एक में इसका विज्ञापन किया गया था, मुझे उम्मीद है कि सब कुछ ठीक होगा।
UPD : मेमोरी प्रॉब्लम
सॉल्व है, मेरी कैंट थी। स्रोत और बायनेरी 0.6 तक अपडेट हुए।