www.pudn.com > CeChat.rar > CeChat.cpp
//====================================================================== // CeChat - A Windows CE communication demo // // Written for the book Programming Windows CE // Copyright (C) 2003 Douglas Boling //====================================================================== #include// For all that Windows stuff #include // Command bar includes #include "CeChat.h" // Program-specific stuff #if defined(WIN32_PLATFORM_PSPC) #include // Add Pocket PC includes. #pragma comment( lib, "aygshell" ) // Link Pocket PC lib for menu bar. #endif //---------------------------------------------------------------------- // Global data // const TCHAR szAppName[] = TEXT ("CeChat"); HINSTANCE hInst; // Program instance handle. BOOL fContinue = TRUE; HANDLE hComPort = INVALID_HANDLE_VALUE; int nSpeed = CBR_19200; int nLastDev = -1; #if defined(WIN32_PLATFORM_PSPC) && (_WIN32_WCE >= 300) SHACTIVATEINFO sai; #endif HANDLE g_hSendEvent = INVALID_HANDLE_VALUE; HANDLE hReadThread = INVALID_HANDLE_VALUE; // Message dispatch table for MainWindowProc const struct decodeUINT MainMessages[] = { WM_CREATE, DoCreateMain, WM_SIZE, DoSizeMain, WM_COMMAND, DoCommandMain, WM_SETTINGCHANGE, DoPocketPCShell, WM_ACTIVATE, DoPocketPCShell, WM_SETFOCUS, DoSetFocusMain, WM_DESTROY, DoDestroyMain, }; // Command Message dispatch for MainWindowProc const struct decodeCMD MainCommandItems[] = { IDC_COMPORT, DoMainCommandComPort, ID_SENDBTN, DoMainCommandSendText, IDM_EXIT, DoMainCommandExit, IDM_ABOUT, DoMainCommandAbout, }; //====================================================================== // Program entry point // int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance, LPWSTR lpCmdLine, int nCmdShow) { HWND hwndMain; HACCEL hAccel; MSG msg; int rc = 0; // Initialize this instance. hwndMain = InitInstance (hInstance, lpCmdLine, nCmdShow); if (hwndMain == 0) return 0x10; // Load accelerator table. hAccel = LoadAccelerators (hInst, MAKEINTRESOURCE (ID_ACCEL)); // Application message loop while (GetMessage (&msg, NULL, 0, 0)) { if (!TranslateAccelerator (hwndMain, hAccel, &msg)) { TranslateMessage (&msg); DispatchMessage (&msg); } } // Instance cleanup return TermInstance (hInstance, msg.wParam); } //---------------------------------------------------------------------- // InitInstance - Instance initialization // HWND InitInstance (HINSTANCE hInstance, LPWSTR lpCmdLine, int nCmdShow){ HWND hWnd; HANDLE hThread; WNDCLASS wc; INITCOMMONCONTROLSEX icex; // Save program instance handle in global variable. hInst = hInstance; #if defined(WIN32_PLATFORM_PSPC) // If Pocket PC, allow only one instance of the application. HWND hWnd = FindWindow (szAppName, NULL); if (hWnd) { SetForegroundWindow ((HWND)(((DWORD)hWnd) | 0x01)); return 0; } #endif // Register application main window class. wc.style = 0; // Window style wc.lpfnWndProc = MainWndProc; // Callback function wc.cbClsExtra = 0; // Extra class data wc.cbWndExtra = 0; // Extra window data wc.hInstance = hInstance; // Owner handle wc.hIcon = NULL; // Application icon wc.hCursor = LoadCursor (NULL, IDC_ARROW);// Default cursor wc.hbrBackground = (HBRUSH) GetStockObject (WHITE_BRUSH); wc.lpszMenuName = NULL; // Menu name wc.lpszClassName = szAppName; // Window class name if (RegisterClass (&wc) == 0) return 0; // Load the command bar common control class. icex.dwSize = sizeof (INITCOMMONCONTROLSEX); icex.dwICC = ICC_BAR_CLASSES; InitCommonControlsEx (&icex); // Create unnamed auto-reset event initially false. g_hSendEvent = CreateEvent (NULL, FALSE, FALSE, NULL); // Create main window. hWnd = CreateWindow (szAppName, TEXT ("CeChat"), WS_VISIBLE, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, NULL, NULL, hInstance, NULL); // Return fail code if window not created. if (!IsWindow (hWnd)) return 0; // Create write thread. Read thread created when port opened. hThread = CreateThread (NULL, 0, SendThread, hWnd, 0, NULL); if (hThread) CloseHandle (hThread); else { DestroyWindow (hWnd); return 0; } // Standard show and update calls ShowWindow (hWnd, nCmdShow); UpdateWindow (hWnd); return hWnd; } //---------------------------------------------------------------------- // TermInstance - Program cleanup // int TermInstance (HINSTANCE hInstance, int nDefRC) { HANDLE hPort = hComPort; fContinue = FALSE; hComPort = INVALID_HANDLE_VALUE; if (hPort != INVALID_HANDLE_VALUE) CloseHandle (hPort); if (g_hSendEvent != INVALID_HANDLE_VALUE) { PulseEvent (g_hSendEvent); Sleep(100); CloseHandle (g_hSendEvent); } return nDefRC; } //====================================================================== // Message handling procedures for MainWindow //---------------------------------------------------------------------- // MainWndProc - Callback function for application window // LRESULT CALLBACK MainWndProc (HWND hWnd, UINT wMsg, WPARAM wParam, LPARAM lParam) { int i; // // Search message list to see if we need to handle this // message. If in list, call procedure. // for (i = 0; i < dim(MainMessages); i++) { if (wMsg == MainMessages[i].Code) return (*MainMessages[i].Fxn)(hWnd, wMsg, wParam, lParam); } return DefWindowProc (hWnd, wMsg, wParam, lParam); } //---------------------------------------------------------------------- // DoCreateMain - Process WM_CREATE message for window. // LRESULT DoCreateMain (HWND hWnd, UINT wMsg, WPARAM wParam, LPARAM lParam) { HWND hwndCB, hC1, hC2, hC3; int i; TCHAR szFirstDev[32]; LPCREATESTRUCT lpcs = (LPCREATESTRUCT) lParam; #if defined(WIN32_PLATFORM_PSPC) && (_WIN32_WCE >= 300) memset (&sai, 0, sizeof (sai)); sai.cbSize = sizeof (sai); { SHMENUBARINFO mbi; // For Pocket PC, create memset(&mbi, 0, sizeof(SHMENUBARINFO)); // menu bar so that we mbi.cbSize = sizeof(SHMENUBARINFO); // have a sip button. mbi.hwndParent = hWnd; mbi.dwFlags = SHCMBF_EMPTYBAR; SHCreateMenuBar(&mbi); SetWindowPos (hWnd, 0, 0, 0, lpcs->cx, lpcs->cy-26, SWP_NOZORDER | SWP_NOMOVE); } #endif // Create a command bar. hwndCB = CommandBar_Create (hInst, hWnd, IDC_CMDBAR); CommandBar_InsertMenubar (hwndCB, hInst, ID_MENU, 0); // Insert the COM port combo box. CommandBar_InsertComboBox (hwndCB, hInst, 140, CBS_DROPDOWNLIST, IDC_COMPORT, 1); FillComComboBox (hWnd); // Add exit button to command bar. CommandBar_AddAdornments (hwndCB, 0, 0); // Create child windows. They will be positioned in WM_SIZE. // Create receive text window. hC1 = CreateWindowEx (WS_EX_CLIENTEDGE, TEXT ("edit"), TEXT (""), WS_VISIBLE | WS_CHILD | WS_VSCROLL | ES_MULTILINE | ES_AUTOHSCROLL | ES_READONLY, 0, 0, 10, 10, hWnd, (HMENU)ID_RCVTEXT, hInst, NULL); // Create send text window. hC2 = CreateWindowEx (WS_EX_CLIENTEDGE, TEXT ("edit"), TEXT (""), WS_VISIBLE | WS_CHILD, 0, 0, 10, 10, hWnd, (HMENU)ID_SENDTEXT, hInst, NULL); // Create send text window. hC3 = CreateWindowEx (WS_EX_CLIENTEDGE, TEXT ("button"), TEXT ("&Send"), WS_VISIBLE | WS_CHILD | BS_DEFPUSHBUTTON, 0, 0, 10, 10, hWnd, (HMENU)ID_SENDBTN, hInst, NULL); // Destroy frame if window not created. if (!IsWindow (hC1) || !IsWindow (hC2) || !IsWindow (hC3)) { DestroyWindow (hWnd); return 0; } // Open a COM port. for (i = 0; i < 10; i++) { if (SendDlgItemMessage (hwndCB, IDC_COMPORT, CB_GETLBTEXT, i, (LPARAM)szFirstDev) == CB_ERR) break; if (InitCommunication (hWnd, szFirstDev) != INVALID_HANDLE_VALUE) { SendDlgItemMessage (hwndCB, IDC_COMPORT, CB_SETCURSEL, i, (LPARAM)szFirstDev); break; } } return 0; } //---------------------------------------------------------------------- // DoSizeMain - Process WM_SIZE message for window. // LRESULT DoSizeMain (HWND hWnd, UINT wMsg, WPARAM wParam, LPARAM lParam){ RECT rect; // Adjust the size of the client rect to take into account // the command bar height. GetClientRect (hWnd, &rect); rect.top += CommandBar_Height (GetDlgItem (hWnd, IDC_CMDBAR)); SetWindowPos (GetDlgItem (hWnd, ID_RCVTEXT), NULL, rect.left, rect.top, (rect.right - rect.left), rect.bottom - rect.top - 25, SWP_NOZORDER); SetWindowPos (GetDlgItem (hWnd, ID_SENDTEXT), NULL, rect.left, rect.bottom - 25, (rect.right - rect.left) - 50, 25, SWP_NOZORDER); SetWindowPos (GetDlgItem (hWnd, ID_SENDBTN), NULL, (rect.right - rect.left) - 50, rect.bottom - 25, 50, 25, SWP_NOZORDER); return 0; } //---------------------------------------------------------------------- // DoPocketPCShell - Process Pocket PC required messages. // LRESULT DoPocketPCShell (HWND hWnd, UINT wMsg, WPARAM wParam, LPARAM lParam) { #if defined(WIN32_PLATFORM_PSPC) && (_WIN32_WCE >= 300) if (wMsg == WM_SETTINGCHANGE) return SHHandleWMSettingChange(hWnd, wParam, lParam, &sai); if (wMsg == WM_ACTIVATE) return SHHandleWMActivate(hWnd, wParam, lParam, &sai, 0); #endif return 0; } //---------------------------------------------------------------------- // DoFocusMain - Process WM_SETFOCUS message for window. // LRESULT DoSetFocusMain (HWND hWnd, UINT wMsg, WPARAM wParam, LPARAM lParam) { SetFocus (GetDlgItem (hWnd, ID_SENDTEXT)); return 0; } //---------------------------------------------------------------------- // DoCommandMain - Process WM_COMMAND message for window. // LRESULT DoCommandMain (HWND hWnd, UINT wMsg, WPARAM wParam, LPARAM lParam) { WORD idItem, wNotifyCode; HWND hwndCtl; int i; // Parse the parameters. idItem = (WORD) LOWORD (wParam); wNotifyCode = (WORD) HIWORD (wParam); hwndCtl = (HWND) lParam; // Call routine to handle control message. for (i = 0; i < dim(MainCommandItems); i++) { if (idItem == MainCommandItems[i].Code) return (*MainCommandItems[i].Fxn)(hWnd, idItem, hwndCtl, wNotifyCode); } return 0; } //---------------------------------------------------------------------- // DoDestroyMain - Process WM_DESTROY message for window. // LRESULT DoDestroyMain (HWND hWnd, UINT wMsg, WPARAM wParam, LPARAM lParam) { PostQuitMessage (0); return 0; } //====================================================================== // Command handler routines //---------------------------------------------------------------------- // DoMainCommandExit - Process Program Exit command. // LPARAM DoMainCommandExit (HWND hWnd, WORD idItem, HWND hwndCtl, WORD wNotifyCode) { SendMessage (hWnd, WM_CLOSE, 0, 0); return 0; } //---------------------------------------------------------------------- // DoMainCommandComPort - Process the COM port combo box commands. // LPARAM DoMainCommandComPort (HWND hWnd, WORD idItem, HWND hwndCtl, WORD wNotifyCode) { int i; TCHAR szDev[32]; if (wNotifyCode == CBN_SELCHANGE) { i = SendMessage (hwndCtl, CB_GETCURSEL, 0, 0); if (i != nLastDev) { SendMessage (hwndCtl, CB_GETLBTEXT, i, (LPARAM)szDev); InitCommunication (hWnd, szDev); SetFocus (GetDlgItem (hWnd, ID_SENDTEXT)); } } return 0; } //---------------------------------------------------------------------- // DoMainCommandSendText - Process the Send text button. // LPARAM DoMainCommandSendText (HWND hWnd, WORD idItem, HWND hwndCtl, WORD wNotifyCode) { // Set event so that sender thread will send the text. SetEvent (g_hSendEvent); SetFocus (GetDlgItem (hWnd, ID_SENDTEXT)); return 0; } //---------------------------------------------------------------------- // DoMainCommandAbout - Process the Help | About menu command. // LPARAM DoMainCommandAbout(HWND hWnd, WORD idItem, HWND hwndCtl, WORD wNotifyCode) { // Use DialogBox to create modal dialog. DialogBox (hInst, TEXT ("aboutbox"), hWnd, AboutDlgProc); return 0; } //====================================================================== // About Dialog procedure // BOOL CALLBACK AboutDlgProc (HWND hWnd, UINT wMsg, WPARAM wParam, LPARAM lParam) { switch (wMsg) { case WM_COMMAND: switch (LOWORD (wParam)) { case IDOK: case IDCANCEL: EndDialog (hWnd, 0); return TRUE; } break; } return FALSE; } //---------------------------------------------------------------------- // FillComComboBox - Fills the COM port combo box // int FillComComboBox (HWND hWnd) { int rc; WIN32_FIND_DATA fd; HANDLE hFind; hFind = FindFirstFileEx (TEXT ("COM?:"), FindExInfoStandard, &fd, FindExSearchLimitToDevices, NULL, 0); if (hFind != INVALID_HANDLE_VALUE) { do { SendDlgItemMessage (GetDlgItem (hWnd, IDC_CMDBAR), IDC_COMPORT, CB_INSERTSTRING, -1, (LPARAM)fd.cFileName); rc = FindNextFile (hFind, &fd); } while (rc); rc = FindClose (hFind); } SendDlgItemMessage (GetDlgItem (hWnd, IDC_CMDBAR), IDC_COMPORT, CB_SETCURSEL, 0, 0); return 0; } //---------------------------------------------------------------------- // InitCommunication - Open and initialize selected COM port. // HANDLE InitCommunication (HWND hWnd, LPTSTR pszDevName) { DCB dcb; TCHAR szDbg[128]; COMMTIMEOUTS cto; HANDLE hLocal; DWORD dwTStat; hLocal = hComPort; hComPort = INVALID_HANDLE_VALUE; if (hLocal != INVALID_HANDLE_VALUE) CloseHandle (hLocal); // This causes WaitCommEvent to return. hLocal = CreateFile (pszDevName, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL); if (hLocal != INVALID_HANDLE_VALUE) { // Configure port. dcb.DCBlength = sizeof (dcb); GetCommState (hLocal, &dcb); dcb.BaudRate = nSpeed; dcb.fParity = FALSE; dcb.fNull = FALSE; dcb.StopBits = ONESTOPBIT; dcb.Parity = NOPARITY; dcb.ByteSize = 8; SetCommState (hLocal, &dcb); // Set the timeouts. Set infinite read timeout. cto.ReadIntervalTimeout = 0; cto.ReadTotalTimeoutMultiplier = 0; cto.ReadTotalTimeoutConstant = 0; cto.WriteTotalTimeoutMultiplier = 0; cto.WriteTotalTimeoutConstant = 0; SetCommTimeouts (hLocal, &cto); wsprintf (szDbg, TEXT ("Port %s opened\r\n"), pszDevName); SendDlgItemMessage (hWnd, ID_RCVTEXT, EM_REPLACESEL, 0, (LPARAM)szDbg); // Start read thread if not already started. hComPort = hLocal; if (!GetExitCodeThread (hReadThread, &dwTStat) || (dwTStat != STILL_ACTIVE)) { hReadThread = CreateThread (NULL, 0, ReadThread, hWnd, 0, &dwTStat); if (hReadThread) CloseHandle (hReadThread); } } else { wsprintf (szDbg, TEXT ("Couldn\'t open port %s. rc=%d\r\n"), pszDevName, GetLastError()); SendDlgItemMessage (hWnd, ID_RCVTEXT, EM_REPLACESEL, 0, (LPARAM)szDbg); } return hComPort; } //====================================================================== // SendThread - Sends characters to the serial port // DWORD WINAPI SendThread (PVOID pArg) { HWND hWnd, hwndSText; int rc; DWORD cBytes; TCHAR szText[TEXTSIZE]; hWnd = (HWND)pArg; hwndSText = GetDlgItem (hWnd, ID_SENDTEXT); while (1) { rc = WaitForSingleObject (g_hSendEvent, INFINITE); if (rc == WAIT_OBJECT_0) { if (!fContinue) break; // Disable send button while sending. EnableWindow (GetDlgItem (hWnd, ID_SENDBTN), FALSE); GetWindowText (hwndSText, szText, dim(szText)); lstrcat (szText, TEXT ("\r\n")); rc = WriteFile (hComPort, szText, lstrlen (szText)*sizeof (TCHAR),&cBytes, 0); if (rc) { // Copy sent text to output window. SendDlgItemMessage (hWnd, ID_RCVTEXT, EM_REPLACESEL, 0, (LPARAM)TEXT (" >")); SetWindowText (hwndSText, TEXT ("")); // Clear text box } else { // Else, print error message. wsprintf (szText, TEXT ("Send failed rc=%d\r\n"), GetLastError()); DWORD dwErr = 0; COMSTAT Stat; if (ClearCommError (hComPort, &dwErr, &Stat)) { printf ("fail\n"); } } // Put text in receive text box. SendDlgItemMessage (hWnd, ID_RCVTEXT, EM_REPLACESEL, 0, (LPARAM)szText); EnableWindow (GetDlgItem (hWnd, ID_SENDBTN), TRUE); } else break; } return 0; } //====================================================================== // ReadThread - Receives characters from the serial port // DWORD WINAPI ReadThread (PVOID pArg) { HWND hWnd; DWORD cBytes, i; BYTE szText[TEXTSIZE], *pPtr; TCHAR tch; hWnd = (HWND)pArg; while (fContinue) { tch = 0; pPtr = szText; for (i = 0; i < sizeof (szText)-sizeof (TCHAR); i++) { while (!ReadFile (hComPort, pPtr, 1, &cBytes, 0)) if (hComPort == INVALID_HANDLE_VALUE) return 0; // This syncs the proper byte order for Unicode. tch = (tch << 8) & 0xff00; tch |= *pPtr++; if (tch == TEXT ('\n')) break; } *pPtr++ = 0; // Avoid alignment problems by addressing as bytes. *pPtr++ = 0; // If out of byte sync, move bytes down one. if (i % 2) { pPtr = szText; while (*pPtr || *(pPtr+1)) { *pPtr = *(pPtr+1); pPtr++; } *pPtr = 0; } SendDlgItemMessage (hWnd, ID_RCVTEXT, EM_REPLACESEL, 0, (LPARAM)szText); } return 0; }