На главную

On-line справка по Win32 API

Написать письмо
БЕСПЛАТНАЯ ежедневная online лотерея! Выигрывай каждый день БЕСПЛАТНО!
Список всех статей A-B-C-D-E-F-G-H-I-J-K-L-M-N-O-P-Q-R-S-T-U-V-W-X-Y-Z | Скачать Вниз

Using a Multithreaded Multiple Document Interface Application



The example in this topic shows how to use multiple threads in a multiple document interface (MDI) process. The process has a single main window, but can have any number of child windows. The primary thread of the process performs initialization and also handles messages to all windows through the application-defined MainWndProc and ChildWndProc functions.

Each time a child window is created, a new thread is also created. In the example, the new thread continually checks a global variable to see if it is time to terminate.
The ThreadFunc function is specified in the CreateThread function as the code for the new thread to execute. The handle of the child window associated with the thread is passed as a parameter to ThreadFunc. The child window's handle is also a parameter to ChildWndProc when a message is dispatched to the child window. A handle is necessary for any communication between a child window and its corresponding thread. Both ThreadFunc and ChildWndProc use the window handle in the SetWindowLong function to access the value that is reserved for application use in each window structure. In the example, the value is a termination flag. When ChildWndProc gets the WM_CLOSE message, it sets the flag; ThreadFunc checks the flag each time through its loop.

The example demonstrates how to use normal priority for the primary thread and below-normal priority for the other threads. Because the primary thread handles all messages for both the main window and the child windows, its higher relative priority ensures responsiveness to user input.
When the user terminates the process by closing the main window, the primary thread sets the global parameter to indicate that worker threads should terminate. The primary thread waits for each child thread to terminate before proceeding. This is necessary only if you want the threads to clean up, save changes to a file, or detach from DLLs before closing. If the primary thread does not wait, no other threads will be able to execute, because they have a lower priority.

#include
#include
#include

#define MM_NEWWIN 8001
typedef struct _PTHREADLIST
{
HANDLE hThread;
LPVOID lpvNext;
} THREADLIST, *PTHREADLIST;

HANDLE hModule; // handle to .EXE file for this process
HWND hwndMain = NULL; // handle to main window
BOOL fKillAll = FALSE; // sets TRUE to terminate all threads
PTHREADLIST pHead = NULL; // head of thread information linked list

BOOL InitializeApp(VOID);

LRESULT CALLBACK MainWndProc(HWND, UINT, WPARAM, LPARAM);
LRESULT CALLBACK ChildWndProc(HWND, UINT, WPARAM, LPARAM);
DWORD ThreadFunc(HWND);
VOID AddThreadToList(HANDLE);
VOID ErrorExit(LPSTR);

// Primary thread: Initialize the application and dispatch messages.

int WINAPI WinMain( HINSTANCE hInst,
HINSTANCE hPrevInst,
LPSTR lpszCmdLn,
int nShowCmd)
{
MSG msg;
hModule = GetModuleHandle(NULL);
if (! InitializeApp())
ErrorExit("InitializeApp failure!");

while (GetMessage(&msg, NULL, 0, 0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return 1;
UNREFERENCED_PARAMETER(hInst);
UNREFERENCED_PARAMETER(hPrevInst);
UNREFERENCED_PARAMETER(lpszCmdLn);
UNREFERENCED_PARAMETER(nShowCmd);
}

// Register window classes and create the main window.

BOOL InitializeApp(VOID)
{
HMENU hmenuMain, hmenuPopup;
WNDCLASS wc;

// Register a window class for the main window.


wc.style = CS_OWNDC;
wc.lpfnWndProc = MainWndProc;
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hInstance = hModule;
wc.hIcon = LoadIcon(NULL,IDI_APPLICATION);
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.hbrBackground = (HBRUSH)(COLOR_BACKGROUND+1);
wc.lpszMenuName = NULL;
wc.lpszClassName = "MainWindowClass";
if (! RegisterClass(&wc))
return FALSE;


// Register a window class for child windows.

wc.lpfnWndProc = ChildWndProc;
wc.lpszClassName = "ThreadWindowClass";
if (! RegisterClass(&wc))
return FALSE;

// Create a menu for the main window.

hmenuMain = CreateMenu();
hmenuPopup = CreateMenu();
if (!AppendMenu(hmenuPopup, MF_STRING, MM_NEWWIN, "&New Window"))
return FALSE;
if (!AppendMenu(hmenuMain, MF_POPUP, (UINT)hmenuPopup, "&Threads"))
return FALSE;


// Create the main window.

hwndMain = CreateWindow("MainWindowClass", "Primary Window",
WS_OVERLAPPED | WS_CAPTION | WS_BORDER | WS_THICKFRAME |
WS_MAXIMIZEBOX | WS_MINIMIZEBOX | WS_CLIPCHILDREN |
WS_VISIBLE | WS_SYSMENU, CW_USEDEFAULT, CW_USEDEFAULT,
CW_USEDEFAULT, CW_USEDEFAULT, NULL, hmenuMain, hModule,
NULL);
if (hwndMain == NULL)
return FALSE;

// Set the initial focus.

SetFocus(hwndMain);
return TRUE;

}

// Main window procedure: Handle messages for the main window.

LRESULT CALLBACK MainWndProc(HWND hwnd, UINT uiMessage,
WPARAM wParam, LPARAM lParam)
{
static HWND hwndClient;
static DWORD dwCount = 1;
CLIENTCREATESTRUCT ccsClientCreate;
HWND hwndChildWnd;
DWORD IDThread;
PTHREADLIST pNode;

switch (uiMessage)
{
// Create a client window to receive child window messages.

case WM_CREATE:
ccsClientCreate.hWindowMenu = NULL;

ccsClientCreate.idFirstChild = 1;
hwndClient = CreateWindow("MDICLIENT", NULL,
WS_CHILD | WS_CLIPCHILDREN | WS_VISIBLE, 0, 0, 0, 0,
hwnd, NULL, hModule, (LPVOID)&ccsClientCreate);
return 0L;

// Close the main window. First set fKillAll to TRUE to
// terminate all threads. Then wait for the threads to exit
// before passing a close message to a default handler. If you
// don't wait for threads to terminate, the process terminates

// with no chance for thread cleanup.

case WM_CLOSE:
fKillAll = TRUE;
pNode = pHead;
while (pNode)
{
DWORD dwRes;
SetThreadPriority(pNode->hThread,
THREAD_PRIORITY_HIGHEST);
dwRes = WaitForSingleObject(pNode->hThread,
INFINITE);
pNode = (PTHREADLIST) pNode->lpvNext;
}
return DefFrameProc(hwnd, hwndClient, uiMessage,

wParam, lParam);

// Terminate the process.

case WM_DESTROY:
PostQuitMessage(0);
return 0L;

// Handle the menu commands.

case WM_COMMAND:
switch (LOWORD(wParam))
{
// Create a child window and start a thread for it.
case MM_NEWWIN:
HANDLE hThrd;
MDICREATESTRUCT mdicCreate;
TCHAR tchTitleBarText[32];
LONG lPrev;


sprintf(tchTitleBarText, "Thread Window %d", dwCount);
mdicCreate.szClass = "ThreadWindowClass";
mdicCreate.szTitle = tchTitleBarText;
mdicCreate.hOwner = hModule;
mdicCreate.x = mdicCreate.y =
mdicCreate.cx = mdicCreate.cy = CW_USEDEFAULT;
mdicCreate.style = mdicCreate.lParam = 0L;

// Send a "create child window" message to the
// client window.


hwndChildWnd = (HWND) SendMessage(hwndClient,
WM_MDICREATE, 0L, (LONG)&mdicCreate);
if (hwndChildWnd == NULL)
ErrorExit("Failed in Creating Thread Window!");

// Window structure used to pass a quit message to
// the thread.

lPrev = SetWindowLong(hwndChildWnd, GWL_USERDATA, 0);

// Create a suspended thread; alter its priority before

// calling ResumeThread.

hThrd = CreateThread(NULL, // no security attributes
0, // use default stack size
(LPTHREAD_START_ROUTINE) ThreadFunc,
(LPVOID)hwndChildWnd, // param to thread func
CREATE_SUSPENDED, // creation flag
&IDThread); // thread identifier
if (hThrd == NULL)

ErrorExit("CreateThread Failed!");
AddThreadToList(hThrd);
dwCount++;

// Set the priority lower than the primary (input)
// thread, so the process is responsive to user
// input. Then resume the thread.

if (!SetThreadPriority(hThrd,
THREAD_PRIORITY_BELOW_NORMAL))
ErrorExit("SetThreadPriority failed!");
if ((ResumeThread(hThrd)) == -1)

ErrorExit("ResumeThread failed!");
return 0L;

default:
return DefFrameProc(hwnd, hwndClient, uiMessage,
wParam, lParam);
}

default:
return DefFrameProc(hwnd, hwndClient, uiMessage,
wParam, lParam);
}
}

// Process messages for the child windows.

LRESULT CALLBACK ChildWndProc(HWND hwnd, UINT uiMessage, WPARAM
wParam, LPARAM lParam)

{
LONG lPrevLong;
switch (uiMessage)
{
// Use a window structure to pass "close" message to thread.

case WM_CLOSE:
lPrevLong = SetWindowLong(hwnd, GWL_USERDATA, 1);
return DefMDIChildProc(hwnd, uiMessage, wParam, lParam);

case WM_DESTROY:
return 0L;

default:
return DefMDIChildProc(hwnd, uiMessage, wParam, lParam);
}
}

// Each child window has a thread that can be used to perform tasks

// associated with that window--for example, drawing its contents.

DWORD ThreadFunc(HWND hwnd)
{
LONG lKillMe = 0L;
while (TRUE)
{
lKillMe = GetWindowLong(hwnd, GWL_USERDATA);
if (fKillAll || lKillMe) break;

// Perform tasks.

}

// Perform actions needed before thread termination.

return 0;
}

VOID AddThreadToList(HANDLE hThread)
{
PTHREADLIST pNode;
pNode = (PTHREADLIST) LocalAlloc(LPTR, sizeof(PTHREADLIST));

if (pNode == NULL)
ErrorExit("malloc Failed!");
pNode->hThread = hThread;
pNode->lpvNext = (LPVOID) pHead;
pHead = pNode;
}

VOID ErrorExit(LPSTR lpszMessage)
{
MessageBox(hwndMain, lpszMessage, "Error", MB_OK);
ExitProcess(0);
}



Пригласи друзей и счет твоего мобильника всегда будет положительным!
Предыдущая статья
 
Сайт Народ.Ру Интернет
Следующая статья
Пригласи друзей и счет твоего мобильника всегда будет положительным!

Интерфейс Использования Многочисленного Приложения Документа Multithreaded



Пример в этой теме показывает как, чтобы использовать многочисленную резьбу на многочисленном интерфейсе документа процесса (MDI). Процесс имеет единственное основное окно, но может иметь любой номер окна ребенка. Первичная резьба процесса выполняет инициализацию и также оперирует сообщения во все окно через определенное приложение MainWndProc и функции ChildWndProc.

Всякий раз, когда окно ребенка создано, новая резьба также создана. В примере, новая резьба непрерывно проверяет глобальную переменную, чтобы видеть если пора завершаться.
Функция ThreadFunc определена в функции CreateThread как код для новой резьбы, чтобы выполняться. Ручка окна ребенка связанного резьбой пройдена как параметр на ThreadFunc. Ручка окна ребенка является также параметром на ChildWndProc когда сообщение послано в окно ребенка. Ручка необходима для любой связи между окном ребенка и соответствующей резьбы. Как ThreadFunc так и ChildWndProc использует ручку окна в функции SetWindowLong, чтобы иметь доступ к величине, которая зарезервирована для прикладного использования в каждой структуре окна. В примере, величина является флагом завершения. Когда ChildWndProc получает сообщение WM_CLOSE, это устанавливает флаг; ThreadFunc ПРОВЕРЯЕТ флаг всякий раз, когда через свой цикл.

Пример демонстрирует как, чтобы использовать нормальный приоритет для первичной резьбы и ниже-нормальный приоритет для другой резьбы. Поскольку первичная резьба оперирует все сообщения как для основного окна так и окно ребенка, более высокого относительного приоритета гарантирует ответную реакцию на ввод пользователя.
Когда потребитель завершает процесс закрывая основное окно, первичная резьба устанавливает глобальный параметр, чтобы указывать, что рабочий заправляет должно завершаться. Первичная резьба ждет каждую резьбу ребенка, чтобы завершаться перед действием. Необходимо только если Вы хотите, чтобы резьба наводила порядок, сохраняешь изменения в файл или отделяешься из DLLs перед закрытием. Если первичная резьба не ожидается, никакая другая резьба не будет способной выполнить, поскольку у них есть более низкий приоритет.

#include #include #include

#define MM_NEWWIN 8001 typedef struct _PTHREADLIST
{
ПРООПЕРИРУЙТЕ hThread;
LPVOID lpvNext;
} THREADLIST, *PTHREADLIST;

ПРООПЕРИРУЙТЕ hModule; // ручка в файл .EXE для этого процесса HWND hwndMain = НЕДЕЙСТВИТЕЛЬНЫЙ; // ручка в основное окно BOOL fKillAll = ЛОЖЬ; // ИСТИНА комплектов, чтобы завершать всю резьбу PTHREADLIST pHead = НЕДЕЙСТВИТЕЛЬНЫЙ; // головка информации резьбы связавшей список

BOOL InitializeApp(ПУСТОТА);

LRESULT CALLBACK MainWndProc(HWND, UINT, WPARAM, LPARAM);
LRESULT CALLBACK ChildWndProc(HWND, UINT, WPARAM, LPARAM);
DWORD ThreadFunc(HWND);
НЕДЕЙСТВИТЕЛЬНАЯ AddThreadToList(РУЧКА);
АННУЛИРУЙТЕ ErrorExit(LPSTR);

// Первичная резьба: Инициализируйте приложение и посылайте сообщения.

int WINAPI WinMain( HINSTANCE hInst, HINSTANCE hPrevInst, LPSTR lpszCmdLn, int nShowCmd)
{
msg MSG;
hModule = GetModuleHandle(НЕДЕЙСТВИТЕЛЬНЫЙ);
если (! InitializeApp()) ErrorExit(НЕУДАЧА "InitializeApp!");

пока (GetMessage(&msg, НЕДЕЙСТВИТЕЛЬНЫЙ, 0, 0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
возврат 1;
UNREFERENCED_PARAMETER(hInst);
UNREFERENCED_PARAMETER(hPrevInst);
UNREFERENCED_PARAMETER(lpszCmdLn);
UNREFERENCED_PARAMETER(nShowCmd);
}

// Зарегистрируйте классы окна и создавайте основное окно.

BOOL InitializeApp(ПУСТОТА)
{
HMENU hmenuMain, hmenuPopup;
wc WNDCLASS;

// Зарегистрируйте класс окна для основного окна.


wc.style = CS_OWNDC;
wc.lpfnWndProc = MainWndProc;
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hInstance = hModule;
wc.hIcon = LoadIcon(НЕДЕЙСТВИТЕЛЬНЫЙ,IDI_APPLICATION);
wc.hCursor = LoadCursor(НЕДЕЙСТВИТЕЛЬНЫЙ, IDC_ARROW);
wc.hbrBackground = (HBRUSH)(COLOR_BACKGROUND+1);
wc.lpszMenuName = НЕДЕЙСТВИТЕЛЬНЫЙ;
wc.lpszClassName = "MainWindowClass";
если (! RegisterClass(&wc)) ОБРАТНАЯ ЛОЖЬ;


// Зарегистрируйте класс окна для окна ребенка.

wc.lpfnWndProc = ChildWndProc;
wc.lpszClassName = "ThreadWindowClass";
если (! RegisterClass(&wc)) ОБРАТНАЯ ЛОЖЬ;

// Создайте меню для основного окна.

hmenuMain = CreateMenu();
hmenuPopup = CreateMenu();
если (!AppendMenu(hmenuPopup, MF_STRING, MM_NEWWIN, "&НОВОЕ Окно")) обратная ЛОЖЬ;
если (!AppendMenu(hmenuMain, MF_POPUP, (UINT)hmenuPopup, "&РЕЗЬБА")) обратная ЛОЖЬ;


// Создайте основное окно.

hwndMain = CreateWindow("MainWindowClass", "Первичное Окно", WS_OVERLAPPED | WS_CAPTION | WS_BORDER | WS_THICKFRAME | WS_MAXIMIZEBOX | WS_MINIMIZEBOX | WS_CLIPCHILDREN | WS_VISIBLE | WS_SYSMENU, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, НЕДЕЙСТВИТЕЛЬНЫЙ, hmenuMain, hModule, НЕДЕЙСТВИТЕЛЬНЫЙ);
если (hwndMain == НЕДЕЙСТВИТЕЛЬНЫЙ) обратная ЛОЖЬ;

// Установленный начальный фокус.

SetFocus(hwndMain);
возвращайтесь ВЕРНО;

}

// Процедура окна Основы: сообщения Ручки для основного окна.

LRESULT CALLBACK MainWndProc(HWND hwnd, uiMessage UINT, WPARAM wParam, LPARAM lParam)
{
статический HWND hwndClient;
статический DWORD dwCount = 1;
CLIENTCREATESTRUCT ccsClientCreate;
HWND hwndChildWnd;
DWORD IDThread;
PTHREADLIST pNode;

ключ (uiMessage)
{
// Создайте окно клиента, чтобы получать сообщения окна ребенка.

случай WM_CREATE: ccsClientCreate.hWindowMenu = НЕДЕЙСТВИТЕЛЬНЫЙ;

ccsClientCreate.idFirstChild = 1;
hwndClient = CreateWindow("MDICLIENT", НЕДЕЙСТВИТЕЛЬНЫЙ, WS_CHILD | WS_CLIPCHILDREN | WS_VISIBLE, 0, 0, 0, 0, hwnd, НЕДЕЙСТВИТЕЛЬНЫЙ, hModule, (LPVOID)&ccsClientCreate);
возвращайте 0L;

// Закрытый основное окно. Установка Первого fKillAll в ИСТИНУ, чтобы // завершать всю резьбу. Затем подождите резьбу, чтобы выходить из // перед прохождением закрытого сообщения по умолчанию вручителю. Если Вы // не ждать резьбу, чтобы завершаться, процесс завершается

// без шанса для очистки резьбы.

случай WM_CLOSE: fKillAll = ИСТИНА;
pNode = pHead;
пока (pNode)
{
DWORD dwRes;
SetThreadPriority(pNode->hThread, THREAD_PRIORITY_HIGHEST);
dwRes = WaitForSingleObject(pNode->hThread, БЕСКОНЕЧНЫЙ);
pNode = (PTHREADLIST) pNode->lpvNext;
}
возврат DefFrameProc(hwnd, hwndClient, uiMessage,

wParam, lParam);

// Завершите процесс.

случай WM_DESTROY: PostQuitMessage(0);
возвращайте 0L;

// Ручка команды меню.

случай WM_COMMAND: ключ (LOWORD(wParam))
{
// Создайте окно ребенка и начинайте с резьбы для этого.
случай MM_NEWWIN: РУЧКА hThrd;
MDICREATESTRUCT mdicCreate;
TCHAR tchTitleBarText[32];
ДОЛГО (ДЛИНОЙ) lPrev;


sprintf(tchTitleBarText, "Окно Резьбы %d", dwCount);
mdicCreate.szClass = "ThreadWindowClass";
mdicCreate.szTitle = tchTitleBarText;
mdicCreate.hOwner = hModule;
mdicCreate.x = mdicCreate.y = mdicCreate.cx = mdicCreate.cy = CW_USEDEFAULT;
mdicCreate.style = mdicCreate.lParam = 0L;

// Пошлите сообщение "создавать окно ребенка" в // окно клиента.


hwndChildWnd = (HWND) SendMessage(hwndClient, WM_MDICREATE, 0L, (LONG)&mdicCreate);
если (hwndChildWnd == НЕДЕЙСТВИТЕЛЬНЫЙ) ErrorExit("Failed на Создании Окна Резьбы!");

// Структура Окна использованная, чтобы передавать сообщение выхода на // резьба.

lPrev = SetWindowLong(hwndChildWnd, GWL_USERDATA, 0);

// Создайте приостановленную резьбу; измените свой приоритет прежде

// разговор ResumeThread.

hThrd = CreateThread(НЕДЕЙСТВИТЕЛЬНАЯ, // никакая безопасность не приписывает 0, // размер по умолчанию стека использования (LPTHREAD_START_ROUTINE) ThreadFunc, (LPVOID)hwndChildWnd, // param, чтобы заправлять func CREATE_SUSPENDED, // флаг создания &IDThread); // идентификатор резьбы если (hThrd == НЕДЕЙСТВИТЕЛЬНЫЙ)

ErrorExit("CreateThread ПОТЕРПЕВШИЙ неудачу!");
AddThreadToList(hThrd);
dwCount++;

// Установленный приоритет ниже, чем первичный (ввод) // резьба, так что процесс отзывчивый пользователю // ввод. Затем продолжите резьбу.

если (!SetThreadPriority(hThrd, THREAD_PRIORITY_BELOW_NORMAL)) ErrorExit("SetThreadPriority ПОТЕРПЕВШИЙ неудачу!");
если ((ResumeThread(hThrd)) == -1)

ErrorExit("ResumeThread ПОТЕРПЕВШИЙ неудачу!");
возвращайте 0L;

умолчание:
возвращайте DefFrameProc(hwnd, hwndClient, uiMessage, wParam, lParam);
}

умолчание:
возвращайте DefFrameProc(hwnd, hwndClient, uiMessage, wParam, lParam);
}
}

// Обработайте сообщения для окна ребенка.

LRESULT CALLBACK ChildWndProc(HWND hwnd, uiMessage UINT, WPARAM wParam, LPARAM lParam)

{
ДОЛГО (ДЛИНОЙ) lPrevLong;
ключ (uiMessage)
{
// Использование структура окна, чтобы передавать сообщение "закрытия", чтобы заправляться.

случай WM_CLOSE:
lPrevLong = SetWindowLong(hwnd, GWL_USERDATA, 1);
возвращайте DefMDIChildProc(hwnd, uiMessage, wParam, lParam);

случай WM_DESTROY: возврат 0L;

умолчание:
возвращайте DefMDIChildProc(hwnd, uiMessage, wParam, lParam);
}
}

// Каждое окно ребенка имеет резьбу, которая может быть использована, чтобы выполнять задачи

// связанное этим окном-например, рисуя содержание.

DWORD ThreadFunc(HWND hwnd)
{
ДОЛГО (ДЛИНОЙ) lKillMe = 0L;
пока (ИСТИНА)
{
lKillMe = GetWindowLong(hwnd, GWL_USERDATA);
если прерывание (fKillAll || lKillMe);

// Выполните задачи.

}

// Выполните действия, которым нужно перед завершением резьбы.

возврат 0;
}

ПУСТОТА AddThreadToList(РУЧКА hThread)
{
PTHREADLIST pNode;
pNode = (PTHREADLIST) LocalAlloc(LPTR, sizeof(PTHREADLIST));

если (pNode == НЕДЕЙСТВИТЕЛЬНЫЙ) ErrorExit("malloc Терпел бы неудачу!");
pNode->hThread = hThread;
pNode->lpvNext = (LPVOID) pHead;
pHead = pNode;
}

ПУСТОТА ErrorExit(lpszMessage LPSTR)
{
MessageBox(hwndMain, lpszMessage, "ОШИБКА", MB_OK);
ExitProcess(0);
}



Вверх Version 1.3, Oct 26 2010 © 2007, 2010, mrhx Вверх
 mrhx software  Русский перевод OpenGL  Русский перевод Win32 API
 
Используются технологии uCoz