FindWindow
GetWindow
GetWindowText
SetWindowText
آیس ویندوز
MoveWindow
IsWindowVisible
فعال کردن پنجره
IsWindowEnabled
WindowFromPoint
پنجره ی نمایش
پنجره بسته
SetWindowPos
GetClassLong
SetClassLong
GetWindowLong
SetWindowLong
GetDesktopWindow
GetParent
تابع FindWindow
تابع FindWindow(className,WindowName: PChar) : HWND;
تابع یک توصیفگر پنجره را برمی گرداند که درخواست را برآورده می کند (0 اگر چنین پنجره ای یافت نشد).
ممکن است یکی از پارامترها برابر با صفر باشد، سپس جستجو با استفاده از پارامتر دیگری انجام می شود.
مثال:
تابع GetWindow
تابع GetWindow (Wnd: HWND؛ Param): HWND
تابع یک توصیفگر پنجره را برمی گرداند که درخواست را برآورده می کند.
مثال:
تابع GetWindowText
تابع GetWindowText(hWnd: HWND; lpString: PChar; nMaxCount: Integer): Integer;
تابع متن پنجره را برمی گرداند. برای یک فرم، این عنوان، برای یک دکمه - برچسب روی دکمه است.
حداکثر طول متن؛ اگر متن طولانیتر باشد، قطع میشود.
مثال:
تابع IsWindow
تابع IsWindow(hWnd: HWND): BOOL;اگر پنجره ای با دسته داده شده وجود داشته باشد True، در غیر این صورت False را برمی گرداند.
هوند توصیفگر پنجره مورد نظرتابع MoveWindow
MoveWindow(hWnd: HWND; X, Y, nWidth, nHeight: Integer; bRepaint: BOOL): BOOL;پنجره را به موقعیت جدیدی منتقل می کند.
hWnd یک دستگیره به سمت پنجره در حال حرکت است. X، Y، nعرض، nارتفاع بر این اساس: مختصات جدید X,Y; عرض، ارتفاع جدید b رنگ آمیزی مجدد یک مقدار بولی که نشان می دهد آیا پنجره دوباره ترسیم می شود یا خیر.تابع IsWindowVisible
تابع IsWindowVisible(hWnd: HWND): BOOL;
اگر پنجره داده شده قابل مشاهده باشد، True را برمی گرداند.
فعال کردن عملکرد پنجره
تابع EnableWindow(hWnd: HWND; beEnable: BOOL): BOOL;
در دسترس بودن پنجره را تنظیم می کند (اگر به رویدادهای ماوس، صفحه کلید و غیره پاسخ ندهد، پنجره در دسترس نیست). یک آنالوگ در دلفی از ویژگی Enabled of components. EnableWindow اگر همه چیز موفقیت آمیز بود True و در غیر این صورت False را برمی گرداند.
مثال:
تابع IsWindowEnabled
تابع IsWindowEnabled(hWnd: HWND): BOOL;
برمی گرداند برای پنجره داده شده: اگر پنجره موجود باشد درست است و در غیر این صورت False.
تابع WindowFromPoint
WindowFromPoint(نقطه: TPoint): HWND;
یک دستگیره را به پنجره ای که در یک نقطه معین از صفحه قرار دارد برمی گرداند.
تابع
نوع TPoint = رکورد x: Longint; y: Longint; پایان; |
تابع ShowWindow
تابع ShowWindow(hWnd: HWND; nCmdShow: Integer): BOOL;پنجره را نشان می دهد یا پنهان می کند.
hWnd توصیفگر پنجره مورد نظر nCmdShow ثابتی که تعیین می کند با پنجره چه کاری انجام می شود: SW_HIDE SW_SHOWNORMAL SW_NORMAL SW_SHOWMINIMIZED SW_SHOWMAXIMIZED SW_MAXIMIZE SW_SHOWNOACTIVATE SW_SHOW SW_MINIMIZE SW_SHOWMINNOACTIVE SW_SHOWNA SW_RESTORE SW_SHOWDEFAULT SW_MAX
مثال:
عملکرد بستن پنجره
تابع CloseWindow(hWnd: HWND): BOOL; stdcall;
پنجره را می بندد.
SetWindowPos
تابع SetWindowPos(hWnd: HWND؛ hWndInsertAfter: HWND؛ X, Y, cx, cy: Integer؛ uFlags: UINT): BOOL; stdcall;
پنجره را در موقعیت جدیدی قرار می دهد
بر این اساس، افق های جدید. ، راس موقعیت های پنجره ( X، Y) و همچنین عرض جدید
و ارتفاع ( cx، cy)
تابع GetClassLong
تابع GetClassLong(hWnd: HWND; nIndex: Integer): Integer;
این تابع یک عدد صحیح 32 بیتی گرفته شده از یک فیلد خاص در یک رکورد را برمی گرداند TWndClassExپنجره مشخص شده
توجه داشته باشید: در مواردی که تابع یک اشاره گر را برمی گرداند، نوع casting ضروری است (Integer ->
تابع SetClassLong
تابع SetClassLong(hWnd: HWND; nIndex: Integer; dwNewLong: Longint): Integer;تابع تابع جفت. فیلد مورد نیاز را به مقدار مناسب تنظیم می کند.
تابع مقدار قدیمی فیلد را برمی گرداند تا بعداً بتوان آن را اصلاح کرد یا اگر مشکلی پیش آمد صفر را برمی گرداند.
توجه داشته باشید اشاره گرتایپ کردن عدد صحیح.
تابع GetWindowLong
تابع GetWindowLong(hWnd: HWND; nIndex: Integer): Longint;اطلاعات مربوط به یک پنجره را به صورت یک عدد صحیح 32 بیتی برمی گرداند.
hWndدستگیره پنجره nIndex یک تعریف ثابت که چه چیزی برگردانده خواهد شد. باید یکی از موارد زیر باشد:GWL_WNDPROC آدرس رویه پنجره مرتبط با این پنجره را برمی گرداند. آدرس به دست آمده (پس از کست های نوع مناسب) می تواند در یک تابع استفاده شود CallWindowProc. این مقدار معمولاً در صورتی استفاده میشود که بخواهند یک رویه پنجره موجود را با خود جایگزین کنند و برای اینکه عملکرد پنجره را از دست ندهند، معمولاً از آن استفاده میکنند. CallWindowProc. GWL_HINSTANCE دسته برنامه مشخص شده هنگام ایجاد پنجره توسط تابع را برمی گرداند CreateWindowEx. GWL_HWNDPARENT دسته (HWND) پنجره والد را برمی گرداند GWL_STYLE سبک پنجره را برمی گرداند. مقادیر سبک خاص با استفاده از یک عملیات بیتی یافت می شود وو ثابت ها WS_XXX GWL_EXSTYLE سبک پنجره توسعه یافته را برمی گرداند. مقادیر سبک خاص با استفاده از یک عملیات بیتی یافت می شود وو ثابت ها WS_EX_XXX GWL_USERDATA عدد صحیح 32 بیتی مرتبط با پنجره را برمیگرداند (این آخرین پارامتر در فراخوانی CreateWindow یا CreateWindowEx است) GWL_ID هنگام فراخوانی CreateWindow یا CreateWindowEx، شناسه پنجره را برمیگرداند (این ربطی به دسته پنجره ندارد!) که توسط پارامتر hMenu برای پنجرههای فرزند مشخص شده است.
توجه داشته باشید: در مواردی که تابع یک اشاره گر را برمی گرداند، نوع ریخته گری ضروری است (Integer -> Pointer). شما می توانید این کار را به این صورت انجام دهید:
تابع SetWindowLong
تابع SetWindowLong(hWnd: HWND; nIndex: Integer; dwNewLong: Longint): Longint;
با تابع جفت شد. ویژگی های یک پنجره خاص را تغییر می دهد.
در صورت موفقیت آمیز بودن فراخوانی، این تابع مقدار قدیمی ویژگی را برمیگرداند یا در غیر این صورت، آن را تهی میکند.
توجه داشته باشید: هنگام تنظیم فیلدهای اشاره گر، یک نوع Cast مورد نیاز است اشاره گرتایپ کردن عدد صحیح.
تابع GetDesktopWindow
تابع GetDesktopWindow: HWND
تابع یک دسته را به پنجره دسکتاپ برمی گرداند. بدون پارامتر
GetParent
تابع GetParent(hWnd: HWND): HWND;
دسته پنجره والد را برای یک پنجره برمی گرداند hWnd.
C WinAPI مجموعه اصلی مایکروسافت از رابط های برنامه نویسی (API) موجود در سیستم عامل ها است.نسخه اولیه Win32 API نامیده می شود.
معرفی
C WinAPI یک رابط برنامه نویسی کاربردی است که برای ایجاد برنامه های کاربردی ویندوز استفاده می شود. برای شروع، یک کاربر مبتدی باید Windows SDK را دانلود کند، که قبلا به عنوان Platform SDK شناخته می شد.
حاوی فایلهای هدر، کتابخانهها، نمونهها، اسناد و ابزارهایی است که برای توسعه برنامهها استفاده میشوند. API برای زبان های برنامه نویسی C و C++. این مستقیم ترین راه برای ایجاد برنامه های کاربردی در سیستم عامل شرکت است.
C WinAPI را می توان به چندین بخش تقسیم کرد:
رابط کاربری؛
چند رسانه ای؛
پوسته ویندوز؛
خدمات شبکه
خدمات اساسی؛
ایمنی؛
خدمات اصلی دسترسی به منابع اولیه را فراهم می کند. اینها شامل توابع C WinAPI، سیستمهای فایل، دستگاهها، فرآیندها، رشتهها، رجیستری و مدیریت خطا هستند. ناحیه امنیتی رابط ها، اشیا و سایر عناصر برنامه نویسی را برای احراز هویت، مجوز، رمزنگاری و سایر وظایف مرتبط با امنیت فراهم می کند. زیرسیستم گرافیک عملکردی را برای خروجی محتوای گرافیکی به نمایشگرها، چاپگرها و سایر دستگاه های خروجی فراهم می کند. رابط کاربری قابلیت هایی را برای ایجاد ویندوز و کنترل ها فراهم می کند.
مؤلفه چند رسانه ای ابزارهایی را برای کار با دستگاه های ویدیویی، صوتی و ورودی فراهم می کند. توابع رابط شل به برنامهها اجازه میدهند به توابع ارائه شده توسط پوسته سیستم عامل دسترسی پیدا کنند. خدمات شبکه دسترسی به قابلیت های شبکه ویندوز را فراهم می کند.
اجزاء
هنگام ایجاد WinAPI C، باید قابلیت های اساسی ارائه شده توسط Windows API را در نظر بگیرید که می تواند در هفت دسته سازماندهی شود. بیایید به هر یک از آنها با جزئیات بیشتری نگاه کنیم.
خدمات ضروری دسترسی به منابع اولیه سیستم موجود در ویندوز را فراهم می کند. مثال: سیستم فایل، تجهیزات جانبی، فرآیندها، دسترسی به رجیستری و سیستم مدیریت استثنا. این توابع در فایلهای kernel.exe، krnl286.exe یا krnl386.exe برای سیستمهای 16 بیتی و kernel32.dll و advapi32.dll برای سیستمهای 32 بیتی ذخیره میشوند.
رابط کاربری گرافیکی دسترسی به منابع را برای نمایش بر روی مانیتورها، چاپگرها و سایر تجهیزات جانبی فراهم می کند. در gdi.exe در سیستم های 16 بیتی و gdi32.dll در سیستم های 32 بیتی ذخیره می شود.
رابط کاربری مسئول مشاهده و کنترل عناصر اساسی مانند دکمه ها و نوارهای اسکرول، به دست آوردن اطلاعات صفحه کلید و ماوس و عملکردهای مرتبط است. این توابع در user.exe در سیستم های 16 بیتی و user32.dll comctl32.dll در سیستم های 32 بیتی ذخیره می شوند. با شروع XP، کنترل ها در comctl32.dll گروه بندی شدند.
گفتگوهای عمومی - نمایش اطلاعات برای باز کردن و ذخیره فایل ها، انتخاب رنگ ها و فونت ها. در فایل comdlg.dll در سیستم های 16 بیتی و comdlg32.dll در سیستم های 32 بیتی یافت می شود.
Windows Shell جزء WinAPI است که به برنامهها اجازه میدهد به عملکردهای ارائه شده توسط پوسته سیستم عامل دسترسی داشته باشند.
خدمات شبکه دسترسی به قابلیت های شبکه ای مختلف سیستم عامل را فراهم می کند. اجزای فرعی آن عبارتند از NetBIOS، Winsock، RPC. در نسخه های قدیمی - NetDDE.
نسخه ها
Win16، Win32 و Win32s مجموعه استانداردی از اجزا هستند که به نرم افزارهای کاربردی اجازه می دهند از عملکردهای سیستم عامل های مختلف خانواده ویندوز استفاده کنند.
Win32، جانشین Win16، در سال 1993 در محصولات خانواده ویندوز 32 بیتی مانند Windows NT، 2000، 95 معرفی شد. این رابط برنامه نویسی توسط سه کتابخانه نرم افزاری Kernel32.dll، User32.dll و GDI32.dll2 پیاده سازی شده است. همان ویژگی های Win32 در همه محصولات ویندوز موجود است و بسته به محصول، استفاده از برخی ویژگی ها ممکن است منجر به خطای سرویس شود.
قابلیت های Win32 شامل ارتباط بین برنامه ها، مدیریت فرآیندها، شبکه های کامپیوتری، فایل ها، چاپگرها، سرورها و پورت های ارتباطی است.
مشخصات
C WinAPI یک ویژگی رابط برنامه نویسی انتزاعی برای سیستم عامل ویندوز است. شامل اعلان توابع، اتحادیه ها، ساختارها، انواع داده ها، ماکروها، ثابت ها و سایر عناصر برنامه نویسی است. WinAPI توسط یک استاد توضیح داده شده و در هدرهای ویندوز C یافت می شود. اجرای رسمی توابع WinAPI در کتابخانه های پیوند پویا (DLL) یافت می شود: به عنوان مثال، kernel32.dll، user32.dll، gdi32.dll یا shell32.dll در دایرکتوری سیستم پیاده سازی های شخص ثالثی از Windows API وجود دارد: مهمترین آنها پروژه Wine و پروژه ReactOS.
Windows API یک شی پویا است. تعداد توابع با هر نسخه سیستم عامل جدید و بسته های سرویس جدید به طور مداوم در حال افزایش است. همچنین تفاوت های مهمی بین نسخه سرور و دسکتاپ سیستم عامل وجود دارد. برخی از عملکردها به طور رسمی مستند نشده اند.
پلس سی
Pelles C یک برنامه رایگان و بهترین کامپایلر C و محیط توسعه یکپارچه (IDE) برای زبان برنامه نویسی C است. از ویندوز 32 بیتی (x86) و ویندوز 64 بیتی (x64) پشتیبانی می کند. هر دو استاندارد C99 و C11 را اجرا می کند. Pelles C دارای یک ویرایشگر منابع داخلی، بیت مپ، ویرایشگر نماد و مکان نما و ویرایشگر هگز رومیزی است. این توسط توسعه دهنده سوئدی Pelle Orinius توسعه یافته است. کامپایلر به نام نویسنده آن نامگذاری شده است. همراه با SDK است، بنابراین برنامه نویس می تواند بلافاصله بدون نصب بیشتر شروع به ایجاد برنامه های کاربردی کند.
خطای معماری هدف
برای ایجاد برنامه های Windows API، باید افزونه های مایکروسافت را فعال کنید. آنها به طور پیش فرض غیرفعال هستند و باعث می شوند کامپایلر پیغام خطای زیر را صادر کند، که نمونه ای از یک WinAPI شکسته C است: خطای مرگبار #1014: #error: "معماری هدف وجود ندارد" برای فعال کردن برنامههای افزودنی مایکروسافت، به تنظیمات پروژه بروید و تب کامپایلر را انتخاب کنید. در این برگه، کادر "Enable Microsoft extensions" را فعال کنید.
MSDN
پورتال مرکزی برای توسعه ویندوز است. این مجموعه عظیمی از مواد مربوط به توسعه برنامه با استفاده از ابزارهای مایکروسافت است. این جامع ترین پایگاه داده به همراه مستندات توسعه برنامه های دسکتاپ و لیستی از API های ویندوز است.
استفاده از DLL در WinAPI C
کتابخانه Common Controls دسترسی به ویژگی های پیشرفته سیستم عامل مانند نوار وضعیت، نوار پیشرفت، نوار ابزار و برگه ها را فراهم می کند. این دستورات در commctrl.dll در سیستم های 16 بیتی و comctl32.dll یافت می شوند و با رابط کاربری گروه بندی می شوند.
DLL یک فرمت فایل کتابخانه پیوند پویا است که برای ذخیره چندین کد و رویه برای برنامه های ویندوز استفاده می شود. فایل های DLL به گونه ای ساخته شده اند که چندین برنامه می توانند همزمان از اطلاعات خود استفاده کنند و به صرفه جویی در حافظه کمک کنند. به کاربر اجازه می دهد تا کدگذاری چندین برنامه را به طور همزمان بدون تغییر آنها ویرایش کند. DLL ها را می توان با استفاده از MSIL Disassembler یا DLL برای Lib 3.00 به استاتیک تبدیل کرد.
WinAPI، به عنوان یک رابط برنامه نویسی کاربردی برای ویندوز، بسیاری از ویژگی های قدرتمند را ارائه می دهد که به شما امکان می دهد برنامه های خود را ایجاد کنید، از پردازش ساده فایل گرفته تا ساخت یک رابط گرافیکی برای برنامه نویسی درایورهای دستگاه های سطح پایین.
قبل از شروع برنامه نویسی در WinAPI، باید محیط کد خود را در ویندوز تنظیم کنید. از آنجایی که توزیع لینوکس نیست، کامپایلر داخلی برای ایجاد برنامهها ندارد. برای کامپایل کردن کد گزینه های زیر را در نظر بگیرید:
یک کیت توسعه برای ویندوز در دسترس است که اسناد و ابزارهایی را برای توسعه دهندگان برای ایجاد نرم افزار با استفاده از API و فناوری های مرتبط فراهم می کند.
مخفف API، Application Programming Interface (API) به سادگی مجموعه ای آماده از توابع است که توسعه دهندگان برنامه می توانند از آن استفاده کنند. به طور کلی، این مفهوم معادل چیزی است که قبلاً بیشتر به آن کتابخانه زیر روال میگفتند. با این حال، اغلب API به دسته خاصی از چنین کتابخانه هایی اشاره دارد.
در طول توسعه تقریباً هر برنامه نسبتاً پیچیده (MyApplication) برای کاربر نهایی، مجموعه ای از توابع داخلی خاص تشکیل می شود که برای اجرای این برنامه خاص استفاده می شود که MyApplication API نامیده می شود. اغلب معلوم می شود که این توابع می توانند به طور موثر برای ایجاد برنامه های کاربردی دیگر، از جمله توسط برنامه نویسان دیگر، استفاده شوند. در این صورت، نویسندگان بر اساس استراتژی تبلیغ محصول خود، باید در مورد این سوال تصمیم بگیرند که آیا آنها دسترسی به این مجموعه را برای کاربران خارجی باز می کنند یا خیر؟ اگر پاسخ مثبت باشد، در توضیحات بسته نرم افزاری، به عنوان مزیت آن، این عبارت ظاهر می شود که "بسته شامل مجموعه ای باز از توابع API است."
بنابراین، اغلب یک API به مجموعه ای از توابع اشاره دارد که بخشی از یک برنامه کاربردی هستند، اما برای استفاده در برنامه های دیگر نیز در دسترس هستند. به عنوان مثال، اکسل، علاوه بر رابط کاربری نهایی خود، دارای مجموعه ای از توابع API اکسل است که می توان از آنها به ویژه هنگام ایجاد برنامه های کاربردی با استفاده از VB استفاده کرد.
بر این اساس، Windows API مجموعه ای از توابع است که بخشی از خود سیستم عامل است و در عین حال برای هر برنامه دیگری قابل دسترسی است. و در این رابطه، تشابه با مجموعه وقفه سیستم BIOS/DOS که در واقع یک API DOS است کاملاً موجه است.
تفاوت این است که ترکیب توابع Windows API از یک طرف در مقایسه با DOS بسیار گسترده تر است، از طرف دیگر بسیاری از ابزارهای مدیریت مستقیم منابع رایانه ای را که در گذشته در دسترس برنامه نویسان بود، در بر نمی گیرد. سیستم عامل علاوه بر این، فراخوانیهای API ویندوز با استفاده از فراخوانیهای رویهای معمولی انجام میشوند و فراخوانیهای توابع DOS از طریق یک دستورالعمل پردازشگر ویژه به نام Interrupt انجام میشوند.
Win16 API و Win32 API
همانطور که می دانید، تغییر از ویندوز 3.x به ویندوز 95 نشان دهنده گذار از معماری سیستم عامل 16 بیتی به 32 بیتی است. در همان زمان، API 16 بیتی ویندوز (Win16 API) با نسخه جدید 32 بیتی (Win32 API) جایگزین شد. در این مورد، فقط باید در نظر داشته باشید که به جز چند استثنا، مجموعه Win32 API برای خانوادههای Windows 9x و Windows NT یکسان است.
وقتی با Win API آشنا میشوید، متوجه میشوید که بسیاری از توابع داخلی چیزی بیش از فراخوانی رویههای سیستم مربوطه نیستند، بلکه فقط در قالب نحو یک زبان خاص پیادهسازی میشوند. با در نظر گرفتن این موضوع، نیاز به استفاده از API با گزینه های زیر تعیین می شود:
توابع API که به طور کامل به عنوان توابع داخلی پیاده سازی می شوند. با این حال، گاهی اوقات در این مورد، تغییر به استفاده از API مفید است، زیرا گاهی اوقات می تواند عملکرد را به طور قابل توجهی بهبود بخشد (به ویژه به دلیل عدم تغییر غیر ضروری پارامترهای تصویب شده).
توابع داخلی تنها یک مورد خاص از تابع API مربوطه را پیاده سازی می کنند. این یک گزینه نسبتا رایج است.
تعداد زیادی از توابع API در نسخه فعلی کامپایلرها اصلاً آنالوگ ندارند. به عنوان مثال، شما نمی توانید یک دایرکتوری را با استفاده از VB حذف کنید - برای این کار باید از تابع DeleteDirectory استفاده کنید.
همچنین باید تاکید کرد که برخی از توابع API (سهم آنها در Win API بسیار کم است) به دلیل تعدادی محدودیت زبان، به عنوان مثال، ناتوانی در کار با آدرس های حافظه، نمی توانند از برنامه ها فراخوانی شوند. اما در برخی موارد، تکنیک های برنامه نویسی غیر پیش پا افتاده می تواند کمک کند (به ویژه در مورد همان آدرس ها).
Win APIوکتابخانه پیوند پویا (DLL)
مجموعه Win API در قالب DLL های پویا پیاده سازی شده است.
در این مورد، منظور ما از DLL نسخه سنتی کتابخانههای پویا باینری است که برنامهها را با دسترسی مستقیم به رویههای لازم - زیر روالها یا توابع (مثل آنچه هنگام فراخوانی رویهها در یک پروژه اتفاق میافتد) فراهم میکند. چنین کتابخانه هایی را می توان با استفاده از ابزارهای مختلف ایجاد کرد - VC++، Delphi، Fortran، Assembler.
فایل های کتابخانه پویا معمولا دارای پسوند .DLL هستند، اما این ضروری نیست. برای Win16، پسوند EXE اغلب استفاده میشد؛ درایورهای دستگاه خارجی با استفاده از .DRV تعیین میشوند.
تعیین تعداد دقیق توابع API ویندوز و فایل های حاوی آنها دشوار است (اما همه آنها در فهرست راهنمای سیستم قرار دارند). در این راستا، بهتر است ترکیب کتابخانه هایی که هسته سیستم عامل را تشکیل می دهند و کتابخانه های اصلی با عملکردهای اضافی کلیدی برجسته شود.
کتابخانه های Win32 API هسته سیستم عامل ویندوز 95/98:
KERNEL32.DLL: توابع سطح پایین برای مدیریت حافظه، وظایف و سایر منابع سیستم.
USER32.DLL: این عمدتاً جایی است که توابع کنترل رابط کاربری در آن قرار دارند.
GDI32.DLL: کتابخانه رابط دستگاه گرافیکی - توابع مختلف برای خروجی به دستگاه های خارجی.
COMDLG32.DLL: توابع مربوط به استفاده از جعبه های محاوره ای عمومی.
کتابخانه های اصلی با توابع افزونه:
COMCTL32.DLL: مجموعه ای از کنترل های اضافی ویندوز، از جمله Tree List و Rich Text.
MAPI32.DLL: توابعی برای کار با ایمیل.
NETAPI32.DLL: کنترل ها و توابع شبکه.
ODBC32.DLL: توابع این کتابخانه برای کار با پایگاه داده های مختلف از طریق پروتکل ODBC مورد نیاز است.
WINMM.DLL: عملیات دسترسی به رسانه سیستم.
این مقاله برای کسانی است که مانند من با برنامه نویسی C++ آشنا هستند و به طور اتفاقی یا میل تصمیم به یادگیری WinAPI دارند.من می خواهم بلافاصله به شما هشدار دهم:
من ادعا نمی کنم که یک گورو C++ یا WinAPI هستم.
من تازه یاد میگیرم و میخواهم در اینجا چند مثال و نکاتی را ارائه کنم که یادگیری عملکردها و مکانیسمهای WinAPI را برای من آسانتر میکند.
در این مقاله، فرض میکنم که شما قبلاً به اندازه کافی با C++ آشنا شدهاید تا بتوانید کلاسها را ایجاد کنید و عملگرهای مختلف را برای آنها بارگذاری کنید، و قبلاً برخی از مکانیسمهای خود را در کلاس "پنهان" کردهاید.
ایجاد و استفاده از کنسول
برای اشکال زدایی یک برنامه Win32 یا فقط برای اینکه ببینم همه چیز در داخل چگونه اتفاق می افتد، من همیشه از کنسول استفاده می کنم.از آنجایی که شما در حال ایجاد یک برنامه رابط کاربری گرافیکی هستید و نه یک برنامه کنسول، کنسول متصل نیست. برای فراخوانی آن، این کد در اعماق اینترنت پیدا شد
اگر (AllocConsole())
{
std::ios::sync_with_stdio();
}
برای راحتی، من به شما توصیه می کنم آن را در یک تابع بپیچید. مثلا:
void CreateConsole()
{
if (AllocConsole())
{
int hCrt = _open_osfhandle((طولانی)GetStdHandle(STD_OUTPUT_HANDLE)، 4);
*stdout = *(::_fdopen(hCrt، "w"));
::setvbuf(stdout، NULL، _IONBF، 0);
*stderr = *(::_fdopen(hCrt، "w"));
::setvbuf(stderr، NULL، _IONBF، 0);
std::ios::sync_with_stdio();
}
کنسول فراخوانی شده فقط در حالت خروجی کار می کند و مانند برنامه های کنسول کار می کند. اطلاعات خروجی طبق معمول - cout/wcout.
برای اینکه این کد کار کند، باید فایل های زیر را در پروژه قرار دهید:
#عبارتند از
#شامل #شامل
و فضای نام std را در فضای نام جهانی قرار دهید:
با استفاده از namespace std.
البته، اگر نمیخواهید این کار را انجام دهید، فقط std:: را به همه موجوداتی که در آن هستند اضافه کنید.
ارث بری اشیا برای خروجی و حساب. عملیات
هنگام ایجاد و مطالعه خود "ویندوزها"، همیشه نیاز داشتم مقداری را به کنسول خروجی بدهم.مثلا:
اندازه ناحیه مشتری پنجره را با استفاده از تابع GetClientRect دریافت می کنید، جایی که آدرس یک شی ساختار RECT به عنوان پارامتر برای پر کردن این شی با داده ارسال می شود. اگر نیاز به دانستن اندازه ناحیه مشتری دریافتی دارید، می توانید آن را به سادگی در کنسول از قبل متصل شده نمایش دهید
کوت< اما انجام هر بار این کار (به خصوص اگر اغلب مجبور به انجام چنین کاری هستید) بسیار ناخوشایند است. کلاس newrect: public RECT اکنون فقط شی را با استفاده از cout/wcout خروجی بگیرید: کوت< و همه چیز به شکل مناسبی که نیاز دارید برای شما نمایش داده می شود. هنگامی که به طور کامل فکر کنید و چنین کلاسی را بنویسید، زندگی خود را آسان تر خواهید کرد و زمان بیشتری را صرف یادگیری و تقویت مهارت های خود خواهید کرد تا اینکه هر بار همان مطلب را بنویسید. علاوه بر این، فکر می کنم ایجاد چنین کلاسی خودتان و تکمیل آن در صورت لزوم بسیار مفید است. سلب مسئولیت به نظر می رسد که WinAPI در حال تبدیل شدن به چیزی از گذشته است. مدت زیادی است که تعداد زیادی فریمورک متقابل پلتفرم وجود دارد، ویندوز فقط روی دسکتاپ نیست و خود مایکروسافت از برنامه هایی که از این هیولا در فروشگاه خود استفاده می کنند استقبال نمی کند. علاوه بر این، هزاران مقاله در مورد نحوه ایجاد ویندوز با استفاده از WinAPI، نه تنها در اینجا، بلکه در سراسر اینترنت، در سطحی از پیش دبستانی و بالاتر وجود دارد. کل این فرآیند دیگر حتی به اتم ها تجزیه نمی شود، بلکه به ذرات زیراتمی تبدیل می شود. چه چیزی می تواند ساده تر و واضح تر باشد؟ و من اینجا هستم... اما همه چیز به این سادگی که به نظر می رسد نیست. من در مورد چه چیزی صحبت می کنم؟ و این هم یک قطعه کد: Case WM_KEYDOWN: MessageBox(hwndDlg,"Die!","من مردم!",MB_YESNO|MB_ICONINFORMATION)؛ break; پاسخ این است: شما نمی توانید این کار را انجام دهید! و، بازگشت به سوال اصلی در مورد WinAPI: بسیاری از پروژه های محبوب، و نه چندان محبوب، در حال حاضر از آن استفاده می کنند، زیرا بسیاری از کارها را نمیتوان بهتر از استفاده از یک API خالص انجام داد (در اینجا میتوانید بیپایان قیاسهایی مانند مقایسه زبانهای سطح بالا و زبان اسمبلی ارائه دهید، اما اکنون این موضوع نیست). و چه کسی می داند چرا؟ آنها فقط از آن استفاده می کنند و تمام. دور زدن چنین مشکلات جزئی آسان است. حداقل دو راه کاملا قانونی وجود دارد: در حالی که (GetMessage(&msg, nullptr, 0, 0)) ( TranslateMessage(&msg); DispatchMessage(&msg); ) شایان ذکر است که در قالب های VS برای برنامه های Win32 دقیقاً چنین چیزی نوشته شده است اشتباهچرخه و این خیلی ناراحت کننده است. از این گذشته، تعداد کمی از مردم به آنچه خود نویسندگان انجام داده اند می پردازند، زیرا این پیشینی درست است. و کد نادرست به همراه اشکالاتی که یافتن آنها بسیار دشوار است، چند برابر می شود. پس از این قطعه کد، به طور معمول، داستانی در مورد شتاب دهنده ها دنبال می شود و چند خط جدید اضافه می شود (با در نظر گرفتن نکته در MSDN، پیشنهاد می کنم بلافاصله چرخه صحیح را بنویسید): HACCEL hAccel = Load Accelerators(hInstance, MAKEINTRESOURCE(IDR_ACCELERATOR)); BOOL bret = 0; while (bRet = GetMessage(&msg, nullptr, 0, 0)) ( if (-1 == bRet) break; if (!TranslateAccelerator(msg.hwnd, hAccel, &msg)) ( TranslateMessage(&msg) DispatchMessage(&msg) ;)) ابتدا در مورد آنچه تغییر کرده است (سپس در مورد مشکلات این کد): در خط اول، جدولی از کلیدها از منابع بارگیری می شود؛ با فشار دادن، یک پیام WM_COMMAND با شناسه فرمان مربوطه ایجاد می شود. در واقع، TranslateAccelerator این کار را انجام می دهد: اگر WM_KEYDOWN و کد کلید موجود در این لیست را ببیند، سپس (دوباره نکته کلیدی) یک پیام WM_COMMAND (MAKEWPARAM(id, 1)) تولید می کند و آن را به مورد مربوطه ارسال می کند. دسته پنجره مشخص شده در آرگومان اول، رویه پردازش. از جمله آخر فکر کنم مشخص شد مشکل کد قبلی چی بوده. واضح است که TranslateAccelerator باید برای پنجره ایجاد شده ما فراخوانی شود: HWND hMainWnd = CreateWindow(...); HACCEL hAccel = Load Accelerators(hInstance, MAKEINTRESOURCE(IDR_ACCELERATOR)); BOOL bret = 0; while (bRet = GetMessage(&msg, nullptr, 0, 0)) ( if (-1 == bRet) break; if (!TranslateAccelerator(hMainWnd, hAccel, &msg)) ( TranslateMessage(&msg; DispatchMessage(&msg);) ) و باز هم نه :-) تا زمانی که دقیقاً یک پنجره داشته باشیم - این پنجره به درستی کار می کند. به محض ظاهر شدن یک پنجره جدید بدون حالت (دیالوگ)، تمام کلیدهایی که در آن فشار داده می شوند به WM_COMMAND ترجمه می شوند و به کجا ارسال می شوند؟ و دوباره به درستی: در پنجره اصلی ما. در این مرحله، پیشنهاد میکنم از عصا برای حل این وضعیت بنبست استفاده نکنید، بلکه پیشنهاد میکنم مواردی را که قبلاً کمتر رایج هستند (یا تقریباً هرگز پیدا نشدهاند) در آموزشها در نظر بگیرید. در واقع، کمی بیشتر از چیزی که از نامش پیداست، انجام می دهد. برای مثال: ثانیاً، زندگی ما را در مورد سایر نکات ذکر شده در لیست (و حتی کمی بیشتر) آسان تر می کند. به طور کلی در جایی در اعماق ویندوز برای اطمینان از کار استفاده می شود جعبه های محاوره ای مودال، و به برنامه نویسان داده می شود تا آن را برای گفتگوهای بدون حالت فراخوانی کنند. با این حال، ما می توانیم از آن در هر جایی استفاده کنیم: HWND hMainWnd = CreateWindow(...); HACCEL hAccel = Load Accelerators(hInstance, MAKEINTRESOURCE(IDR_ACCELERATOR)); BOOL bret = 0; while (bRet = GetMessage(&msg, nullptr, 0, 0)) ( if (-1 == bRet) break; if (!TranslateAccelerator(hMainWnd, hAccel, &msg)) ( if (!IsDialogMessage(hMainWnd, &msg) ( TranslateMessage(&msg); DispatchMessage(&msg); ) ) وقت آن است که در مورد آنچه در آموزش ها و پاسخ ها نیست صحبت کنیم. به عنوان یک قاعده (به عنوان یک قاعده! اگر کسی بیشتر می خواهد، پس می توانید کلاس خود را برای دیالوگ ها ثبت کنید و مانند این کار کنید. و اگر کسی به این موضوع علاقه دارد، می توانم این را به مقاله اضافه کنم) وقتی می خواهد WM_KEYDOWN می خواهد یک کلیک روی کلیدی را پردازش کنید که بدون توجه به کنترل انتخاب شده در پنجره عملکردی را انجام می دهد - i.e. برخی از عملکردهای کلی برای همه این گفتگوی خاص. و اگر چنین است، پس چرا از فرصت های غنی که خود WinAPI به ما ارائه می دهد استفاده نکنید: Translate Accelerator. همه جا استفاده می شود دقیقا یکیجدول شتاب دهنده و فقط برای پنجره اصلی. خوب، واقعاً: یک چرخه حلقه GetMessage وجود دارد، به این معنی که یک جدول وجود دارد. دیگر کجا باید بروند؟ در واقع، GetMessage-loops می تواند باشد تو در تو. بیایید دوباره به توضیحات PostQuitMessage نگاه کنیم: ما می توانیم برای هر کس غیر معین
ویندوز در برنامه ما حلقه مشابه خود را ایجاد می کند. در این مورد، DialogBoxParam برای ما مناسب نیست، زیرا چرخه خودش را میچرخاند و ما نمیتوانیم روی آن تأثیر بگذاریم. با این حال، اگر یک گفتگو از طریق CreateDialogBoxParam یا یک پنجره از طریق CreateWindow ایجاد کنیم، میتوانیم یک حلقه دیگر بچرخانیم. در همان زمان، در هر کسدر چنین پنجره و دیالوگی، باید PostQuitMessage را فراخوانی کنیم: HWND hMainWnd = CreateWindow(...); HACCEL hAccel = Load Accelerators(hInstance, MAKEINTRESOURCE(IDR_ACCELERATOR)); BOOL bret = 0; while (bRet = GetMessage(&msg, nullptr, 0, 0)) ( if (-1 == bRet) break; if (!TranslateAccelerator(hMainWnd, hAccel, &msg)) ( if (!IsDialogMessage(hMainWnd, &msg) ( TranslateMessage(&msg); DispatchMessage(&msg); ) ) // .... LRESULT CALLBACK WndProc(HWND hwnd، UINT umsg، WPARAM wparam، LPARAM lparam) (سوئیچ(umsg) (مورد WM_MYWNDATEHD hInstance، MAKEINTRESOURCE(IDD_MYDIALOG)، hwnd، MyDialogBoxProc)؛ HACCEL hAccel = LoadAccelerators(hInstance, MAKEINTRESOURCE(IDR_ACCELERATOR_FOR_MY_DIALOG))؛ BOOL fRwnStable=drownEnd0; EnableWindow(hwnd, F ALSE)؛ // غیر فعال کردن پنجره والد از آنجایی که پنجره محاورهای مودال است در حالی که (bRet = GetMessage(&msg, nullptr, 0, 0)) (اگر (-1 == bRet) شکسته شود؛ اگر (!TranslateAccelerator(hDlg, hAccel, &msg)) (اگر (!IsDialogMessage( hDlg , &msg)) ( TranslateMessage(&msg); DispatchMessage(&msg); ) ) ) EnableWindow(hwnd, fSavedEnabledState)؛ // فعال کردن پنجره والد. دیالوگ بسته شد شکست؛ ) ) ) INT_PTRgProCALLBACKHU,My WPARAM wparam، LPARAM lparam) ( switch(umsg) ( case WM_CLOSE: ( // EndDialog(hwnd, 0); --این کار را نکن! // EndDialog فقط برای دیالوگ های Modal معتبر است که با DialogBox(Param) DestroyWindow(hwnd) ایجاد شده است. زنگ تفريح؛ ) case WM_DESTROY: ( PostQuitMessage(0); break; ) // .... ) return 0; ) واقعیت این است که حلقه بیرونی در تماس با DispatchMessage، که رویه ما را فراخوانی میکند، متوقف شد. داخلیحلقه GetMessage با همان DispatchMessage. یک تماس تو در تو کلاسیک (در این مورد DispatchMessage). بنابراین، حلقه بیرونی WM_QUIT را دریافت نمی کند و در این مرحله خاتمه نمی یابد. همه چیز به آرامی کار خواهد کرد. اما این هم معایبی دارد: خوب، وقت آن است که همه این نظرات را در نظر بگیریم و در نهایت پردازش صحیح همه پیام ها را از تمام پنجره های برنامه خود بنویسیم. من می خواهم توجه داشته باشم که در زیر ما مورد را برای یک موضوع در نظر می گیریم. زیرا هر رشته دارای صف پیام های خاص خود است، سپس برای هر رشته باید ساختارهای خود را ایجاد کنید. این کار با تغییرات بسیار کم اهمیت در کد انجام می شود. اولا، منطقی است که فقط فعالپنجره پیام ها را دریافت می کند. آن ها برای یک پنجره غیرفعال، ما شتاب دهنده ها را پخش نمی کنیم و پیام ها را به IsDialogMessage ارسال نمی کنیم. ثانیاً، اگر جدول شتاب دهنده برای پنجره مشخص نشده باشد، چیزی برای پخش وجود ندارد؛ ما به سادگی پیام را به IsDialogMessage ارسال می کنیم. بیایید یک std::map ساده بسازیم که توصیفگر پنجره را به توصیفگر جدول شتاب دهنده نگاشت می کند. مثل این: Std:: map BOOL AddAccelerators(HWND hWnd, HACCEL hAccel) ( if (IsWindow(hWnd)) ( l_mAccelTable[hWnd ] = hAccel; return TRUE; ) return FALSE; ) BOOL AddAccelerators(HWND AddAccelerators(HWNDAccelerator(hWnd,hWnd) نویسندگان ( hInstance, accel)); ) BOOL AddAccelerators(HWND hWnd, int accel) ( return AddAccelerators(hWnd, MAKEINTRESOURCE(accel)); ) BOOL AddAccelerators(HWND hWnd) ( بازگشت AddAccelerators(hWnd, HAULLCCEL); Void DelAccel(HWND hWnd) ( std::map ما لیستی از ویندوزها با توصیفگرهای لازم داریم. بیایید حلقه اصلی پردازش پیام خود را کمی تغییر دهیم: // ... HWND hMainWnd = CreateWindow(...); Add Accelerators (hMainWnd، IDR_ACCELERATOR)؛ BOOL bret = 0; while (bRet = GetMessage(&msg, nullptr, 0, 0)) ( if (-1 == bRet) break; if (!HandleAccelArray(GetActiveWindow(), msg)) ( TranslateMessage(&msg); DispatchMessage(&msg); ) ) // ... کمی تئوری: دو تابع وجود دارد که یک دسته را به پنجره فعال باز می گرداند: GetForegroundWindow و GetActiveWindow. تفاوت بین اول و دوم کاملاً به وضوح در توضیح دوم توضیح داده شده است: بنابراین، HandleAccelArray، با هدایت توصیفگر ارسال شده به آن برای پنجره فعال، همین پنجره را در نقشه ما جستجو می کند، و اگر وجود دارد، این پیام را برای پخش به TranslateAccelerator می فرستد، و سپس (اگر اولین مورد آن را ندید سمت راست) به IsDialogMessage. اگر دومی پیام را پردازش نکرد، ما FALSE را برمیگردانیم تا از رویه استاندارد TranslateMessage/DispatchMessage عبور کنیم. به نظر می رسد که: BOOL HandleAccelWindow(std::map سوئیچ (HIWORD(wParam)) (مورد BN_CLICKED: // دستور از دکمهها/منوها (سوئیچ(LOWORD(wParam)) (مورد IDC_BUTTON1: DoButton1Stuff(); break؛ مورد IDC_BUTTON2: DoButton2Stuff(); break; // ... ) زنگ تفريح؛ ) ) سوئیچ(HIWORD(wParam)) ( مورد 1: // مورد شتاب دهنده BN_CLICKED: // فرمان از دکمه ها/منوها ( سوئیچ(LOWORD(wParam)) (مورد IDC_BUTTON1: DoButton1Stuff(); شکست؛ مورد IDC_BUTTON2: DoButton break2Stuff(); ؛ // ... ) زنگ تفريح؛ ) ) P.S.: تعداد کمی از مردم می دانند، اما شما می توانید جدول شتاب دهنده خود را ایجاد کنید و اکنون آن را در پرواز اعمال کنید. P.P.S.: چون DialogBox/DialogBoxParam حلقه خود را میچرخاند، سپس هنگام فراخوانی گفتگو از طریق آنها، شتابدهندهها کار نمیکنند و حلقه (یا حلقههای) ما "بیکار" خواهند بود. P.P.P.S.: پس از فراخوانی HandleAccelWindow، نقشه l_mAccelTable ممکن است تغییر کند، زیرا TranslateAccelerator یا IsDialogMessage با DispatchMessage تماس می گیرد و در آنجا ممکن است با AddAccelerators یا DelAccel در گرداننده های خود مواجه شویم! بنابراین بهتر است بعد از این عملکرد به آن دست نزنید. می توانید کد را احساس کنید. کد تولید شده از الگوی استاندارد MS VS 2017 به عنوان پایه در نظر گرفته شد. برچسب ها: اضافه کردن برچسب
اینجاست که ارث به کمک ما می آید.
کلاسی ایجاد کنید که آشکارا از ساختار RECT ارث می برد و عملگر خروجی را بارگذاری می کند<< так, как вам угодно.
مثلا:
{
عمومی:
دوست ostream& operator<<(ostream &strm,newrect &rect)
{
strm<<"Prtint RECT object:\n";
strm<
}
};
شما می توانید همین کار را با هر اپراتور مورد نیاز خود انجام دهید.
برای مثال، اگر نیاز به مقایسه یا تخصیص ساختارها دارید (به عنوان مثال، RECT یا POINT)، به ترتیب عملگر اضافه بار ==() و عملگر=().
اگر می خواهید کمتر از عملگر را پیاده سازی کنید< что бы быстро сравнивать размеры окна и т.д. перегрузите operator<().
فکر میکنم تقریباً با هر ساختاری میتوانید این کار را انجام دهید و مهمترین چیز این است که همه توابعی که با یک شی ساختار معمولی RECT کار میکنند به همان خوبی با وارث آن کار میکنند.
و همچنین توصیه می کنم این همه زیبایی را در یک فایل همراه جداگانه قرار دهید و در صورت لزوم از آن استفاده کنید.کلاس تو
در مورد دیگران نمی دانم، اما از آنجایی که من کاملاً سبز هستم، تصمیم گرفتم برای هر تابعی که مطالعه می کردم یا برای هر فصل / زیرفصل یک کتاب، یک پروژه جدید ایجاد کنم تا همه چیز در قفسه ها باشد و من می توانم هر لحظه برگردم و خاطره ام را از نکات ضروری تازه کنم.
از آنجایی که در WinAPI، حتی برای ایجاد ساده ترین پنجره، باید یک ساختار کلاس را پر کنید، آن را ثبت کنید و یک رویه پنجره بی اهمیت بنویسید، پس از پروژه سوم یا چهارم به یاد آوردم که هنوز در C++ می نویسم.
در نهایت همه چیز را در یک کلاس درس ساده پنهان کردم. دسته پنجره، نام آن، نام کلاس، آدرس رویه پنجره، کلاس پنجره (WNDCLASS) همه در بخش خصوصی کلاس پنهان هستند.
برای به دست آوردن آنها کافی است روش های ساده Get را شرح دهید، به عنوان مثال:
HWND GetHWND()
LPCTSTR GetClsName() و غیره
پر کردن و ثبت کلاس پنجره، ایجاد خود پنجره و نمایش آن در سازنده انجام می شود.
برای راحتی، میتوانید سازنده را اضافه بارگذاری کنید، و پر کردن و ثبت کلاس پنجره را در یک تابع کلاس خصوصی جداگانه پنهان کنید و آن را در هر یک از سازندهها فراخوانی کنید. راحتی بارگذاری بیش از حد این است که گاهی اوقات من نیاز به ایجاد یک پنجره بسیار ساده دارم و سازنده را با دو پارامتر فراخوانی می کنم - نام پنجره و راهنمای برنامه.
در مواقع دیگر من نیاز به ایجاد یک پنجره با اندازه خاص دارم، نه با رویه پنجره پیش فرض و با سبک خاص دیگر - سازنده را با پارامترهای همراه فراخوانی می کنم.
من این کلاس را در یک فایل include جداگانه تعریف کرده ام که در پوشه include IDE قرار دارد.
یک قالب برای این کلاس:
کلاس BaseWindow
{
WNDCLASSEX_wcex;
TCHAR_className;
TCHAR_windowName;
HWND_hwnd;
bool _WindowCreation();
عمومی:
BaseWindow(LPCTSTR نام پنجره، HINSTANCE hInstance، سبک DWORD، UINT x، UINT y، ارتفاع UINT، عرض UINT).
BaseWindow(LPCTSTR windowName,HINSTANCE hInstance)؛
const HWND GetHWND()const(بازگشت HWND;)
LPCTSTR GetWndName()const(return _windowName;)
}; P.S.
همه چیزهایی که شرح داده شد برای:
پلتفرم - ویندوز 7 32 بیتی
IDE - Visual Studio 2010
شاید این نکات برای برخی باعث خنده و کنایه شود، اما با این حال، همه ما زمانی در کاری مبتدی/کارآموز/جوان بودیم.
لطفا با این پست با درک رفتار کنید. البته انتقاد سازنده قابل استقبال است. چرا در مورد WinAPI در حال حاضر؟
در یک نقطه، در حالی که در حال مطالعه بر روی یکی از بازی ها در یک بازی بسیار خوب، فکر کردم: به نظر می رسد این امولسیون خوبی است، اما دیباگر چیز ساده ای مانند پیمایش از طریق دکمه های صفحه کلید که در دسترس است ندارد. در هر دیباگر معمولی
بنابراین، نویسندگان می خواستند پشتیبانی از صفحه کلید را اضافه کنند، اما واقعیت خشن اعماق معماری جعبه های محاوره ای در ویندوز، چنین ابتکاری را به شدت سرکوب کرد. آیا کسی که از شبیه ساز و دیباگر در آن استفاده کرده باشد این پیام را دیده است؟
مشکل چیست؟در مورد مشکل
جعبههای گفتگو کار با رابط کاربری گرافیکی را آسانتر میکنند و در عین حال فرصت انجام کاری را از ما سلب میکنند. به عنوان مثال، پیامهای WM_KEYDOWN/WM_KEYUP که به رویه پنجره میآیند، در اعماق DefDlgProc «خورده» میشوند و مواردی مانند پیمایش Tab، پردازش کلیدهای Esc، Enter و غیره را انجام میدهند. علاوه بر این، دیالوگ ها نیازی به ایجاد دستی ندارند: به هر حال، ترسیم دکمه ها، لیست ها در ویرایشگر منابع، ساده تر است، CreateDialog/DialogBox را در WinMain فراخوانی کنید و کارتان تمام شد.
نقطه ضعف واضح است: شما باید یک کلاس دیگر ثبت نام کنید، 1 روش CALLBACK دیگر داشته باشید، که ماهیت آن فقط پخش چند پیام خواهد بود. علاوه بر این، ما نمی دانیم جایی کهآنها را پخش کنید، و شما باید با عصا نرده بکشید.آموزش ها؟
از گفتن این حرف نمی ترسم همهآموزش ایجاد ویندوز از طریق WinAPI با چنین کد ساده ای شروع می شود و آن را به عنوان یک "حلقه پردازش پیام" نشان می دهد (من جزئیات آماده سازی کلاس پنجره و سایر اتصالات را حذف می کنم):
اینجا واقعا ساده است:
بیایید با این واقعیت شروع کنیم که استفاده از این کد خطرناک است و در اینجا دلیل آن است. لطفا به پاورقی توجه کنید: از آنجایی که مقدار بازگشتی می تواند غیر صفر، صفر یا -1 باشد، از کدی مانند زیر اجتناب کنید:
و در زیر نمونه ای از یک حلقه صحیح آورده شده است.
در حالی که (GetMessage(lpMsg، hWnd، 0، 0)) ...
این گزینه ای است که من اغلب دیده ام. و او ( تادام) دوباره اشتباه است!
اجازه دهید توضیح بدهم: GetMessage پیامها را برای همه اشیاء از نوع "پنجره" (که شامل کودکان: دکمهها، لیستها و غیره میشود) میگیرد و TranslateAccelerator WM_COMMAND تولید شده را به کجا ارسال میکند؟ صحیح: بازگشت به دکمه/لیست و غیره. اما ما WM_COMMAND را در رویه خود پردازش می کنیم، به این معنی که ما علاقه مند به دریافت آن در آن هستیم.
و اکنون همه چیز خوب و شگفت انگیز به نظر می رسد: ما همه چیز را با جزئیات تجزیه و تحلیل کرده ایم و همه چیز باید به خوبی کار کند.IsDialogMessage
با قضاوت بر اساس نام این تابع، ممکن است فکر کنید که به دلایلی تعیین می کند که آیا یک پیام داده شده به دیالوگ تعلق دارد یا خیر. اما اول از همه، چرا باید این را بدانیم؟ و دوم اینکه با این اطلاعات باید چیکار کنیم؟
چه چیزی به ما می دهد؟ اول، لازم نیست به پیمایش درون پنجره فکر کنیم. به هر حال هر کاری برای ما انجام خواهند داد. به هر حال، ناوبری Tab را می توان با افزودن سبک WS_EX_CONTROLPARENT به پنجره اصلی ما انجام داد، اما این کار ناشیانه است و چندان کاربردی نیست..اگرچه تابع IsDialogMessage برای جعبههای محاورهای بدون حالت در نظر گرفته شده است، اما میتوانید آن را با هر پنجرهای که حاوی کنترلها است استفاده کنید و پنجرهها را قادر میسازد تا همان صفحهکلیدی را که در یک کادر محاورهای استفاده میشود، ارائه دهند.
آن ها حالا اگر حلقه را به این صورت طراحی کنیم:
سپس پنجره ما ناوبری خواهد داشت، مانند گفتگوی بومی ویندوز. اما الان دو تا عیب داریم:
و در این مرحله، به طور کلی، تمام آموزش ها به پایان می رسد و سوالات شروع می شود: چگونه رویدادهای صفحه کلید را در یک گفتگوی استاندارد winapi مدیریت کنیم؟
این اولین لینک در گوگل است، اما باور کنید: هزاران مورد وجود دارد. در مورد راه حل های پیشنهادی (بهترین آنها ایجاد کلاس گفتگوی خود است، که در بالا در مورد آن نوشتم، قبل از کلاس بندی و RegisterHotKey. در جایی حتی "بهترین" راه را دیدم: از Windows Hooks استفاده کنید). تابع PostQuitMessage یک پیام WM_QUIT را به صف پیام رشته ارسال می کند و فوراً برمی گردد؛ این تابع به سادگی به سیستم نشان می دهد که موضوع در زمانی در آینده درخواست خروج از آن را دارد.
و GetMessage: اگر تابع پیام WM_QUIT را بازیابی کند، مقدار بازگشتی صفر است.
بنابراین، اگر در رویه پنجره، PostQuitMessage را فراخوانی کنیم، حلقه GetMessage خارج می شود. چه مفهومی داره؟
لطفا توجه داشته باشید: اکنون برای هر پنجره جدید در برنامه ما می توانیم به پردازش اضافه کنیم خودجدول شتاب دهنده WM_QUIT GetMessage را از حلقه برای گفتگو ربوده و حلقه بیرونی حتی آن را نمی بیند. چرا این اتفاق می افتد؟
هر حلقه از این قبیل پیام ها را پردازش می کند فقط برای پنجره "شما".. ما اینجا از دیگران خبر نداریم. این بدان معنی است که اگر چرخه دیگری در جایی ظاهر شود، تمام پنجره های دیگر پردازش لازم از پیام های خود را توسط جفت TranslateAccelerator/IsDialogMessage دریافت نمی کنند.ما آن را به زیبایی انجام می دهیم
زیرا فرمول صحیح مسئله نیمی از راه حل است، سپس ابتدا باید این مشکل را به درستی مطرح کنید.
و همانطور که ویندوز ایجاد می شود، پنجره های جدیدی را با یک توصیفگر به جدول مورد علاقه خود (یا صفر، اگر چنین پردازشی لازم نیست) به آن اضافه می کنیم.
خب پس از بستن پنجره، آن را حذف کنید. مثل این:
اکنون، همانطور که یک گفتگو/پنجره جدید ایجاد می کنیم، با AddAccelerators (hNewDialog، IDR_MY_ACCEL_TABLE) تماس بگیرید. نحوه بستن: DelAccel (hNewDialog).
خیلی بهتر! در HandleAccelArray چیست و چرا GetActiveWindow() در آنجا وجود دارد؟مقدار بازگشتی، دستگیره پنجره فعال متصل به صف پیام رشته تماس است. در غیر این صورت، مقدار بازگشتی NULL است.
اگر اولی یک دسته را به هر پنجره ای در سیستم برگرداند، دومی فقط برمی گردد که از صف پیام رشته ما استفاده می کند. زیرا ما فقط به پنجره های رشته خود علاقه مند هستیم (و بنابراین آنهایی که در صف پیام ما قرار می گیرند)، بنابراین دومی را می گیریم.
اکنون هر پنجره فرزند حق دارد جدول شتاب دهنده مورد علاقه خود را اضافه کند و با آرامش WM_COMMAND را با کد لازم بگیرد و پردازش کند.و یک خط دیگر در کد کنترل کننده WM_COMMAND چطور؟
توضیحات در TranslateAccelerator به شرح زیر است: برای متمایز کردن پیامی که این تابع ارسال می کند از پیام های ارسال شده توسط منوها یا کنترل ها، کلمه مرتبه بالای پارامتر wParam پیام WM_COMMAND یا WM_SYSCOMMAND حاوی مقدار 1 است.
معمولاً کد پردازش WM_COMMAND به شکل زیر است:
حالا می توانید اینگونه بنویسید:
و اکنون، بازگشت به همان fceux، اضافه کردن فقط یک خطدر کد پردازش دستورات از دکمه ها، آنچه را که می خواهیم دریافت می کنیم: دیباگر را از صفحه کلید کنترل کنید. کافی است یک بسته بندی کوچک در اطراف حلقه پیام اصلی و یک جدول شتاب دهنده جدید با موارد منطبق VK_KEY => IDC_DEBUGGER_BUTTON اضافه کنید.