PDA

View Full Version : آموزش مقدماتی Win32



توسعه نویس
شنبه 02 شهریور 1387, 13:30 عصر
سلام به همه دوستان.
از اونجایی که یکی از مطرح ترین روشهای برنامه نویسی (Win32) هست، و از طرفی کتاب خاصی به زبان فارسی در این مورد وجود نداره، و همینطور در دنیا نیز کتاب در این مورد وجود نداره، تصمیم گرفتم یک مبحث در مورد آموزش Win32 درست کنم تا دوست داران Win32 بتونند با این روش برنامه بنویسند.
================================================== ======


اکنون به مبحث برنامه نویسی win32 با زبان C++ می پردازد. متأسفانه در ایران به مقوله برنامه نویسی win32 به چشم یک روش منسوخ شده می نگرند، در حالی که این شیوه یکی از گسترده ترین روشها در دنیا و پیشقدم در نوآوریهای سخت افزاری و نرم افزاری می باشد.
در این جا ما به آموزش C++ نمی پردازیم و فقط به آموزش win32 خواهیم پرداخت. البته مسائل کوچک اما مهم را از C++ حین آموزش بیان خواهیم کرد. در صورتی که مباحثی مانند typedef ، Macro ها و یا switch و ... را هنوز بلد نیستید، دست نگه دارید و ابتدا یک کتاب خوب در زمینه C++ استاندارد را مطالعه کنید.
برنامه های ویندوزی در شروع کار ابتدا خودشان را در سیستم عامل ثبت و به عبارتی رجیستر می کنند و با یک حلقه برای پیغامهای دریافتی به کار خود ادامه می دهند.
برای شروع یک مثال خیلی ساده از یک برنامه ویندوزی را مطرح می کنم. یادآوری می کنم برای شروع ابتدا باید یک پروژه Win32 از نوع Windows Application باز کنید. در زیر مراحل باز کردن یک پروژه win32 در Visual Studio 2005 نمایش داده شده :


ابتدا از منوی file > New گزینه Project را انتخاب کنید و سپس در کادر باز شده مانند زیر در سمت چپ گزینه Win32 و سمت راست گزینه Win32 Project را انتخاب کنید و در پایین پنجره یک نام برای پروژه جدید و سپس مسیر ذخیره را انتخاب و روی دکمه OK کلیک کنید.
http://barnamenevis.org/forum/attachment.php?attachmentid=22221&stc=1&d=1219480016

سپس در کادر ویزاردی که باز می¬شودگزینه Application Settings را از سمت راست انتخاب کنید. نوع پروژه را Windows application انتخاب کرده و گزینه مارک دار Empty Project را انتخاب کنید و در نهایت دکمه Finish را کلیک کنید. با این کار شما یک پروژه خالی Win32 از نوع ویندوزی را بوجود آورده اید.
http://barnamenevis.org/forum/attachment.php?attachmentid=22222&stc=1&d=1219480016

برای نوشتن کدها نیاز به یک فایل با پسوند cpp می باشد. در پنجره Solution Explorer روی Source File راست کلیک کنید و گزینه Add > New item را انتخاب کنید. در کادر باز شده شما می توانید انواع مختلفی از فایلها را به پروژه خود اضافه کنید. اما در حال حاضر ما به یک فایل cpp احتیاج داریم. در قسمت راست گزینه Code را انتخاب و در سمت چپ گزینه C++ File --- .cpp را انتخاب کنید. در زیر نام فایل را به main.cpp تغییر داده و روی دکمه Add کلیک کنید. حالا برای نوشتن کدها از main.cpp استفاده می کنیم.


در بالا روش ساخت یک پروژه به سادگی شرح داده شد. اما مبحث اصلی کدها می باشند. کد نوشته شده در زیر یک پیغام را به نمایش در خواهد آورد:



#include <windows.h>

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
LPSTR lpCmdLine, int nCmdShow)
{
MessageBoxA(NULL, "Hello world!", "Note", MB_OK);
return 0;
}


کد فوق را در main.cpp کپی کرده و برنامه را run کنید تا نتیجه مشاهده شود. این اولین و کوچکترین مثال از یک برنامه بود. حالا اجازه دهید مقداری در مورد کدها توضیح دهم. در خط اول یک هدر یا سرآیند(header) اضافه شده. توجه داشته باشید سرآیندها شامل توابع و ملحقات کتابخانه ای می باشند که در زمان نیاز در بالای کدها اضافه می شوند. سرآیند windows.h بسیاری از توابع و نوع های مربوط به Win32 را به پروژه اضافه می کند. پس برای ما وجود این سرآیند ضروری می باشد.

در خط بعدی تابع اصلی و اجرایی برنامه تعریف شده. برنامه ها ابتدا از اجرای یک تابع که اکثرا با نامهای main و یا WinMain می باشند، شروع به اجرا کرده و از طریق این تابع به قسمت های دیگر برنامه هدایت می شوند.


int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
LPSTR lpCmdLine, int nCmdShow)


توابع می توانند دارای پارامتر باشند. تابع اصلی برنامه دارای چندین پارامتر ضروری بوده که درزمان اجرای برنامه مورد استفاده قرار می گیرند. این پارامترها از نوع های تعریف شده در Win32 هستند که به اختصار در مورد آنها توضیح می دهم:

HINSTANCE hInstance : اولین پارامتر که یک هندل یا دستگیره(Handle) از برنامه اجرا شده در حافظه را به برنامه برمی گرداند. برای ارتباط با برنامه اجرا شده ما که در حافظه مستقر است، می¬توان از این پارامتر که با نام hInstance تعریف شده استفاده نمود.

HINSTANCE hPrevInstance : یک هندل ثانویه. این پارامتر همیشه در برنامه های Win32 مقدار NULL برمی گرداند. این یک هندل از نمونه برنامه اجرا شده ما در قبل را برمی گرداند. البته مقدار به این پارامتر در مد Win16 ارسال می شود و در Win32 نادیده گرفته می شود.

LPSTR lpCmdLine : از مدل آرگومانهای ارسال شده در خط فرمان(Command Prompt) می باشد و یک مقدار رشته ای در اختیار برنامه قرار می دهد. LPSTR یک نوع تعریف شده در Win32 می باشد و بعبارتی معادل یک اشاره گر از نوع char است.

int nCmdShow : یک مقدار عددی می باشد که به تابع ShowWindow() ارسال می شود. در آینده در این مورد توضیح می دهم.

hInstance برای وظایف متعددی مانند بارگذاری منابع و ... مورد استفاده قرار می گیرد و اینها در داخل و اساس ماژول برنامه اجرا می شوند.

نکته: ماژول چیست؟ یک ماژول منبع بارگذاری شده در حافظه سیستم از یک EXE و یا DLL می باشد. در اینجا برنامه ما از نوع EXE می باشد و تا زمانی که در حال اجراست، ماژول برنامه در حافظه موجود می باشد.

WINAPI در تعریف تابع یک فراخوانی قراردادی می باشد که یک نوع از __stdcall را تعیین می کند. اگر معنی این را نمی دانید نگران نباشید. در این مثال این گزینه نتیجه ملموسی برای ما ندارد. فقط یادتان باشد وجود WINAPI در تعریف این تابع ضروری است.

================================================== =======

فعلا تا اینجا بقیه مطلب را بعدا می نویسم. لازمه بگم بنده در حال جمع آوری و تدوین یک کتاب در مورد win32 هستم و این مطالب از ترجمه های منابع است.

توسعه نویس
جمعه 08 شهریور 1387, 00:37 صبح
فایلهای سرآیند header

Windows.h اصلی ترین فایل مشتمل شده در Win32 می باشد که خود فایلهای سرآیند دیگری را شامل می شود. فایلهای زیر مهمترین و مقدماتی ترین فایلهای سرآیند می باشد :


windef.h : شامل تعاریف و نوع های داده تعیین شده ابتدایی می باشد.
winnt.h : شامل تعریف نوع داده هایی می شود که از استاندارد Unicode پشتیبانی میکند.
winbase.h : شامل توابع هسته Kernel در Win32 می باشد.
winuser.h : شامل توابع رابط کاربری می باشد.
wingdi.h : شامل توابع رابط ابزار گرافیکی می باشد.

این فایلهای سرآیند تمام انواع داده، توابع قابل فراخوانی، ساختارهای داده، و ثابتهای معین را تعیین می کنند. آنها یک قسمت مهم از مستندات ویندوز می باشند.

انواع داده در Win32 :

شما می توانید تعدادی از کلمه های کلیدی و انواع داده ها را پیدا کنید که دارای تعریف مشخصی در ویندوز هستند. به عنوان مثال UINT یک نوع باز تعریف شده از unsigned int می باشد، LPSTR باز تعریف نوع char* می باشد و ... . اگر شما از بکار بردن مستقیم یک اشاره گر کاراکتر(char*) به جای LPSTR راضی تر هستید، پس این کار را با خیال راحت انجام دهید، اما قبل انجام این جایگزینی ها باید بدانید واقعا چه نوع هایی از داده ها در مقابل شما هستند و چه معنی هایی دارند.
بعضی از چیزها مقداری حالت تفسیری دارند. بدین معنی که ترکیب نام آنها ماهیت شان را شرح می دهند. برای مثال پیشوند LP در بعضی از نوع ها، نشان دهنده یک اشاره گر از جنس long (LONG Pointer) می باشد. داخل Win32 بخش Long منسوخ گشته است، از این رو نگران آن نباشید. از طرفی اگر شما نمی دانید اشاره گر چیست، دو راه در پیش رو دارید: 1- یک کتاب آموزشی از C++ برای خود دست و پا کنید، 2- به هر صورتی که هست جلو بروید و وضعیت را پیچیده کنید. من راه اول را به شما پیشنهاد می کنم، ولی بعضی از مردم راه دوم را دنبال می کنند. در هر صورت انتخاب با شماست.
مطلب بعدی که باید بدانید یک حرف C است که در مواردی جلوی پیشوند LP قرار می گیرد، و بیانگر یک نوع ثابت (const) می باشد. نوع LPCSTR نشان دهنده اشارگر به یک رشته ثابت (const string) بوده و نمی توان مقدار اشاره شده آن را اصلاح کرد. از طرف دیگر در مقابل این نوع، نوع LPSTR به مقدار ثابت اشاره نکرده و قابل ویرایش می باشد.
همچنین شما می توانید بعضی مواقع یک حرف T را هم مشاهده کنید که با اینها ترکیب شده است، این مورد برای تعریف انتخابی یکی از حالت های Unicode و یا ANSI تعبیه شده است. یعنی اینکه داده هایی از این دست به صورت خودکار مدل استاندارد کاربردی خود را انتخاب می کند. به عنوان مثال تعریف نوع داده LPTSTR در زیر نشان داده شده است:



#ifdef UNICODE
typedef LPWSTR LPTSTR;
#else
typedef LPSTR LPTSTR;
#endif

همانطور که مشاهده می کنید در صورتی که Unicode وجود داشته باشد، LPTSTR از مدل 32 بیتی LPWSTR بازتعریف می شود و در غیر این صورت از مدل 8 بیتی LPSTR بازتعریف خواهد شد. این اتفاق به دور از دید شما خواهد بود و داده LPTSTR نوع خود را با توجه به محیط انتخاب خواهد کرد.
بیشتر انواع داده در Win32 شبیه داده های ++C هستند، اگر چه عیناً مانند انواع داده در ++C نیستند. شما می توانید بدون هیچ پیش نیازی نوع داده های ++C را خیلی سریع و روشن در Win32 استفاده کنید. در Win32 انواع مختلف و متنوعی از داده ها وجود دارد که هر یک برای منظوری بکار می رود. زیاد مهم نیست که ما همه آنها را بدانیم. اما بهتر می باشد با گروهی از آنها آشنا شویم. در زیر پرکاربردترین انواع داده در Win32 معرفی شده است :

BOOL :این نوع داده در ویندوز بوده و همانند نوع int در++C می باشد و فقط مقادیر true و یا false را بخود می گیرد.

32-bit , 0 = FALSE , 1 = TRUE
-----------------------------------------------------------------------------


BOOLEAN :معادل نوع داده byte می باشد و TRUE و یا FALSE را بخود می گیرد.


8-bit , 0 = FALSE , 1 = TRUE
-----------------------------------------------------------------------------

WORD :این یک نوع عددی (integer) 16 بیتی می باشد. این نوع کمی شبیه به Long می باشد. مخصوصا زمانی که در بعضی توابع ویندوز استفاده می شود. این نوع معادل نوع unsigned short در ++C می باشد.

16-bit , 0 to 65535
-----------------------------------------------------------------------------
FLOAT :این نوع دقیقاً معادل نوع float در ++C می باشد.

-----------------------------------------------------------------------------
UINT :این نوع معادل unsigned int در ++C می باشد.

32-bit , 0 to 4294967295
-----------------------------------------------------------------------------
UINT8 :معادل نوع unsigned char در ++C می باشد.

8-bit , 0 to 255
-----------------------------------------------------------------------------
UINT16 :معادل نوع unsigned short در ++C می باشد.

16-bit , 0 to 65535
-----------------------------------------------------------------------------
UINT32 :معادل نوع unsigned int در ++C می باشد.

32-bit , 0 to 4294967295
-----------------------------------------------------------------------------
UINT64 :معادل نوع unsigned __int64 می باشد.

64-bit , 0 to 18446744073709551615
-----------------------------------------------------------------------------
WINAPI, APIENTRY, CALLBACK, APIPRIVATE, STDCALL :
تمام اینها مانند نوع stdcall__ می باشند، و این یک حالت فراخوانی قراردادی استاندارد می باشد.

------------------------------------------------------------------------------
CDECL, WINAPIV :هر دو مانند نوع cdecl_ هستند که یک حالت فراخوانی قراردادی در ++C می باشد.

------------------------------------------------------------------------------
FASTCALL :همانند fastcall_ بوده، که یک حالت فراخوانی قراردادی در ++C می باشد.

------------------------------------------------------------------------------
PASCAL :همانند pascal_ بوده، که یک حالت فراخوانی قراردادی در ++C می باشد.

------------------------------------------------------------------------------
WPARAM :همانند یک اشاره گر به نوع unsigned int می باشد و درون پیغامهای ویندوزی استفاده می شود.



------------------------------------------------------------------------------
LPARAM :این نوع داخل توابع API درWin32 ، مورد استفاده گروهی از پیغامهای ویندوزی که با پیشوند _WM شروع می شوند قرار می گیرد، و در حقیقت یک اشاره گر به یک مقدار Long می باشد.
------------------------------------------------------------------------------
HRESULT :همانند نوع long در ++C بوده و برای ثبت و ارسال خطا و هشدار بکار می رود.

32-bit
------------------------------------------------------------------------------
LRESULT :همانند نوع HRESULT در Win32 بوده، اما یک اشاره گر به مقدار LONG می باشد.
------------------------------------------------------------------------------
INT :همانند نوع int در ++C بوده، اما علامت دار و با محدوده منفی.

32-bit , signed
,-2147483648 to 2147483647
------------------------------------------------------------------------------
BYTE :مترادف نوع unsigned char در ++C می باشد، و برای کاراکترهای متنی استفاده می شود.

8-bit block of data
------------------------------------------------------------------------------
DWORD :همانند نوع unsigned long در ++C استاندارد می باشد.

32-bit , 0 to 4294967295
------------------------------------------------------------------------------
LONG :همانند INT بوده و از long در ++C بازتعریف شده.

32-bit , signed
-2147483648 to 2147483647
------------------------------------------------------------------------------
HANDLE :یک نوع استاندارد از long بوده و برای ذخیره دستگیره های اشیاء مختلف در Win32 بکار میرود.
------------------------------------------------------------------------------
HINSTANCE :شبیه به HANDLE بوده، با این تفاوت که برای تعریف و ایجاد یک نمونه از خصوصیات پنجره برای هر شیئی بکار می رود.
------------------------------------------------------------------------------
HWND :مخفف عبارت (Handle Window) و از نوع long بوده و برای اشاره کردن به شیء پنجره بکار می رود.



------------------------------------------------------------------------------
LPSTR :اشاره گر به یک مقدار String در Win32 می باشد.
------------------------------------------------------------------------------
LPCSTR :اشاره گر به یک مقدار String در Win32 می باشد.
------------------------------------------------------------------------------
LPTSTR :اشاره گر به یک مقدار ثابت متنی String

8-bit ANSI , or 32-bit UNICODE
------------------------------------------------------------------------------
LPCTSTR :اشاره گر به یک مقدار متنی با دو حالت باز تعریفی، به صورت ANSI و یا UNICODE.

8-bit ANSI , or 32-bit UNICODE
------------------------------------------------------------------------------



گروهی از برنامه های ویندوز از سیستمی به نام “Hungatian notation” برای نامگذاری متغیرها استفاده می کنند. در این سیستم به ابتدای نام متغیرها یک پیشوند کوتاه اضافه می کنند و با این پیشوند نوع داده متغییر را نشان می دهند. به عنوان مثال حرف " i " به عنوان نشان دهنده نوع int بکار می رود. و حروف "sz" بیانگر یک نوع متغییر string می باشد که با مقدار دهی یک عدد صفر خالی می شود.
تابع WinMain() با قابلیت برگرداندن یک مقدار عددی int تعریف شده است. علامت WINAPI در فایل windef.h تعریف شده است. عبارت زیر حالت بازتعریفی آن را نشان می دهد:


#difine WINAPI __stdcall
این عبارت ویژه یک فراخوانی قراردادی می باشد و باعث می شود در کد کامپایل شده به زبان ماشین تابع به حالتی ترجمه شده باشد که با استاندارد سیستم عامل ویندوز همخوانی داشته باشد. WINAPI چگونگی و طریقه بارگذاری تابع و آرگومانهایش را داخل فضای پشته (stack) تعیین می کند. به عبارت دیگر توابعی که باید از محیط ویندوز فراخوانی شوند، باید به نوعی برای محیط ویندوز استاندارد شوند و این کار را نوع WINAPI انجام می دهد. اکثر توابع قابل فراخوانی در ویندوز با این کلمه کلیدی تعریف گشته اند.

================================================== ==
این قسمت هم تمام شد . منتظر بعدی باشید.:چشمک:

توسعه نویس
یک شنبه 17 شهریور 1387, 15:48 عصر
تابع ()MessageBox :
این تابع مخصوص نمایش پیامهای کوتاه روی صفحه نمایش طراحی شده است. تیتر موجود در پنجره پیغام ()MessageBox باید نشان دهنده یک عبارت کوتاه سنجیده در رابطه با این پنجره پیغام باشد، اگر چه خیلی هم با محتوای آن مطابق نباشد.
اولین آرگومان ارسالی به ()MessageBox در حالت معمولی یک دستگیره پنجره است. دومین آرگومان ارسالی یک مقدار متنی می باشد که در میانه بدنه پنجره پیغام نمایش می یابد، و سومین آرگومان ارسالی یک مقدار کوتاه متنی می باشد که در بالای پنجره به عنوان تیتر بکار می رود. چهارمین آرگومان دارای قابلیت دریافت یک مقدار مخلوط از مقادیر ثابتی می باشد که در سرآیند winuser.h تعریف شده اند و با پیشوند _MB شروع می شوند. این مقادیر ثابت امکان تنظیم پنجره با دکمه ها و آیکون های نمایشی مخصوص را فراهم می کند.

باید تا به حال دیده باشید که مقادیر ثابت متعددی را بوسیله Or بیتی یعنی علامت " | " ، با هم ترکیب کرده و به یک تابع ارسال می کنند.در حقیقت با این کار چندین پرچم را در یک مقدار (که اکثرا یک بایت می باشد) ذخیره کرده و ارسال می کنند. تابع هدف نیز این پرچم ها را از مقدار مربوطه استخراج کرده و طبق آنها اقدام می کند. این یک مدل مرسوم در Win32 میباشد. شما می توانید اولین مقدار ثابت تنظیمی را برای نمایش دکمه هایی که می خواهید روی پنجره پیغام ظاهر شوند را از لیست زیر انتخاب کنید :


#define MB_OK 0x00000000L
#define MB_OKCANCEL 0x00000001L
#define MB_ABORTRETRYIGNORE 0x00000002L
#define MB_YESNOCANCEL 0x00000003L
#define MB_YESNO 0x00000004L
#define MB_RETRYCANCEL 0x00000005L



زمانی که شما آرگومان چهارم را با مقدار صفر مقداردهی می کنید، پنجره پیغام فقط دکمه ok را ظاهر می کند. بعد از انتخاب دکمه ها، می تواند دکمه پیش فرظ را نیز انتخاب کنید. زمانی که پنجره Load می شود بطور خودکار فوکوس روی دکمه پیش فرظ قرار می گیرد. بوسیله گذاشتن علامت " | " بین مقادیر ثابت، آنها با هم ترکیب می شوند. لذا پس از مقدار ثابت دکمه ها یکی از مقادیر زیر را قرار دهید و دکمه پیش فرظ مورد نظر خود را انتخاب کنید:


#define MB_DEFBUTTON1 0x00000000L
#define MB_DEFBUTTON2 0x00000100L
#define MB_DEFBUTTON3 0x00000200L
#define MB_DEFBUTTON4 0x00000300L



همچنین می توانید برای اضافه کردن آیکون های استاندارد ویندوز برای بیان نوع پنجره پیغام، از ثابتهای زیر استفاده کنید :


#define MB_ICONHAND 0x00000010L
#define MB_ICONQUESTION 0x00000020L
#define MB_ICONEXCLAMATION 0x00000030L
#define MB_ICONASTERISK 0x00000040L



تمام این آیکون ها دارای نام دیگری نیز می باشند. نام دیگر این آیکون ها در زیر آمده است :


#define MB_ICONWARNING MB_ICONEXCLAMATION
#define MB_ICONERROR MB_ICONHAND
#define MB_ICONINFORMATION MB_ICONASTERISK
#define MB_ICONSTOP MB_ICONHAND



تعداد دیگری مقادیر ثابت که با _MB شروع می شوند نیز وجود دارد. اما توضیحاتی که تا اینجا مطرح شد پاسخگوی تمام نیازهای شما برای یک پنجره پیغام می باشد. در صورت اطلاعات بیشتر می توانید به راهنمای MSDN مراجعه کنید.
قدم بعدی برای پنجره پیغام، بازگرداندن مقداری متناسب با توجه به دکمه فشرده شده در پنجره می باشد. در مثالی که آوردیم، پنجره پیغام مقدار 1 را برمی گرداند. مقدار 1 مخصوص IDOK می باشد و بیان می کند که کاربر دکمه ok را در پنجره پیغام فشرده است. برای دکمه های دیگر مقادیر IDYES ، IDNO ، IDCANCEL ، IDABORT ، IDRETRY و IDIGNORE در نظر گرفته شده است. ارسال یکی از این مقادیر از طریق تابع ()MessageBox بیانگر دکمه ای است که کاربر فشرده است.اینها مقادیر ثابتی هستند که در winuser.h تعریف شده اند.

اکنون مطالب گفته شده را با یک مثال آزمایش می کنیم :



#include <windows.h>

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
LPSTR lpCmdLine, int nCmdShow)
{
// declare variable
UINT8 res;
LPSTR MyMessage;

// show MessageBox
res = MessageBoxA(NULL, "Please Click own of the Button.", "Note",
MB_YESNOCANCEL|MB_DEFBUTTON3|MB_ICONQUESTION);

// check what press of buttons
if (res == IDYES)
MyMessage = "You now Click (Yes) Button !";
else if (res == IDNO)
MyMessage = "You now Press (No) Button !";
else if (res == IDCANCEL)
MyMessage = "You now Press (Cancel) !";

// show Result by MessageBox
MessageBoxA(NULL, MyMessage, "Result", MB_ICONINFORMATION);

return 0;
}



در مثال بالا ابتدا دو متغیر تعریف کردیم. متغیر res که از نوع UINT8 می باشد، مقدار بازگشتی از تابع ()MessageBox را در خود ذخیره می کند. سپس این مقدار توسط شرط نوشته شده تست می شود. متغیر دوم که از نوع LPSTR می باشد، متناسب با دکمه فشرده شده، آدرس یکی از متن های نوشته شده را در خود ذخیره کرده و سپس این متغیر توسط تابع ()MessageBox دوم برای نمایش متن استفاده می شود.
در Win32 دو مدل از تابع ()MessageBox وجود دارد. یک تابع با نام ()MessageBoxA که با نوع رشته ای Ascii کار می-کند و دوم تابع ()MessageBoxW بوده که با نوع رشته ای Unicode کار می کند. اگر به آرگومانهای درخواستی هر کدام نگاه کنید متوجه اختلاف بین این دو تابع خواهید شد. همینطور طریقه بکار گیری ثابتهای مخصوص در آرگومان چهارم را نگاه کنید. سعی کنید مقادیر ثابت در مثال را با مقادیر توضیح داده شده دیگر جایگزین کرده و نتیجه را مشاهده کنید.

کامپایل، اتصال و اجرا :
برای کامپایل برنامه خود و اجرای آن، بعد از نوشتن کدها دکمه F5 را فشار دهید. در این زمان Visual Studio پیامی را روی صفحه ظاهر می کند و از شما می پرسد که برنامه را کامپایل کند یا خیر. در صورت انتخاب دکمه Yes برنامه کامپایل شده و اجرا می شود. در صورت انتخاب دکمه No برنامه با کامپایل قبلی اجرا می شود و اگر قبلا برنامه را کامپایل نکرده اید یک پیغام خطا نمایش داده می شود. در نوار ابزار نیز یک دکمه مثلث وجود دارد که کار کلید F5 را انجام می دهد. در صورتی که بخواهید پروژه را فقط کامپایل کرده و اجرا نکنید می توانید کلیدهای ترکیبی Ctrl+Shift+B را فشرده و یا از منوی Build گزینه Build Solution و یا {Build {Project Name را انتخاب کنید.
در حالت معمولی طی مرحله کامپایل، کامپایلر یک شیئ که یک فایل OBJ. می باشد را از منبع کد برنامه استخراج می کند. سپس کامپایلر وارد مرحله اتصال ( link ) می شود. در طی مرحله اتصال، اتصال دهنده با ترکیب فایل OBJ. با فایلهای کتابخانه ای LIB. فایل اجرایی EXE. را می سازد. می توانید لیستی از این فایلهای کتابخانه ای را در قسمت تنظیمات پروژه خود مشاهده نماید.حتما نام سه فایل KERNEL32.LIB ، USER32.LIB ، GDI32.LIB را مشاهده کنید. این کتابخانه ها سه زیر سیستم بزرگ ویندوز هستند. آنها حاوی نامهای کتابخانه های دینامیکی DLL. و منبع اطلاعاتی هستند که فایل EXE. به آنها نیازمند می باشد. ویندوز از این اطلاعات برای مرتفع کردن فراخوانی ها از برنامه شما به توابع داخل کتابخانه های دینامیکی KERNEL32.DLL ، USER32.DLL ، GDI32.DLL استفاده می کند.

================================================== ===
در آینده در مورد پنجره ها مطالب را شروع می کنیم.

توسعه نویس
شنبه 23 شهریور 1387, 13:54 عصر
پنجره ها و پیغامها :

در فصل گذشته مثالهای ما از تابع ()MessageBox برای نمایش یک خروجی متنی به کاربر مورد استفاده قرار می گرفت. تابع ()MessageBox یک پنجره می سازد. در ویندوز کلمه "Window" به معنای پنجره، دارای یک معنای مختصر و مفید است. یک پنجره، یک فضای مستطیل شکل بر روی صفحه نمایش می باشد که از کاربر ورودی گرفته و خروجی را بصورت متن و گرافیک نمایش می دهد. این یک تعریف ساده و ابتدایی از یک پنجره بود و البته پنجره یک واسطه گرافیکی و تعاملی برای ارتباط کاربر با برنامه شما می باشد.

تابع ()MessageBox یک پنجره می سازد اما این پنجره برای مقصود خاصی و با انعطاف پذیری محدود بکار می رود. پنجره پیغام از یک نوار عنوان و یک دکمه برای بستن و چندین خط برای توضیح و یک آیکون تصویری تشکیل شده. محدوده سفارشی کردن این پنجره به یک مجموعه کوچک دکمه ها و آیکون ها که در سیستم عامل ویندوز تدارک دیده شده محدود می شود. پنجره پیغام تنها هدف ما نبوده و ما باید برای تمام نیازهایمان پنجره مخصوص خودمان را بسازیم.


اطلاعاتی در مورد پنجره :

پنجره برای ساخته شدن نیاز به تابع ()CreateWindow دارد. این تابع عملا یک پنجره می سازد. ولی قبل از ساخته شدن یک پنجره نیاز به تنظیماتی می باشد. اولین آرگومان تابع ()CreateWindow یک نمونه از کلاسی به نام کلاس پنجره (Window Class) می باشد و این کلاس در برنامه زمان اجرا ، با چیزی به نام پروسیجر پنجره (Window Prosedure) در ارتباط است. عجله نکنید، هم اکنون ما قبل از ساخته شدن پنجره نیاز به یکسری اطلاعات پس زمینه داریم که مفیدند.


بازبینی یک معماری :

زمانی که شما برای ویندوز برنامه نویسی می کنید، واقعا در حال برنامه نویسی با یک نوع خاص از شیء گرایی هستید. این موضوع بیشتر زمانی نمود پیدا می کند که شما داخل یک شیء مشغول به کار هستید. یک شیء مهمتر وجود دارد که نام ویندوز را بخود گرفته است. بنظر می آید این شیء رفتارهایی شبیه به انسان دارد. این شیء می تواند در خیال شما این را مجسم کند که : این شیء واقعاً می داند که یک پنجره است.

بیشترین پنجره های قابل دید که صفحه دسکتاپ شما را مزین می کنند از نوع اپلیکیشن های پنجره (WindowsApplication) می باشند. این پنجره ها شامل قسمتهایی مانند نوار عنوان برای نمایش یک نام، یک نوار منو، و در موارد نیاز داری نوار ابزار، نوار پیمایش و ... می باشد. انواع دیگر پنجره ها در حقیقت پنجره های محاوره ای (DialogBox) می باشند، که از پیش آماده و برای مقاصد محدود و استاندارد بکار می رود.

اشیاء گوناگون دیگری نیز در پنجره های محاوره ای وجود دارند که نسبتا کمتر به چشم می آیند. مانند buttons، radio buttons ، check box ، list box، scrollbar و ... . هر کدام از این اشیاء کوچک قابل دید، در حقیقت یک پنجره می باشد که مخصوصا بیشتر به آنها پنجره های فرزند و یا پنجره های کنترل و یا کنترل های بچه پنجره می گویند.

کاربر این پنجره ها را به صورت اشیاء در صفحه نمایش مشاهده می کند و بوسیله ماوس و کیبرد مستقیما با آنها در تعامل است. این نکته به اندازه کافی قابل توجه می باشد که یک برنامه نویس این اشیاء را همانگونه می بیند که یک کاربر آنها را مشاهده می کند. پنجره ورودی از کاربر را در قالب پیغام هایی که به پنجره ارسال می شود دریافت می کند. همچنین پنجره از این پیغامها برای تعامل با پنجره های دیگر استفاده می کند. درک صحیح پیغامها و طریقه عملکرد آنها یک بخش مهم از این آموزش است که چگونه برای ویندوز برنامه بنویسیم.

این یک مثال در مورد پیغامهای ویندوز می باشد: همانطور که می دانید بیشتر برنامه های ویندوز دارای پنجره های قابل تغییر اندازه می باشند. یعنی اینکه شما می توانید با کلیک ماوس روی لبه پنجره و کشیدن آن، اندازه پنجره را تغییر دهید. برنامه نیز بارها با اصلاح همزمان محتویات مربوط به پنجره به این تغییر پاسخ می دهد. آیا توانستید حدس بزنید؟ ویندوز خودش سریعتر از یک برنامه اپلیکیشن قادر است تا کدهای شلوغ و پیچیده خود را در زمان مثلا تغییر اندازه پنجره بررسی کند. با این حال اپلیکیشن می داند که پنجره تغییر اندازه داده است.

حال اپلیکیشن چگونه متوجه می شود که کاربر اندازه پنجره را تغییر داده است؟ برنامه نویسان اغلب به برنامه نویسی حالت نوشتاری (Character-mode)که قرار دادی می باشد عادت کرده اند. اما طرزکار سیستم عامل برای رساندن اطلاعات بدین صورت نمی باشد. حال یک جواب باید برای این سوال محوری باشد تا بهتر معماری ویندوز را بشناسیم. زمانی که کاربر پنجره را تغییر اندازه می دهد، ویندوز یک پیغام به برنامه ارسال می کند که مشخص کننده اندازه جدید پنجره است. سپس برنامه نیز می تواند محتویات پنجره را تنظیم کند و اندازه جدید را بازگرداند.

" ویندوز یک پیغام به برنامه ارسال می کند" من امیدوارم که شما این عبارت را سطحی نخوانید. این به چه معناست؟ سیستم عامل چگونه می تواند به یک برنامه پیغامی ارسال کند؟
در حقیقت سیستم عامل یک تابع خاص را در برنامه شما فراخوانی می کند. این تابع را شما می نویسید و این تابع در اصل یک قسمت ضروری از کد برنامه شما می باشد. برنامه نویسان در این تابع به بررسی خصوصیات پیغام می پردازند که توسط ویندوز ارسال شده و برنامه شما آن را دریافت کرده است. این تابع را پروسیجر پنجره (window procedure) می نامند.

بدون شک شما به این تصور عادت کرده اید که همیشه این برنامه است که فراخوانی توابع را به سیستم عامل انجام می دهد. برای مثال این در مواقعی مانند باز کردن یک فایل از دیسک می باشد. پس در برنامه های ویندوز هر دوی حالات وجود دارد.

به ازای هر پنجره یک پروسیجر پنجره در برنامه مربوط به آن وجود دارد. این پروسیجر پنجره می تواند در برنامه خودش یا در یک DLL قرار داشته باشد. ویندوز بوسیله فراخوانی پروسیجر پنجره یک پیغام را به پنجره ارسال می کند. در این تابع نیز پردازش روی برخی از پیغامها که از طرف برنامه نویس مشخص شده است انجام شده و سپس دستورات و تنظیمات جدید به پنجره ارسال می شود.

حال موضوع را بیشتر می شکافیم. هر پنجره معمولا از پایه کلاس پنجره (window class) ساخته می شود. این کلاس پنجره است که در اصل پروسیجر پنجره را تشخیص می دهد. با استفاده از کلاس پنجره، این اجازه را داریم که چندین پنجره را از پایه یک کلاس پنجره مشترک بسازیم، از این رو از یک پروسیجر پنجره نیز می توانیم برای چندین پنجره استفاده کنیم. به عنوان مثال، تمام دکمه ها در تمام برنامه های ویندوزی از پایه یک کلاس پنجره مشترک می باشند. این کلاس پنجره نیز وابسته به یک پروسیجر پنجره می باشد که در یک DLL در ویندوز قرار دارد و آن هم پردازش پیغامهای تمام دکمه ها را در وینـدوز انجام می دهد.

در برنامه نویسی شیء گرا، یک شیء مرکب از کد و داده می باشد. پنجره یک شیء است. پروسیجر پنجره، کد می باشد. و داده اطلاعاتی هستند که توسط پروسیجر پنجره و یا سیستم عامل برای هر پنجره نگهداری می شود.

خیلی از پیغام های ویندوز حاوی ورودی کاربر از طریق ماوس و کیبرد می باشند که به پنجره ارسال می شوند. به عنوان مثال دکمه ها که گفته شد نوعی پنجره هستند می فهمند که از طریق ماوس رویشان کلیک شده است. مابقی پیغامها با پنجره تماس می گیرند و اطلاعاتشان را ارسال می کنند. مانند زمانی که پنجره تغییر سایز می هد و یا زمانی که سطح پنجره نیاز به ترسیم مجدد دارد.

زمانی که یک برنامه ویندوزی شروع به اجرا می کند، ویندوز یک صف پیغام (message queue) برای آن برنامه می سازد و در این صف پیغام تمام پیغامهای پنجره هایی که برنامه می تواند بسازد ذخیره می گردد. یک اپلیکیشن ویندوزی مشتمل شده از یک قطعه کوتاه از کد که آنرا حلقه پیغام (message loop) می نامند و ارسال کننده پیغامها. حلقه پیغام وظیفه دریافت پیغامهای ارسالی را بر عهده دارد و ارسال کننده نیز این پیغام ها را به پروسیجر پنجره مقتضی می فرستد. مابقی پیغام ها بطور مستقیم بدون قرارگیری در صف پیغام ها به پروسیجر پنجره ارسال می شوند.

یک برنامه ویندوزی رویداد گرا می باشد. این بدین معنی است که شما به عنوان برنامه نویس، فرضاً در یک حالت دفاعی به سر می برید. یک کاربر پنجره در دست رس را با عملهای مختلف بمب باران می کند و پنجره نیز برنامه شما را با پیغامهایی متناظر با عملیات کاربر همزمان بمب باران می کند. کلا شما مرتب پیغامهای تازه رسیده را چک می کنید و جواب را به پنجره ارسال می کنید. تصویر زیر بصورت شماتیک مراحل را نشان می دهد.


http://www.barnamenevis.org/forum/attachment.php?attachmentid=23099&stc=1&d=1221295985


پنجره رویدادهای (Events) مختلفی را دریافت می کند، مانند کیبرد، ماوس، پورتها و ... . هر رویداد زمان دریافت به سرعت به یک پیغام تبدیل می شود. در اینجا سیستم عامل ویندوز پیغام را به پنجره مربوطه مخابره می کند. به عنوان مثال تمام پیغامهای دریافت شده از صفحه کلید به پنجره ای که فوکوس (Focus) را در دست دارد (پنجره فعال) فرستاده می شود. پیغامهای ماوس نیز به محل موقعیت مکانی نشانگر ماوس فرستاده می شوند و معمولا آنها به پنجره ای که مستقیما زیر نشانگر قرار دارند انتقال می یابند (مگر برنامه هایی که از ماوس استفاده نمی کنند).

برنامه شما با فراخوانی تابع ()GetMessage یک پیغام را بازیابی می کند. سپس شما با فراخوانی تابع ()DispatchMessage پیغام را به پنجره برمی گردانید. سوالی که وجود دارد اینست که آیا پنجره قادر به ارسال پیغامها به خودش نیست؟ جواب: اصولا باید قادر به ارسال باشد، اما حلقه تکرار پیغامها این توانایی را به برنامه شما می دهد تا بصورت نامحسوس پنجره را زیر نظر داشته باشد و همچنین عملیات اضافی احتمالی را قبل از ارسال روی پیغامها انجام دهید.

اگر چشمان شما از این توضیحات در مورد معماری ویندوز سیاهی رفته ناراحت نباشید. مثالی که ما از طریقه ساخت پنجره ها بیان خواهیم کرد، دید شما را در مورد اینکه پنجـره، کلاس پنجره، پروسیجر پنجره، صف و حلقه پیـغامها چیستند روشنتر خواهد کرد.

توسعه نویس
یک شنبه 12 آبان 1387, 16:29 عصر
یک مثال از ساخت پنجره :



#include <windows.h>
const char g_szClassName[] = "myWindowClass";
// Step 4: the Window Procedure
LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
switch(msg)
{
case WM_CLOSE:
DestroyWindow(hwnd);
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
return DefWindowProc(hwnd, msg, wParam, lParam);
}
return 0;
}
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
LPSTR lpCmdLine, int nCmdShow)
{
WNDCLASSEX wc;
HWND hwnd;
MSG Msg;
//Step 1: Registering the Window Class
wc.cbSize = sizeof(WNDCLASSEX);
wc.style = 0;
wc.lpfnWndProc = WndProc;
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hInstance = hInstance;
wc.hIcon = LoadIcon(NULL, IDI_APPLICATION);
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
wc.lpszMenuName = NULL;
wc.lpszClassName = (LPCWSTR)g_szClassName;
wc.hIconSm = LoadIcon(NULL, IDI_APPLICATION);
if(!RegisterClassEx(&wc))
{
MessageBox(NULL, (LPCWSTR)"Window Registration Failed!", (LPCWSTR)"Error!",
MB_ICONEXCLAMATION | MB_OK);
return 0;
}
// Step 2: Creating the Window
hwnd = CreateWindowEx(
WS_EX_CLIENTEDGE, //DWORD dwExStyle
(LPCWSTR)g_szClassName, //LPCWSTR lpClassName
(LPCWSTR)"The title of my window", //LPCWSTR lpWindowName
WS_OVERLAPPEDWINDOW, //DWORD dwStyle
CW_USEDEFAULT, //int X
CW_USEDEFAULT, //int Y
350, //int nWidth
280, //int nHeight
NULL, //HWND hWndParent
NULL, //HMENU hMenu
hInstance, //HINSTANCE hInstance
NULL); //LPVOID lpParam
if(hwnd == NULL)
{
MessageBox(NULL, (LPCWSTR)"Window Creation Failed!", (LPCWSTR)"Error!",
MB_ICONEXCLAMATION | MB_OK);
return 0;
}
ShowWindow(hwnd, nCmdShow);
UpdateWindow(hwnd);
// Step 3: The Message Loop
while(GetMessage(&Msg, NULL, 0, 0) > 0)
{
TranslateMessage(&Msg);
DispatchMessage(&Msg);
}
return Msg.wParam;
}

کد نوشته شده فوق حدوداً متشکل از 80 خط بوده و بیشتر کدهای لازم برای ساخت یک پنجره ساده را شرح می دهد. اگر شما آن را در برنامه نوشته و کامپایل کنید، باید بدون هیچ مشکلی اجرا شود.
مثالی که نوشبیم از 4 مرحله تشکیل شده. این مراحل را برای کمک به فهم بهتر روال کار ایجاد کردیم. در ثانی این تقسیم بندی اجازه می دهد که بتوانیم درست تر این روال را توضیح دهیم.

اجازه بدهید مراحل کار را با هم بازبینی کنیم:


مرحله 1 - رجیستر یک کلاس پنجره :

کلاس پنجره محل ذخیره اطلاعاتی می باشد که می توان با آنها توسط پروسیجر پنجره، خصوصیات یک پنجره را کنترل کرد. اطلاعاتی از قبیل رنگ پس زمینه، آیکن های کوچک و بزرگ برای پنجره و ... از جمله خصوصیاتی هستند که در هنگام ساخت کلاس پنجره تنظیم می شوند. همانطور که قبلا اشاره شد در این روش یکبار با ساخت یک کلاس پنجره، خصوصیات را تنظیم کرده و سپس می توان پنجره های متعددی را از روی آن ساخت، بدون اینکه چندین مرتبه پیاپی خصوصیاتشان را تنظیم کرد. با این وجود می توان اکثر خصوصیات هر پنجره را در زمانی دیگر جداگانه مقداردهی کرد.


const char g_szClassName[] = "myWindowClass";


به وسیله متغییر بالا می توان یک نام برای کلاس پنجره ذخیره نمود. این متغییر در ناحیه عمومی تعریف شده و در زمان حیات برنامه در حافظه باقی می ماند. ما از آن برای رجیستر کلاس پنجره مان در سیستم استفاده می کنیم.


WNDCLASSEX wc;


بوسیله این کد یک نمونه از ساختار WNDCLASSEX را می سازیم، که در حقیقت کلاس پنجره ما می باشد.


wc.cbSize = sizeof(WNDCLASSEX);
wc.style = 0;
wc.lpfnWndProc = WndProc;
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hInstance = hInstance;
wc.hIcon = LoadIcon(NULL, IDI_APPLICATION);
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
wc.lpszMenuName = NULL;
wc.lpszClassName = (LPCWSTR)g_szClassName;
wc.hIconSm = LoadIcon(NULL, IDI_APPLICATION);
if(!RegisterClassEx(&wc))
{
MessageBox(NULL, (LPCWSTR)"Window Registration Failed!", (LPCWSTR)"Error!",
MB_ICONEXCLAMATION | MB_OK);
return 0;
}


کدهای بالا در تابع ()WinMain نوشته شده اند. ابتدا تمام خصوصیات مورد نیاز و ضروری را برای کلاس پنجره مقدار دهی کرده و سپس با فراخوانی تابع ()RegisterClassEx (همراه با ارسال آدرس کلاس پنجره بعنوان آرگومان تابع)، کلاس پنجره را در سیستم عامل ثبت و بعبارتی رجیستر می کنیم.
توجه کنید که همزمان تابع در شرط if نوشته شده و در حقیقت بلافاصله پس از اتمام کار تابع، مقداری باز گردانده شده و شرط در صورت نبودن مقدار یا NULL بودن اجرا می شود و بعد از نمایش یک پیغام، برنامه به اجرا خاتمه می دهد. در صورتی که تابع موفق به ثبت کلاس پنجره شود، شرط if اجرا نمی شود و تابع ()WinMain با ادامه اجرا وارد مرحله دوم خواهد شد.
گروهی از اعضای ساختاری که ما یک نمونه از آن را به عنوان کلاس پنجره تعریف کردیم به شرح زیر می باشد:
cbSize : اندازه نمونه ساختار تعریف شده برای تخصیص در حافظه.
style : کلاس Styles که با پیشوند CS_ می باشد. برای تعیین شیوه پنجره. ( با Window Styles که با پیشوند WS_ می باشد اشتباه گرفته نشود). این خصوصیت معمولاً با صفر مقداردهی می شود.
lpfnWndProc : یک اشاره گر به پروسیجر پنجره می باشد. آدرس پروسیجر پنجره می بایست در کلاس پنجره ثبت شود تا بعد از رجیستر شدن ویندوز از طریق این اشاره گر پروسیجر پنجره را بشناسد. در این مثال پروسیجر پنجره ما WndProc نام دارد.
cbClsExtra : یک مقدار برای تخصیص حافظه خارجی برای این کلاس. معمولاً صفر می باشد.
cbWndExtra : یک مقدار برای تخصیص حافظه خارجی برای هر پنجره ای که از این کلاس ساخته می شود. معمولاً صفر می باشد.
hInstance : دستگیره ای از یک نمونه اجرا شده از اپلیکیشن برنامه.(ما اولین پارامتر تابع ()WinMain را به آن می-دهیم).
hIcon : یک آیکن بزرگ برای پنجره (معمولا 32*32). این آیکن زمانی که کاربر کلیدهای ترکیبی Alt+Tab را فشار می دهد تا بین پنجره ها حرکت کند، نمایش داده می شود.
hCursor : یک نشانگر ماوس برای زمانی که ماوس کاربر روی ناحیه پنجره می رود.
hbrBackground : پس زمینه ترسیمی، برای تنظیم رنگ پس زمینه پنجره بکار می رود.
lpszMenuName : یک نام از یک منبع منو، برای استفاده ویندوز توسط این کلاس می باشد.
lpszClassName : یک نام که برای احراز هویت کلاس بکار می رود.
hIconSm : یک آیکن کوچک برای پنجره (معمولا 16*16). برای نمایش در TaskBar و گوشه بالای سمت چپ پنجره بکار می رود.
اگر این خصوصیات برایتان مبهم است، زیاد نگران نباشید. توضیحاتی که در قسمتهای بعدی خواهم داد بیش از پیش این موارد را روشن خواهد کرد. نکته دیگری هم هست که باید بدانید. راحت باشید ! . روشنتر می گویم، من خیلی بندرت ساختارها و پارامترهای توابع را به خاطر می سپارم. چون این کار هرز دادن تلاش و خصوصاً زمان مفید می باشد. اگر شما متوجه شوید که نیاز به فراخوانی یک تابع دارید، پیدا کردن و کسب اطلاع از پارامترهای آن تابع برای شما مهم می شود. سپس می توانید این پارمترها و خصوصیاتشان را از منابع کمکی پیدا کنید. به مرور هم پارامترهای توابعی که زیاد استفاده می کنید، در خاطرتان خواهد ماند.

مرحله 2 - ساختن پنجره :
بعد از اینکه کلاس پنجره رجیستر شد، نوبت به ساخت یک پنجره از آن می رسد. حال لازم است نگاهی به تابع ()CreateWindowEx بیندازیم.

HWND hwnd;
در ابتدای تابع ()WinMain یک متغییر از نوع HWND تعریف کردیم. این متغییر یک دستگیره از پنجره را نگهداری می کند که در مثال ما توسط تابع ()CreateWindowEx بازگردانده خواهد شد.


hwnd = CreateWindowEx(
WS_EX_CLIENTEDGE, //DWORD dwExStyle
(LPCWSTR)g_szClassName, //LPCWSTR lpClassName
(LPCWSTR)"The title of my window",//LPCWSTR lpWindowName
WS_OVERLAPPEDWINDOW, //DWORD dwStyle
CW_USEDEFAULT, //int X
CW_USEDEFAULT, //int Y
350, //int nWidth
280, //int nHeight
NULL, //HWND hWndParent
NULL, //HMENU hMenu
hInstance, //HINSTANCE hInstance
NULL); //LPVOID lpParam


اولین پارامتر مقدار WS_EX_CLIENTEDGE را دریافت می کند. پارامتر اول یک قالب توسعه داده شده می باشد. در این مورد من آن را با یک حالت حاشیه تو رفته در اطراف پنجره تنظیم کرده ام. اگر پنجره را با حالت پیشفرظ ویندوز می-خواهید، به این پارامتر مقدار صفر بدهید. همچنین با مقادیر دیگر هم بازی کنید تا نتیجه آنها را نیز مشاهده کنید.
پارامتر دوم نام کلاسی که پنجره از روی آن ساخته می شود را دریافت می کند. تابع به وسیله این نام با سیستم ارتباط برقرار کرده و مشخص می سازد که این پنجره از کدام نوع از کلاسهای رجیستر شده موجود در سیستم ساخته می شود.
پارامتر سوم یک نام برای عنوان پنجره دریافت می کند. این نام در قسمت نوار عنوان پنجره و همچنین در قسمت TaskBar نمایش داده خواهد شد.
پارامتر چهارم یک قالب استاندارد پنجره را دریافت می کند. ما از مقدار WS_OVERLAPPEDWINDOW استفاده کردیم.
پارامتر پنجم و ششم موقعیت مکانی پنجره را بر حسب محورهای x و y تعیین می کند. ما از مقدار CW_USEDEFAULT استفاده کردیم. با استفاده از این مقدار به ویندوز اجازه دادیم که موقعیت پنجره را مطابق را مقادیر پیش فرظ خود انتخاب کند. واحد مقدار این پارمترها pixel می باشد که کوچکترین واحد برای صفحه نمایش می باشد.
پارامتر هفتم و هشتم نیز طول و عرض پنجره را دریافت می کند. واحد این دو پارامتر نیز pixel می باشد.
چهار پارامتر آخر نیز مربوط به دستگیره هایی برای کنترل بیشتر پنجره هستند. پارامتر نهم از نوع HWND است و اگر پنجره شما پنجره فرزند (Child) باشد و برنامه شما دارای پنجره والد (Parent) باشد، باید دستگیره پنجره والد را در اینجا برای تابع ارسال کنید. در ویندوز، پنجره ها در صفحه نمایش بر اساس یک الگوی پنجره والد و فرزند چیده می-شوند. به عنوان مثال Button یک پنجره فرزند می باشد که محتوی دسترسی به پنجره والد خود می باشد. در مثال ما به علت نداشتن هیچ پنجره والدی این مقدار NULL می باشد. دهمین پارامتر دستگیره استاندارد منو از نوع HMENU را بخود می گیرد. در این مثال ما هیچ منویی برای پنجره نداریم، لذا مقدار آن را NULL قرار داده ایم. پارامتر یازدهم از نوع HINSTANCE بوده و دستگیره ای از نمونه اجرا شده برنامه را می گیرد. مقدار دریافتی از اولین پارامتر تابع ()WinMain را به این پارامتر ارسال کردیم. دوازدهمین و آخرین پارامتر از نوع استاندارد LPVOID بوده و برای ارسال اطلاعات ساخته شده اضافی به پنجره بکار می رود. ما فعلا به این پارامتر نیاز نداریم و مقدار آن را NULL در نظر گرفتیم.
نکته: مقدار NULL در Win32 کمی عجیب به نظر می رسد. چون این مقدار را می توان به انواع مختلفی از متغییرها نسبت داد. در زبان C، معادل آن ((void*)0) می شود. یعنی یک اشاره گر به مقدار صفر. ممکن است در بعضی از کامپایلرها، زمانیکه مقدار NULL را به انواع عددی نسبت می دهید، پیغام هشدار دریافت کنید. البته این باعث خطا نمی شود. در صورت تمایل می توانید به راحتی از مقدار صفر (0) استفاده کنید.
نکته: یکی از مشکلات شماره یک برنامه نویسان این است که توابعی که بکار می گیرند ممکن است کار نکند و یا دچار خطا شود. زیرا فراموش می کنند و یا اصلا نمی دانند که گروهی از توابع مقدار برمی گردانند. توابع برای آگاه کردن برنامه از نتیجه عملیاتشان مقداری خاص را برمی گردانند. اکثرا این مقادیر 0 و 1 می باشد که نشان دهنده موفقیت یا عدم موفقیت تابع می باشد. اما مقدار خاص دیگری به نام Troolean نیز وجود دارد. این نوع داده یک حالت اضافی (1-) را نیز در خود دارد. تابع ()GetMessageیکی از مثالهای جالب از نوع داده منطقی خاص مایکروسافت به نام Troolean (متضاد Boolean سنتی) است . ()GetMessage یک مقدار برگشتی از نوع BOOL را تعیین می کند. اما در مستندات سه نوع برگشتی وجود دارد. غیر صفر، صفر و مقدار 1- . برای روشن تر شدن مثال زیر را در نظر بگیرید:

• اگر تابع مقداری غیر از WM_QUIT را دریافت کند، مقدار برگشتی از تابع غیرصفر خواهد بود.
• اگر تابع مقدار WM_QUIT را دریافت کند، مقدار برگشتی صفر خواهد بود.
• اگر بعد از فراخوانی عمیات با خطا مواجه شود، مقدار برگشتی 1- خواهد بود.

هنگام فراخوانی توابع Win32، حتماً مقدار برگشتی آنها را کنترل کنید تا آگاه شوید که توابع کار خود را چگونه انجام داده اند. در کد زیر وجود دستگیره پنجره کنترل شده است.


if(hwnd == NULL)
{
MessageBox(NULL, (LPCWSTR)"Window Creation Failed!", (LPCWSTR)"Error!",
MB_ICONEXCLAMATION | MB_OK);
return 0;
}


بعد از چک کردن درستی دستگیره پنجره، نوبت به نمایش پنجره می رسد. توسط تابع ()ShowWindow و ارسال دستگیره به آن، ویندوز دستور نمایش پنجره را دریافت می کند. مقدار nCmdShow که آخرین پارامتر تابع ()WinMain می باشد نیز برای چگونگی نمایش پنجره به این تابع ارسال شده است. بلافاصله بعد دستور نمایش برای اطمینان و صحت نمایش درست پنجره، تابع ()UpdateWindow فراخوانی می شود.


ShowWindow(hwnd, nCmdShow);
UpdateWindow(hwnd);

استفاده از پارامتر nCmdShow اختیاری است. می توانید به جای این پارامتر مقدار استاندارد SW_SHOWNORMAL را به تابع ارسال کنید. مقدار پارامتر nCmdShow بیرون از برنامه و درست در زمان اجرا به تابع() WinMain ارسال می شود و می تواند مقادیر حالاتی مانند hidden, maximize, minimize و ... را داشته باشد. نمونه ای از تنظیم این پارامتر استفاده از آیکن های میانبر (Shortcut) و یا خط فرمان در ویندوز می باشد.

مرحله 3 – حلقه تکرار :
این مرحله سومین بخش از برنامه می باشد. این حالت خیلی جالب است، زیرا هر چیزی در برنامه از داخل این نقطه از کد ارسال می شود.


while(GetMessage(&Msg, NULL, 0, 0) > 0)
{
TranslateMessage(&Msg);
DispatchMessage(&Msg);
}
return Msg.wParam;


تابع ()GetMessage در هر زمان یک پیغام را از صف پیغام در اپلیکیشن برنامه دریافت می کند. هر زمان که کاربر ماوس را روی پنجره حرکت می دهد، روی آن کلیک می کند، دکمه های کیبرد را فشار می دهد و یا هر رویدادی که انجام دهد، یک پیغام توسط سیستم عامل تولید شده و به انتهای صف پیغام در برنامه شما اضافه می شود. بوسیله فراخوانی تابع ()GetMessage یک پیغام از اول صف پیغام خوانده شده و سپس آن پیغام از صف پاک می شود. این پیغام در آدرس متغییر Msg ذخیره شده و برای پردازش های بعدی در اختیار برنامه قرار می گیرد. اگر در صف هیچ پیغامی وجود نداشته باشد تابع مقدار Null و یا مقداری کمتر از 0 را بازمی گرداند و اصطلاحاً باعث بلوک شدن حلقه می شود.
تابع ()TranslateMessage پردازش های اضافی روی کیبرد را انجام می دهد. نظیر بدست آوردن و تولید پیغام های WM_CHAR زمانی که پیغام WM_KEYDOWN و همانند آن دریافت می شود. سرانجام تابع ()DispatchMessage پیغام مربوطه را به بیرون از پنجره ارسال می کند. محیط بیرون از پنجره می تواند یک پنجره اصلی و یا پنجره دیگر و یا یک کنترل باشد. در بعضی از مواقع هم در پشت صحنه توسط سیستم یا برنامه دیگری یک پنجره ساخته می شود. اما این چیزی نیست که خیلی نگران آن باشیم. زیرا همه ما با این روش پیغامها را به بیرون ارسال می کنیم، سیستم عامل هم با رجوع به پنجره درست، نگرانی را در مورد اشتباه برطرف می کند.

مرحله 4 – پروسیجر پنجره:
اگر حلقه تکرار را قلب یک برنامه در نظر بگیرید، آن وقت می توان گفت که پروسیجر پنجره مغز یک برنامه می باشد. تمام پیغامهایی را که پنجره ما دریافت می کند، مورد پردازش در این تابع قرار می گیرد:


LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
switch(msg)
{
case WM_CLOSE:
DestroyWindow(hwnd);
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
return DefWindowProc(hwnd, msg, wParam, lParam);
}
return 0;
}


پروسیجر پنجره به ازای هر پیغام یک مرتبه فراخوانی می شود. پارامتر hwnd یک دستگیره از پنجره شما را دریافت می کند. این اولین پارامتری است که همراه پیغام ارسال می شود. این پارامتر زمانی مهم می شود که شما از یک کلاس واحد دو و یا تعداد بیشتری پنجره در اختیار دارید، از این رو تمام این پنجره ها از یک پروسیجر پنجره استفاده می کنند. تفاوت مقدار hwnd به معنی استفاده پنجره های متفاوت از تابع می باشد و این حالت در تصمیمات برنامه ضروری است. بعنوان مثال زمانی که ما پیغام WM_CLOSE را دریافت می کنیم باید بدانیم که دستور ()DestroyWindow برای کدام پنجره بکار ببریم.
زمانی که ما ()DestroyWindow را فراخوانی می کنیم، یک پیغام WM_DESTROY توسط سیستم تولید شده و به برنامه ارسال می شود. این پیغام بیان می کند که پنجره مورد نظر تخریب شده. در صورتی که پنجره والد باشد و پنجره های فرزند نیز وجود داشته باشد، بعد از تخریب پنجره والد و قبل از پاک شدن منابع از حافظه، پنجره های فرزند نیز تخریب می شوند. ما تنها یک پنجره خالی در برنامه خود داریم و تمایل به بستن و خروج برنامه داریم، بنابراین تابع ()PostQuitMessage را فراخوانی کردیم. این تابع پیغام WM_QUIT را به حلقه پیغام ارسال می کند. ما هیچ وقت این پیغام را دریافت نمی کنیم، زیرا در این مورد باعث می شویم تابع ()GetMessage مقدار FALSE برگرداند. می توانید حلقه پیغامها را در زمانی که پردازش پیغامها متوقف می شود و نتیجه نهایی کدها بازگردانده می شود را نگاه کنید.
نکته: در بعضی از کامپایلرها ممکن است تبدیل نوع به آسانی و خودکار صورت نگیرد و در نتیجه از کامپایلر پیغامی مبتنی بر اینکه "کامپایلر نمی تواند نوع داده ای را به نوع دیگر تبدیل کند"، دریافت کنید. در این صورت اگر منطق داده-های شما درست باشد، می توانید از تبدیل نوع استاندارد C استفاده کنید. یعنی قبل از داده خود نوع تبدیلی را داخل یک جفت پرانتز قرار دهید. استثنائاً ما هم برای تبدیل ثابت های رشته ای به LPCWSTR ، قبل از آنها از تبدیل نوع (LPCWSTR) استفاده کردیم.

================================================== =====
از اینکه مدتی طول کشید و فاصله افتاد عذر می خواهم. چند وقتیه که سرم شلوغه.
در آینده لینک های منابع را نیز می گذارم.
در آینده در مورد یک مثال دیگه از ساخت پنجره توضیح خواهم داد.:لبخند:

seyed_hasan
شنبه 13 آذر 1389, 00:17 صبح
توسعه نویس جان عالی هستش اگه میشه ادامه بده.

cardano7
جمعه 03 دی 1389, 04:32 صبح
این دوست گلمون گویا دیگه on نمیشه. کسی هست که راهش را ادامه بده؟

mobtadi_1
دوشنبه 30 خرداد 1390, 18:03 عصر
سلام ...
در این تاپیک قصد ادامه مطالب رو دارم ، اگه هنوز دوستانی مشتاق هستند بگن تا شروع کنم ...

mobtadi_1
دوشنبه 30 خرداد 1390, 18:19 عصر
سلام ...

فقط

"LPCWSTR)"The title of my window)

باید این باشه

"LPCWSTR)L"The title of my window)

خیلی خوب بود ...

seyed_hasan
یک شنبه 26 تیر 1390, 11:56 صبح
خواهش میکنم یکی که خوب بلده ادامه بده.

simul8or
جمعه 07 مرداد 1390, 03:47 صبح
خواهش میکنم یکی که خوب بلده ادامه بده.
مشکل وقته. خیلی ها هستن که میتونن. یکی از بهترین ها Nima_NF (http://barnamenevis.org/member.php?46043-Nima_NF) هستند ، اگه ایشون ادامه بدن عالی میشه.
شایدم بنده نوشتم برای جبران کم کاری در این انجمن.(بعد از گذشت 4 سال از عضویت هنوز کاربر تازه وارد هستم و این یعنی فاجعه!!!)

Hossenbor
شنبه 16 مهر 1390, 16:44 عصر
دوست عزیز ناراحت نشو اون تقصیر ماست که کم تشکر میکنیم نه اینکه تشکر نکنیم تو دلمون تشکر می کنیم بازم به بزرگیه خودتون ببخشید

vasilopita
شنبه 16 مهر 1390, 23:09 عصر
اساتید تو رو خدا بیاد این بخش و ادامه بدید ...
آقا Nima_NF ، آقای حامد مصافی تو رو خدا بیاید ادامه بدید ...

jeson_park
شنبه 23 مهر 1390, 02:09 صبح
اساتید تو رو خدا بیاد این بخش و ادامه بدید ...
آقا Nima_NF ، آقای حامد مصافی تو رو خدا بیاید ادامه بدید ...
با سلام
من یکم توی msdn گشتم
قدم به قدم درس داده اما جالب نیست
توی هفته های آینده سعی می کنم شروع کنم به ادامه دادن این بخش

vasilopita
جمعه 13 آبان 1390, 13:06 عصر
دوست عزیز قرار بود ادامه بدی ها! عیبی نداره اگه هیچ کس این بخش رو ادامه نداد خودم میام msdn رو ترجمه می کنم می ذارم اینجا

mohamad.zakery
یک شنبه 25 تیر 1391, 02:18 صبح
دوستان اگر نیاز به آموزش win32 می بینند من هستم!!!

vasilopita
یک شنبه 25 تیر 1391, 20:20 عصر
دوستان اگر نیاز به آموزش win32 می بینند من هستم!!!
نیکی و پرسش ؟؟؟ من که تو این مدت با وجود تحریمات زیاد :چشمک:و عدم وجود دانش کافی ، خودم دست به کار شدم و خیلی چیزها یاد گرفتم. ولی واقعا این بخش نیاز به یه نفر داره که دوباره راه بیافته. متاسفانه با اینکه مدیران محترمی مثل آقای mehdi.mousavi و آقای salar ashghi , nima خیلی روی برنامه نویسی به این شیوه صحبت کرده بودن () و از قدرت این شیوه ی برنامه نویسی صحبت کرده بودن ولی متاسفانه می بینیم که این بخش هم چنان راکده.

Sarv 123
جمعه 27 مرداد 1391, 08:07 صبح
منم خودم رفتم تو msdn و کمی خوندم اما هنوز دو دل هستم که بین روش های مختلف کدوم رو شروع کنم به یادگیری! Win32, Qt و . . .
دوستان لطفا به آقای Nima_NF پیغام بدین ( خصوصی یا هرجور دیگه که میتونین ) که بیان و این بخش رو پیش ببرن. منتظریم!

vasilopita
چهارشنبه 01 شهریور 1391, 19:32 عصر
از اونجایی که این بخش بعد از گذشت مدت زمان زییییییییییییییادی همچنان راکد باقی مونده و از اونجایی که به نظر این بنده ی حقیر بهترین راه یادگیری این شیوه برنامه نویسی توضیح توابع api بصورت برنامه های کوچیکه پس با اجازه ی مدیر این بخش ،شما دوستان (و بزرگترا !) سعی می کنم از این به بعد با توضیح توابع api این بخش رو از این وضعیت دربیارم. امید است که شما دوستان عزیز تر از جانم دست یاری به سوی این بنده ی سراپا تقصیر دراز کرده و برای شکوفایی هرچه بیشتر این بخش یاری نمایید.

تابع بوق سیستم:
BOOL Beep(
DWORD dwFreq,
DWORD dwDuration
);
خوب همونطور که مشاهده می کنید این تابع دوتا پارامتر داره که هردو از نوع DWORD هستن. پارامتر اول میزان فرکانس صدای بوق رو تعیین می کنه که باید عددی توی رنج 37 تا 32767 باشه. پارامتر دوم مدت زمان پخش این بوق رو بر حسب میلی ثانیه تعیین می کنه. مقدار بازگشتی این تابع از نوع bool هستش. در صورتی که این تابع کارش رو با موفقیت انجام بده عددی غیر از صفر برمی گردونه.

تایع پیداکردن پنجره:
HWND FindWindow(
LPCTSTR lpClassName,
LPCTSTR lpWindowName
);


این تابع یک پنجره رو پیدا می کنه وهندلش رو برمیگردونه. پارامتر اول یک رشته بعنوان نام کلاس پنجره است و پارامتر دوم رشته ای بعنوان نام پنجره. نوع خروجی این تابع هم hwnd است که هندلی از نوع پنجره است و درواقع هدنل پنجره رو برمی گردونه.
پ.ن: برای پیدا کردن نام و کلاس یک پنجره می تونید از نرم افزار ++spy که همرا visual studio نصب میشه استفاده کنید. کافیه توی قسمت سرچ ویندوزتون ++spy رو سرچ کنید.
پس از اینکه برنامه رو اجرا کردید از قسمت search رو findwindow کلیک کنید. بعد اون علامت هدفی که روبروی finder tool هست رو بکشید و روی پنجره ی مورد نظرتون بذارید.:

http://picture.rupai.net/pic/232fe81225bc.png
خوب حالا می خوایم یه برنامه ی کوچولو بنویسیم:

HWND hwnd;
hwnd=FindWindow(NULL,L"برنامه نویسی با زبان C و ++C - Mozilla Firefox");
if(!hwnd)
cout<<"Can not find the window!\n";
EnableWindow(hwnd,0);
این برنامه پنجره ی مورد نظر رو قفل می کنه و در واقع به پیغام های ورودی از طرف موس و کیبورد به این پنجره توجهی نمی کنه.
توضیحش خیلی ساده است. با تابع findwindow هندل پنجره مورد نظر رو گرفتیم و اون رو به تابع enablewindow فرستادیم. تابع enablewindow در پارامتر اول هندل رو می گیره و در پارامتر دوم با مقدار 0 پنجره رو غیر فعال و عددی غیر از 0 اون رو فعال می کنه. بهمین سادگی.

فعلا باید برم جایی. بزودی برمیگردم.موفق باشید

zahrazahra67
چهارشنبه 29 آذر 1391, 11:26 صبح
آیا کسی میتونه این سوالو حل کنه و یا راهنمایی کنه؟
برنامه ای بنویسید که محتویات directory را نشان دهد .
اگر آرگومان نبود سپس برنامه محتویات دایرکتوری کنونی را نشان دهد برنامه باید قابلیت گرفتن آرگومان خط فرمان باشد.
f- برای نشان دادن فقط فایلهای موجود
d- برای نشان دادن فقط دایرکتوری های موجود
mydir [-d | -f][path]

houshmand
پنج شنبه 07 دی 1391, 22:18 عصر
فکر کنم این تایپیک می تواند بخشی از ادامه ایم نوشته باشد.
http://barnamenevis.org/showthread.php?72147-مقاله-آموزش-Win32-API-(-برنامه-نویسی-ویندوز-با-C-)

persian9
یک شنبه 01 اردیبهشت 1392, 09:19 صبح
سلام
نمیدانم تایپیکو درست انتخاب کردم یا نه ولی لطفا جوابمو بدین
من تو دانشگاه c++ رو خوندم البته فقط در حد کنسول اپلیکیشن حالا میخوام ببینم از نظر اونایی که تو کارن باید c++ رو ادامه بدم مثل win32 & mfc یا برم سراغ c#
البته هدفم نوشتن برنامه برای فروش هست مثل حسابداری و ....
یادگیری کدام آسانتر و کاربردی تر هست؟
:متفکر:

persian9
دوشنبه 02 اردیبهشت 1392, 17:26 عصر
دوستان یه توجهی هم به سوال ما بکنید لطفا کسایی که تو بازار کار هستند کمک کنند

amin_iman82
پنج شنبه 23 خرداد 1392, 11:10 صبح
سلام من یه سمپل ساده نیاز دارم که کارهای ساده مثل ذخیره و حذف و نمایش اطلاعات فایل XML رو انجام بده ، کسی از دوستان داره ؟

کامبیز اسدزاده
پنج شنبه 23 خرداد 1392, 22:52 عصر
Win32 یکی از بخش های جالب در C++ هست ولی حیف انحصاری شده.

rm classic
یک شنبه 28 دی 1393, 23:27 عصر
سلام دوستان
با توجه به این که این تاپیک از 5-6 سال پیش غیر فعال شده بود و بنده واقعا به این اموزش نیاز داشتم، اگر کسی مرحمت نمی کنه این رو ادامه بده بنده تا جایی که میتونم این تاپیک رو ادامه بدم.

myumyu
یک شنبه 03 اسفند 1393, 10:46 صبح
دوستان خواهشا این مبحث رو ادامه بدید ...
ما تازه کارا منتظریم ....

rm classic
چهارشنبه 06 اسفند 1393, 21:04 عصر
سلام به همه دوستان
از امروز تصمیم گرفتم این تاپیک راکد رو یکم حرکت بدم اگه میشه یه کمکی هم بکنید که تاپیک رو به مراتب بهتر کنیم.

همونطور که توسعه نویس جان توضیح دادن هر پنجره دارای یه پروسیجره که تمامی کارهایی که برنامه انجام میده توی اون نوشته شده هست
برنامه با گرفتن هر پیام از ویندوز سراغ پروسیجر میره تا دستورات مربوط به پیام رو بررسی و اجرا کنه

پیامی که خیلی مورد استفاده هست WM_PAINT هستش که با هر بار نادرست شدن "Client Rect" تو صف پیامها قرار داده میشه.
سوال اینجاست که چه موقع محیط پنجره نادرست میشه؟ در ابتدای برنامه محیط پنجره نادرسته چون برنامه هنوز هیچ چیز روی صفحه ننوشته پس این پیام توی صف پیامها قرار میگیره و اطلاعات رو چاپ میکنه. توی اکثر برنامه ها تغییر اندازه پنجره باعث نادرست شدنش میشه که بخاطر دادن دو فلگ CS_HREDRAW و CS_VREDRAW به فیلد style هست. WM_PAINT با minimize و دوباره maximize شدن هم تو صف پیامها قرار میگیره. حتی با پنهان شدن قسمتی از پنجره توسط پنجره های دیگه اون قسمت از client rect نادرست میشه.

پیام WM_PAINT اغلب با این تابع شروع میشه:


hdc = BeginPaint(hwnd, &ps);



و با این تابع تموم میشه:



EndPaint(hwnd, &ps);



توی هر دو تا تابع، اولین پارامتر دستگیره پنجره هست. پارامتر دوم مربوط به استراکچر PAINTSTRUCT میشه که حاوی اطلاعاتیه که پروسیجر برای چاپ به اونا نیاز داره.
طی فراخوانی تابع BeginPaint، پنجره تمام client area خودشو پاک میکنه و به رنگی که تو hbrbackground تعریف شده رنگ میکنه. تابع BeginPaint مقدار برگشتی از نوع (HDC (Handle to a Device Context داره. HDC برای ارتباط با ویدیو کارت به کار میره که ما برای نشون دادن نوشته هامون بهش نیاز داریم.

rm classic
جمعه 07 فروردین 1394, 21:31 عصر
خب حالا ما پیام WM_PAINT رو برای برنامه معرفی کردیم و ارتباطمون رو با کارت گرافیک برای نوشتن روی صفحه برقرار کردیم.
و در آخر ما به یه قالب میرسیم که به این صورته:



case WM_PAINT:
(hwnd, &ps)hdc=BeginPaint
[Painting Commands]
EndPaint(hwnd, &ps);



شما با دادن دستور EndPaint محیطتون رو از حالت نادرست به درست برمیگردونید. پس با تعریف کردن WM_PAINT توابع BeginPaint و EndPaint حتما باید معرفی بشن حتی اگه توشون هیچ دستوری نباشه. در صورتی که این دو تابع نوشته نشن، محیط پنجره نادرست میمونه و به پروسیجر پیش فرض ویندوز بر میگرده. پروسیجر ویندوز محیط برنامه رو نادرست تشخیص میده. درنتیجه یه پیام WM_PAINT تو صف پیامها میذاره و تو هر ثانیه هزاران بار محیط نقاشی میشه و این چرخه تا ابد انجام میشه.


هر استراکچر PAINTSTRUCT دارای این فیلد هاست:



typedef struct tagPAINTSTRUCT
{
HDC hdc;
BOOL fErase;
RECT rcPaint;
BOOL fRestore;
BOOL fIncUpdate;
BYTE rgbReserved[32];
}



ویندوز با فراخوانی تابع BeginPaint این فیلد هارو پر میکنه ولی برنامه شما تنها از سه تاشون استفاده میکنه و بقیه رو ویندوز استفاده میکنه.


فیلد اول مربوط به دستگیره برنامه شما به Device Context هست که توسط تابع BeginPaint هم بازگردونده میشه.


فیلد بعدی مربوط به پاک کردن محیط برنامه اس که تو اکثر مواقع، ارزش FALSE به خودش میگیره که به این معناست که ویندوز محیط نادرست برنامه رو نقاشی کرده (که تو تابع BeginPaint این اتفاق میفته).


فیلد rcPaint یه استراکچر از نوع RECT هست. RECT خودش چهار تا فیلد داره که چپ(left)، بالا(up)، راست(right) و پایین(down) اونو تشکیل میدن. این استراکچر قسمت نادرست محیط برنامه رو نشون میده که برنامه اونجا رو دوباره نقاشی کنه.
129770
اگر میخواین که محیط برنامتون رو بصورت دستی نادرست کنید از این تابع کمک بگیرید:


(hwnd, NULL, TRUE)InvalidateRect

همونطور که با استفاده از BeginPaint، HDC برنامه رو پر میکردیم و برنامه رو برای نقاشی آماده می کردیم و با EndPaint اونو کامل میکردیم. میتونیم از دوتابع دیگه استفاده کنیم که شباهت های زیادی به این دوتا تابع دارن:

hdc = GetDC(hwnd)
[painting commands]
ReleaseDC(hwnd, hdc)

شاید یه سوال براتون پیش اومده که نمیشه بیرون از پیام WM_PAINT و تو پیام های دیگه محیط رو نقاشی کنیم؟
با دو تابع BeginPaint, EndPaint نه، ولی با توابع GetDC ,ReleaseDC میشه چون دقیقا این دو تابع برای همین کار ساخته شدن و ما میتونیم تو پیام هایی مثل WM_KEYDOWN, WM_MOUSEMOVE, ... از اونها استفاده کنیم.
این دوتا تابع هم مثل BeginPaint , EndPaint باید با هم فراخونده شن و توی یه پیام هم باشن(یکی نباید تو یه پیام و اون یکی تو پیام دیگه ای باشه).
اما برخلاف دو تابع قبلی این تابع ها بعد از فراخونده شدن، محیط نادرست پنجره رو درست نمیکنن و باید به صورت دستی میتونیم اون رو درست کنیم.
برای درست کردن محیط پنجره برای جلوگیری از نقاشی دوباره هم میتونیم از این تابع استفاده کنیم:

ValidateRect(hwnd, NULL)

sputnik
سه شنبه 21 آذر 1396, 10:25 صبح
داداش اول اول وآخر توی بازارکار رو جاوا میزنه بخصوص java EE
بعدش هم سی شارپ و اس پی دات نت
کلا نون توی طراحی وب و طراحی ای پی ای هاست
موفق باشی