Mitä L-kirjain varsinaisesti tekee tässä tyyppimuunnoksessa (LPCWSTR)L"OpenGL"? Merkistöön jotain vaikutusta? Miten saan sen vaihtamaan muuttujan tyyliä, esim. (LPCWSTR)Ltitle?
L toimii vain literaalien kanssa ja tarkoittaa, että vakio on "leveä". Merkkijonovakioissa tarkoittaa, että merkin tyypiksi tulee wchar_t. Muuttujiin et voi sitä käyttää.
L-kirjain ei kuulu tyyppimuunnokseen, olet jäsentänyt ilmauksen väärin. Tyyppimuunnos tuossa on (LPCWSTR)
, osoitin C-tyyliseen (nollamerkkiin loppuvaan) wide char -tekstiin. Muunnettava asia on L"OpenGL" eli wide char -muotoinen teksti "OpenGL". Windowsissa wchar_t tarkoittaa muistaakseni UTF-16:a (joka ei tosin vastaa tyypin virallisia vaatimuksia).
Jos en laita L "väliin" niin tekstit näkyvät ihme merkeillä (japania???). Miten saan sitten muuttujan sisällön näkymään oikein?
Kuka tässä on mitään käskenyt pois ottaa? Tilanne on hieman vastaava kuin (int)0x1234
. Ei tässäkään 0x kuulu tyyppimuunnokseen vaan on osa itse lukua, ja sen poistaminen muuttaa luvun aivan toiseksi. Samoin on oman ilmauksesi kohdalla. Yhtä lailla voidaan todeta, että (int)0xmuuttuja
ei ole millään tavalla toimiva "muunnos", kuten ei omakaan vastaava merkintätapasi. Tähän yhtäläisyydet loppuvatkin.
Muunnoksen pitäisi mahdollisuuksien mukaan onnistua vaikkapa (w)sprintf-funktiolla.
wchar_t *wstr = L"Teksti"; char str[100]; // Varaa tarpeeksi tilaa! sprintf(str, "%ls", wstr); // Tai toiseen suuntaan: char *str = "Teksti"; wchar_t wstr[100]; wsprintf(wstr, L"%hs", str);
Nyt meni kyl ohi kovaa ja korkealta :(
Jos kertoisit, mitä kohtaa et ymmärtänyt, voisi olla helpompi selittää oikeita asioita. ^^ Mutta otetaanpa nyt aivan alusta.
printf("%d != %d\n", sizeof(L"teksti"), sizeof("teksti")); // Linuxissa esimerkiksi "28 != 7"
Kuten tästä selviää, nuo kaksi erilaista tekstiä vievät aivan eri määrän muistia ja ovat siis aivan eri tavaraa. Jatkotutkimuksia voit tehdä vaikka heksamuodossa (koodivinkki). Tällöin selviää, missä muodossa data muistissa on. Esimerkiksi omalla koneellani wchar_t vie neljä tavua merkkiä kohden, vaikka ASCII-merkit ovatkin koodeiltaan aivan normaalit.
Miksi tälläinen wchar_t on olemassa? Tai mihin sitä käytetään?
Standardi sanoo, että yhden wchar_t:n tulee kyetä sisältämään mikä tahansa järjestelmän tuntema merkki. Tämän takia UTF-16 ei täytä vaatimuksia: monet mutkikkaammat merkit vievät kaksi 16-bittistä lukua. Sen sijaan Linuxissa yleisesti käytettävä 32-bittinen luku riittää kattamaan koko Unicode-merkistön ja paljon ylikin. Joka tapauksessa tyypin tarkoitus on siis antaa tuki normaalia ASCII-merkistöä huomattavasti laajemmalle merkistölle. Luonnollisesti funktioistakin on tällöin usein kaksi versiota, "tavallinen" ja wide char -versio. Windowsissa jälkimmäisen tunnistaa yleensä W-kirjaimesta. Tavallisissa taitaa olla A, ja ilman näitä tunnisteita valittava funktio riippuu kääntäjän asetuksista (jotka usein tuntuvat suosivan tavallisia versioita).
Asian vierestä, mutta nuo funktioversiot muuten valitaan ihan esikääntäjällä. #define UNICODE ennen WinAPI-otsikkotiedostojen lisäystä valitsee W-päätteiset.
Anthaing kirjoitti:
Asian vierestä, mutta nuo funktioversiot muuten valitaan ihan esikääntäjällä. #define UNICODE ennen WinAPI-otsikkotiedostojen lisäystä valitsee W-päätteiset.
Toki näinkin, mutta funktioista voi käyttää myös haluamaansa vaihtoehtoa (vaikka molempia), ja ilman tuota UNICODEa valikoituu tietenkin A-päätteinen vaihtoehto. Lopputulos ilman omia säätöjä riippuu siis kehitysympäristön oletusasetuksista.
Kiitos vastauksista. Hieman vaikeaselkoinen asia vain :)
Miten saan CreateGLWindowin ensimmäisen parametrin LPCWSTR-muotoon? Kokeilin soveltaa Metabolixin koodia ylempää, mutta laihalla menestyksellä.
BOOL CreateGLWindow(char* title, int width, int height, int bits, bool fullscreenflag) { GLuint PixelFormat; // Holds The Results After Searching For A Match WNDCLASS wc; // Windows Class Structure DWORD dwExStyle; // Window Extended Style DWORD dwStyle; // Window Style RECT WindowRect; // Grabs Rectangle Upper Left / Lower Right Values WindowRect.left=(long)0; // Set Left Value To 0 WindowRect.right=(long)width; // Set Right Value To Requested Width WindowRect.top=(long)0; // Set Top Value To 0 WindowRect.bottom=(long)height; // Set Bottom Value To Requested Height fullscreen=fullscreenflag; // Set The Global Fullscreen Flag hInstance = GetModuleHandle(NULL); // Grab An Instance For Our Window wc.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC; // Redraw On Size, And Own DC For Window. wc.lpfnWndProc = (WNDPROC) WndProc; // WndProc Handles Messages wc.cbClsExtra = 0; // No Extra Window Data wc.cbWndExtra = 0; // No Extra Window Data wc.hInstance = hInstance; // Set The Instance wc.hIcon = LoadIcon(NULL, IDI_WINLOGO); // Load The Default Icon wc.hCursor = LoadCursor(NULL, IDC_ARROW); // Load The Arrow Pointer wc.hbrBackground = NULL; // No Background Required For GL wc.lpszMenuName = NULL; // We Don't Want A Menu wc.lpszClassName = (LPCWSTR)L"OpenGL"; // Set The Class Name if (!RegisterClass(&wc)) // Attempt To Register The Window Class { MessageBox(NULL,(LPCWSTR)L"Failed To Register The Window Class.",(LPCWSTR)L"ERROR",MB_OK|MB_ICONEXCLAMATION); return FALSE; // Return FALSE } if (fullscreen) // Attempt Fullscreen Mode? { DEVMODE dmScreenSettings; // Device Mode memset(&dmScreenSettings,0,sizeof(dmScreenSettings)); // Makes Sure Memory's Cleared dmScreenSettings.dmSize=sizeof(dmScreenSettings); // Size Of The Devmode Structure dmScreenSettings.dmPelsWidth = width; // Selected Screen Width dmScreenSettings.dmPelsHeight = height; // Selected Screen Height dmScreenSettings.dmBitsPerPel = bits; // Selected Bits Per Pixel dmScreenSettings.dmFields=DM_BITSPERPEL|DM_PELSWIDTH|DM_PELSHEIGHT; // Try To Set Selected Mode And Get Results. NOTE: CDS_FULLSCREEN Gets Rid Of Start Bar. if (ChangeDisplaySettings(&dmScreenSettings,CDS_FULLSCREEN)!=DISP_CHANGE_SUCCESSFUL) { // If The Mode Fails, Offer Two Options. Quit Or Use Windowed Mode. if (MessageBox(NULL,(LPCWSTR)L"The Requested Fullscreen Mode Is Not Supported By\nYour Video Card. Use Windowed Mode Instead?",(LPCWSTR)L"NeHe GL",MB_YESNO|MB_ICONEXCLAMATION)==IDYES) { fullscreen=FALSE; // Windowed Mode Selected. Fullscreen = FALSE } else { // Pop Up A Message Box Letting User Know The Program Is Closing. MessageBox(NULL,(LPCWSTR)L"Program Will Now Close.",(LPCWSTR)L"ERROR",MB_OK|MB_ICONSTOP); return FALSE; // Return FALSE } } } if (fullscreen) // Are We Still In Fullscreen Mode? { dwExStyle=WS_EX_APPWINDOW; // Window Extended Style dwStyle=WS_POPUP; // Windows Style ShowCursor(FALSE); // Hide Mouse Pointer } else { dwExStyle=WS_EX_APPWINDOW | WS_EX_WINDOWEDGE; // Window Extended Style dwStyle=WS_OVERLAPPEDWINDOW; // Windows Style } AdjustWindowRectEx(&WindowRect, dwStyle, FALSE, dwExStyle); // Adjust Window To True Requested Size //Tähän se toiminta, joka muuttaa muuttujan title LPCWSTR-muotoon? En saanut toimimaan Metabolixin koodia soveltamalla // Create The Window if (!(hWnd=CreateWindowEx( dwExStyle, // Extended Style For The Window (LPCWSTR)L"OpenGL", // Class Name title, // Window Title dwStyle | // Defined Window Style WS_CLIPSIBLINGS | // Required Window Style WS_CLIPCHILDREN, // Required Window Style 0, 0, // Window Position WindowRect.right-WindowRect.left, // Calculate Window Width WindowRect.bottom-WindowRect.top, // Calculate Window Height NULL, // No Parent Window NULL, // No Menu hInstance, // Instance NULL))) // Dont Pass Anything To WM_CREATE
line 320 : error C2664: 'CreateWindowExW' : cannot convert parameter 3 from 'char *' to 'LPCWSTR'
Tahdon muuttaa tuon kyseisen kolmannen parametrin oikeaan muotoon :)
Metabolix oikeastaan kirjoitti:
const char *str = "Teksti"; const int size = (strlen(str) + 1) * sizeof(wchar_t); wchar_t *wstr = malloc(size); wsprintf(wstr, L"%hs", str); /* Käyttö tässä välissä */ free(wstr);
Ei nyt ole Windowsia käsillä, joten jos tämä ei toimi, voisit vielä kertoa, miten se ei toimi, ja antaa vaikkapa linkittämäni koodivinkin mukaisen dumppauksen, dump(stdout, wstr, size);
Sovelsinkohan nyt väärin:
BOOL CreateGLWindow(char* title, int width, int height, int bits, bool fullscreenflag) const int size = (strlen(title) + 1) * sizeof(wchar_t); wchar_t *wstr = malloc(size); wsprintf(wstr, "%hs", title); // Create The Window if (!(hWnd=CreateWindowEx( dwExStyle, // Extended Style For The Window (LPCWSTR)L"OpenGL", // Class Name title, // Window Title dwStyle | // Defined Window Style WS_CLIPSIBLINGS | // Required Window Style WS_CLIPCHILDREN, // Required Window Style 0, 0, // Window Position WindowRect.right-WindowRect.left, // Calculate Window Width WindowRect.bottom-WindowRect.top, // Calculate Window Height NULL, // No Parent Window NULL, // No Menu hInstance, // Instance NULL))) // Dont Pass Anything To WM_CREATE { KillGLWindow(); // Reset The Display MessageBox(NULL,(LPCWSTR)L"Window Creation Error.",(LPCWSTR)L"ERROR",MB_OK|MB_ICONEXCLAMATION); return FALSE; // Return FALSE } free(wstr);
1>c:\users\roope\documents\visual studio 2008\projects\gl\opengl\main.cpp(307) : error C2440: 'initializing' : cannot convert from 'void *' to 'wchar_t *' 1> Conversion from 'void*' to pointer to non-'void' requires an explicit cast 1>c:\users\roope\documents\visual studio 2008\projects\gl\opengl\main.cpp(308) : error C2664: 'wsprintfW' : cannot convert parameter 2 from 'const char [4]' to 'LPCWSTR' 1> Types pointed to are unrelated; conversion requires reinterpret_cast, C-style cast or function-style cast 1>c:\users\roope\documents\visual studio 2008\projects\gl\opengl\main.cpp(323) : error C2664: 'CreateWindowExW' : cannot convert parameter 3 from 'char *' to 'LPCWSTR' 1> Types pointed to are unrelated; conversion requires reinterpret_cast, C-style cast or function-style cast
Käytät C++:aa (et maininnut), joten kääntäjälle täytyy erikseen kertoa, että tiedät, mitä teet. Tarvitset siis malloc-funktion paluuarvolle tyyppimuunnoksen (LPCWSTR tai wchar_t*). Funktion sprintfw formaattiin täytyy nähtävästi lisätä L eteen. CreateWindowEx-kutsussa tietenkin käytetään tätä muunnettua tekstiä (wstr) vanhan (title) sijaan.
... wstr = (wchar_t *) malloc(...); wsprintf(wstr, L"%hs", title);
Kiitos taas kerran Metabolix.. Nyt toimii.
Jos tässä vaikka itsekin vahingossa oppisi jotain... Jos ei muuta niin sen, että riemu on olla käyttämättä itse WinAPInaa. Suosittelen sinullekin jotain näppärämpiä rajapintoja, edes SDL:ää.
Harkitsemisen arvoinen idea.. Tämä on ensimmäinen WinAPIlla kokeilemani juttu ja vähän huono maku jäi :) Voisi kyllä yrittää koota SDL:än kautta..
Aihe on jo aika vanha, joten et voi enää vastata siihen.