1 /* 2 * PROJECT: ReactOS Tests 3 * FILE: rostests/win32/user32/biditext/biditext.c 4 * PURPOSE: Demonstrates how ExtTextOut and GetCharacterPlacement 5 * handle bidirectional text strings via certain selection 6 * of flags provided to them. 7 * 8 * PROGRAMMER: Program skeleton: https://github.com/TransmissionZero/MinGW-Win32-Application 9 * Test code by Baruch Rutman 10 */ 11 12 #include "biditext.h" 13 14 /* Prototypes */ 15 DWORD WINAPI LpkGetCharacterPlacement(HDC hdc, LPCWSTR lpString, INT uCount, INT nMaxExtent, 16 GCP_RESULTSW *lpResults, DWORD dwFlags, DWORD dwUnused); 17 18 BOOL WINAPI LpkExtTextOut(HDC hdc, int x, int y, 19 UINT fuOptions, const RECT *lprc, LPCWSTR lpString, 20 UINT uCount , const INT *lpDx, INT unknown); 21 22 /* Global instance handle */ 23 HINSTANCE g_hInstance = NULL; 24 25 /* Our application entry point */ 26 int WINAPI 27 wWinMain(HINSTANCE hInstance, 28 HINSTANCE hPrevInstance, 29 LPTSTR lpszCmdLine, 30 int nCmdShow) 31 { 32 INITCOMMONCONTROLSEX icc; 33 HWND hWnd; 34 HACCEL hAccelerators; 35 MSG msg; 36 37 /* Assign global HINSTANCE */ 38 g_hInstance = hInstance; 39 40 /* Initialise common controls */ 41 icc.dwSize = sizeof(icc); 42 icc.dwICC = ICC_WIN95_CLASSES; 43 InitCommonControlsEx(&icc); 44 45 /* Register our main window class, or error */ 46 if (!RegisterMainWindowClass()) 47 { 48 MessageBox(NULL, TEXT("Error registering main window class."), TEXT("Error"), MB_ICONERROR | MB_OK); 49 return 0; 50 } 51 52 /* Create our main window, or error */ 53 if (!(hWnd = CreateMainWindow())) 54 { 55 MessageBox(NULL, TEXT("Error creating main window."), TEXT("Error"), MB_ICONERROR | MB_OK); 56 return 0; 57 } 58 59 /* Load accelerators */ 60 hAccelerators = LoadAccelerators(hInstance, MAKEINTRESOURCE(IDR_ACCELERATOR)); 61 62 /* Show main window and force a paint */ 63 ShowWindow(hWnd, nCmdShow | SW_MAXIMIZE); 64 UpdateWindow(hWnd); 65 66 /* Main message loop */ 67 while (GetMessage(&msg, NULL, 0, 0) > 0) 68 { 69 if (!TranslateAccelerator(hWnd, hAccelerators, &msg)) 70 { 71 TranslateMessage(&msg); 72 DispatchMessage(&msg); 73 } 74 } 75 76 return (int)msg.wParam; 77 } 78 79 /* Dialog procedure for our "about" dialog */ 80 INT_PTR CALLBACK AboutDialogProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) 81 { 82 switch (uMsg) 83 { 84 case WM_COMMAND: 85 { 86 WORD id = LOWORD(wParam); 87 88 switch (id) 89 { 90 case IDOK: 91 case IDCANCEL: 92 { 93 EndDialog(hwndDlg, (INT_PTR)id); 94 return (INT_PTR)TRUE; 95 } 96 } 97 break; 98 } 99 100 case WM_INITDIALOG: 101 { 102 return (INT_PTR)TRUE; 103 } 104 } 105 106 return (INT_PTR)FALSE; 107 } 108 109 /* Show our "about" dialog */ 110 void ShowAboutDialog(HWND owner) 111 { 112 DialogBox(g_hInstance, MAKEINTRESOURCE(IDD_ABOUTDIALOG), owner, &AboutDialogProc); 113 } 114 115 /* Main window class and title */ 116 static LPCTSTR MainWndClass = TEXT("BiDi Test"); 117 118 /* Window procedure for our main window */ 119 LRESULT CALLBACK MainWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) 120 { 121 switch (msg) 122 { 123 case WM_COMMAND: 124 { 125 WORD id = LOWORD(wParam); 126 127 switch (id) 128 { 129 case ID_HELP_ABOUT: 130 { 131 ShowAboutDialog(hWnd); 132 return 0; 133 } 134 135 case ID_FILE_EXIT: 136 { 137 DestroyWindow(hWnd); 138 return 0; 139 } 140 } 141 break; 142 } 143 144 case WM_GETMINMAXINFO: 145 { 146 /* Prevent our window from being sized too small */ 147 MINMAXINFO *minMax = (MINMAXINFO*)lParam; 148 minMax->ptMinTrackSize.x = 220; 149 minMax->ptMinTrackSize.y = 110; 150 151 return 0; 152 } 153 154 /* Item from system menu has been invoked */ 155 case WM_SYSCOMMAND: 156 { 157 WORD id = LOWORD(wParam); 158 159 switch (id) 160 { 161 /* Show "about" dialog on about system menu item */ 162 case ID_HELP_ABOUT: 163 { 164 ShowAboutDialog(hWnd); 165 return 0; 166 } 167 } 168 break; 169 } 170 171 case WM_PAINT: 172 { 173 PAINTSTRUCT ps; 174 175 HDC hdc = BeginPaint(hWnd, &ps); 176 177 enum 178 { 179 ALEF = 0x5D0, 180 BET, 181 GIMEL, 182 DALET, 183 HEY, 184 VAV, 185 ZAYIN, 186 HET, 187 TET, 188 YUD 189 }; 190 191 const WCHAR szString[] = {ALEF, BET, GIMEL, DALET, HEY, 'A', 'B', 'C', 'D', VAV, ZAYIN, HET, TET, YUD, 0}; 192 const WCHAR szReversedString[] = {HEY, DALET, GIMEL, BET, ALEF, 'A', 'B', 'C', 'D', YUD, TET, HET, ZAYIN, VAV, 0}; 193 int Len = wcslen(szString); 194 int i, xpos, tempLength; 195 WCHAR tempString[20] = { 0 }; 196 WCHAR Glyphs[100] = { 0 }; 197 WCHAR OutString[100] = { 0 }; 198 INT lpCaretPos[100] = { 0 }; 199 UINT lpOrder[100] = { 0 }; 200 GCP_RESULTSW Results = { 0 }; 201 202 Results.lStructSize = sizeof(Results); 203 Results.lpOutString = OutString; 204 Results.lpGlyphs = Glyphs; 205 Results.nGlyphs = 100; 206 Results.lpCaretPos = lpCaretPos; 207 Results.lpOrder = lpOrder; 208 209 SetBkMode(hdc, TRANSPARENT); 210 211 TextOutW(hdc, 10, 10, L"Proper (string being used):", 27); 212 TextOutW(hdc, 200, 10, szString, 14); 213 TextOutW(hdc, 10, 30, L"Reversed (example):", 19); 214 TextOutW(hdc, 200, 30, szReversedString, 14); 215 216 TextOutW(hdc, 10, 50, L"String with NULL LpkETO call (not reversed):", 44); 217 LpkExtTextOut(hdc, 10, 70, 0, NULL, szString, Len, NULL, 0); 218 219 TextOutW(hdc, 10, 90, L"String with ETO_IGNORELANGUAGE LpkETO call (not reversed):", 58); 220 LpkExtTextOut(hdc, 10, 110, ETO_IGNORELANGUAGE, NULL, szString, Len, NULL, 0); 221 222 TextOutW(hdc, 10, 130, L"String with GCP_REORDER and ETO_GLYPH_INDEX LpkGCP call (not reversed):", 71); 223 LpkGetCharacterPlacement(hdc, szString, Len, 0, &Results, GCP_REORDER, 0); 224 LpkExtTextOut(hdc, 10, 150, ETO_GLYPH_INDEX, NULL, Glyphs, Results.nGlyphs, NULL, 0); 225 TextOutW(hdc, 10, 170, L"String with GCP_REORDER and ETO_IGNORELANGUAGE LpkGCP call (not reversed, lpOutString):", 87); 226 ExtTextOutW(hdc, 10, 190, ETO_IGNORELANGUAGE, NULL, OutString, Results.nGlyphs, NULL); 227 228 TextOutW(hdc, 10, 210, L"String without GCP_REORDER and ETO_GLYPH_INDEX LpkGCP call (reversed):", 70); 229 LpkGetCharacterPlacement(hdc, szString, Len, 0, &Results, 0, 0); 230 LpkExtTextOut(hdc, 10, 230, ETO_GLYPH_INDEX, NULL, Glyphs, Results.nGlyphs, NULL, 0); 231 TextOutW(hdc, 10, 250, L"String without GCP_REORDER and ETO_IGNORELANGUAGE LpkGCP call (reversed, lpOutString):", 86); 232 ExtTextOutW(hdc, 10, 270, ETO_IGNORELANGUAGE, NULL, OutString, Len, NULL); 233 234 TextOutW(hdc, 10, 290, L"String with ETO_IGNORELANGUAGE ETO call (reversed, not Lpk direct call!):", 73); 235 ExtTextOutW(hdc, 10, 310, ETO_IGNORELANGUAGE, NULL, szString, Len, NULL); 236 237 TextOutW(hdc, 10, 330, L"String with ETO_RTLREADING LpkETO call (slight order change)", 60); 238 LpkExtTextOut(hdc, 10, 350, ETO_RTLREADING, NULL, szString, Len, NULL, 0); 239 240 TextOutW(hdc, 10, 370, L"String with ETO_RTLREADING ETO call (slight order change)", 57); 241 ExtTextOutW(hdc, 10, 390, ETO_RTLREADING, NULL, szString, Len, NULL); 242 243 GetCharacterPlacementW(hdc, szString, Len, 0, &Results, GCP_REORDER); 244 TextOutW(hdc, 10, 410, L"Glyph positions with GCP_REORDER flag", 37); 245 246 /* Prints per column the location of the character in the string, reordered location, its position and the character itself */ 247 for (i = 0, xpos = 10; i < Len; i++, xpos += 30) 248 { 249 StringCchPrintfW(tempString, 20, L"%d", i); 250 tempLength = wcslen(tempString); 251 TextOutW(hdc, xpos, 430, tempString, tempLength); 252 253 StringCchPrintfW(tempString, 20, L"%d", lpOrder[i]); 254 tempLength = wcslen(tempString); 255 TextOutW(hdc, xpos, 450, tempString, tempLength); 256 257 StringCchPrintfW(tempString, 20, L"%d", lpCaretPos[i]); 258 tempLength = wcslen(tempString); 259 TextOutW(hdc, xpos, 470, tempString, tempLength); 260 261 TextOutW(hdc, xpos, 490, &szString[i], 1); 262 } 263 TextOutW(hdc, xpos, 430, L"Character location", 18); 264 TextOutW(hdc, xpos, 450, L"lpOrder[i]", 10); 265 TextOutW(hdc, xpos, 470, L"lpCaretPos[i]", 13); 266 TextOutW(hdc, xpos, 490, L"String[i]", 9); 267 268 GetCharacterPlacementW(hdc, szString, Len, 0, &Results, 0); 269 TextOutW(hdc, 10, 510, L"Glyph positions without GCP_REORDER flag", 40); 270 271 for (i = 0, xpos = 10; i < Len; i++, xpos += 30) 272 { 273 StringCchPrintfW(tempString, 20, L"%d", i); 274 tempLength = wcslen(tempString); 275 TextOutW(hdc, xpos, 530, tempString, tempLength); 276 277 StringCchPrintfW(tempString, 20, L"%d", lpOrder[i]); 278 tempLength = wcslen(tempString); 279 TextOutW(hdc, xpos, 550, tempString, tempLength); 280 281 StringCchPrintfW(tempString, 20, L"%d", lpCaretPos[i]); 282 tempLength = wcslen(tempString); 283 TextOutW(hdc, xpos, 570, tempString, tempLength); 284 285 TextOutW(hdc, xpos, 590, &szString[i], 1); 286 } 287 TextOutW(hdc, xpos, 530, L"Character location", 18); 288 TextOutW(hdc, xpos, 550, L"lpOrder[i]", 10); 289 TextOutW(hdc, xpos, 570, L"lpCaretPos[i]", 13); 290 TextOutW(hdc, xpos, 590, L"String[i]", 9); 291 292 EndPaint(hWnd, &ps); 293 break; 294 } 295 296 case WM_DESTROY: 297 { 298 PostQuitMessage(0); 299 return 0; 300 } 301 } 302 303 return DefWindowProc(hWnd, msg, wParam, lParam); 304 } 305 306 /* Register a class for our main window */ 307 BOOL RegisterMainWindowClass() 308 { 309 WNDCLASSEX wc; 310 311 /* Class for our main window */ 312 wc.cbSize = sizeof(wc); 313 wc.style = 0; 314 wc.lpfnWndProc = &MainWndProc; 315 wc.cbClsExtra = 0; 316 wc.cbWndExtra = 0; 317 wc.hInstance = g_hInstance; 318 wc.hIcon = (HICON)LoadImage(g_hInstance, MAKEINTRESOURCE(IDI_APPICON), IMAGE_ICON, 0, 0, LR_DEFAULTSIZE | 319 LR_DEFAULTCOLOR | LR_SHARED); 320 wc.hCursor = (HCURSOR)LoadImage(NULL, IDC_ARROW, IMAGE_CURSOR, 0, 0, LR_SHARED); 321 wc.hbrBackground = (HBRUSH)(COLOR_BTNFACE + 1); 322 wc.lpszMenuName = MAKEINTRESOURCE(IDR_MAINMENU); 323 wc.lpszClassName = MainWndClass; 324 wc.hIconSm = (HICON)LoadImage(g_hInstance, MAKEINTRESOURCE(IDI_APPICON), IMAGE_ICON, 16, 16, LR_DEFAULTCOLOR); 325 326 return (RegisterClassEx(&wc)) ? TRUE : FALSE; 327 } 328 329 /* Create an instance of our main window */ 330 HWND CreateMainWindow() 331 { 332 /* Create instance of main window */ 333 HWND hWnd = CreateWindowEx(0, MainWndClass, MainWndClass, WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, 640, 480, 334 NULL, NULL, g_hInstance, NULL); 335 336 if (hWnd) 337 { 338 /* Add "about" to the system menu */ 339 HMENU hSysMenu = GetSystemMenu(hWnd, FALSE); 340 InsertMenu(hSysMenu, 5, MF_BYPOSITION | MF_SEPARATOR, 0, NULL); 341 InsertMenu(hSysMenu, 6, MF_BYPOSITION, ID_HELP_ABOUT, TEXT("About")); 342 } 343 344 return hWnd; 345 } 346