CPlusPlus for Gideros Studio Help
Here you will find various resources to help learn C++ for people who wish to help with Gideros Studio development.
KNOWNFOLDERID
platform-win32.cpp
refs:
- KNOWNFOLDERID: https://learn.microsoft.com/en-us/windows/win32/shell/knownfolderid
- shlobj_core.h header: https://learn.microsoft.com/en-us/windows/win32/api/shlobj_core/
- SHGetKnownFolderPath function (shlobj_core.h): https://learn.microsoft.com/en-us/windows/win32/api/shlobj_core/nf-shlobj_core-shgetknownfolderpath
- SO (cc-by): https://stackoverflow.com/a/50660989/870125
C:\dev\gideros_hgy29\libgid\src\win32\platform-win32.cpp
Convert wstring <-> string
platform-win32.cpp
refs:
- SO (cc-by): https://stackoverflow.com/a/18374698/870125
C:\dev\gideros_hgy29\libgid\src\win32\platform-win32.cpp
#include <locale> // new 20221014 XXX
#include <codecvt> // new 20221014 XXX
...
std::wstring s2ws(const std::string& str)
{
using convert_typeX = std::codecvt_utf8<wchar_t>;
std::wstring_convert<convert_typeX, wchar_t> converterX;
return converterX.from_bytes(str);
}
std::string ws2s(const std::wstring& wstr)
{
using convert_typeX = std::codecvt_utf8<wchar_t>;
std::wstring_convert<convert_typeX, wchar_t> converterX;
return converterX.to_bytes(wstr);
}
win32 minimum, maximum screen size
platform-win32.cpp
refs:
- https://www.youtube.com/watch?v=-kg4TG7GoYI
- https://gamedev.net/forums/topic/569148-c-windows-api-minimum-resize-dimensions/4638297/
- SO (cc-by): https://stackoverflow.com/q/19035481/870125
- SO (cc-by): https://stackoverflow.com/a/22261818/870125
- https://learn.microsoft.com/en-gb/windows/win32/winmsg/wm-getminmaxinfo?redirectedfrom=MSDN
- https://learn.microsoft.com/en-us/windows/win32/api/winuser/nc-winuser-wndproc
C:\dev\gideros_hgy29\libgid\src\win32\platform-win32.cpp
win32 LFS problem with separator
Recent changes to path handling (most likely [0]) caused AssetCatalogTest.create_catalog_after_loading_file to fail on WIN32.
The test relied on the resulting path to be joined with "/" as a path separator. The resulting path used both forward and back-slashes. While these do work for some API's on WIN32, mixing both in a file path isn't expected behavior in most cases, so update the tests to use native slash direction for file-paths.
* \note If you want a trailing slash, add `SEP_STR` as the last path argument,
* duplicate slashes will be cleaned up.
*/
size_t BLI_path_join(char *__restrict dst, size_t dst_len, const char *path, ...)
# define SEP '\\'
# define ALTSEP '/'
# define SEP_STR "\\"
# define ALTSEP_STR "/"
#else
# define SEP '/'
#define SEP_CHR '#'
#define SEP_STR "#"
#define EPS 0.001
#define UN_SC_KM 1000.0f
#define UN_SC_HM 100.0f
str_tmp, TEMP_STR_SIZE, "*%.9g" SEP_STR, unit->scalar / scale_pref);
if (len_num > len_max) {
len_num = len_max;
}
if (found_ofs + len_num + len_move > len_max) {
openFileDialog
platform-win32.cpp
refs:
- https://learn.microsoft.com/en-us/windows/win32/learnwin32/learn-to-program-for-windows
- https://weblogs.asp.net/kennykerr/Windows-Vista-for-Developers-_1320_-Part-6-_1320_-The-New-File-Dialogs
- https://www.codeproject.com/Articles/16678/Vista-Goodies-in-C-Using-the-New-Vista-File-Dialog
- https://learn.microsoft.com/en-us/windows/win32/shell/common-file-dialog
#include <wchar.h> // new 20221026 XXX
...
}else if ((strcmp(what, "openDirectoryDialog") == 0)
|| (strcmp(what, "openFileDialog") == 0)
|| (strcmp(what, "saveFileDialog") == 0))
{
/* TODO parse extension :-( */
// for win32 args ("title|path|extensions//help") is only 1 arg
// unlike Qt which seems to cut the | into different args
if(args.size() == 1){ // do we need to deal with "help" as arg or leave it to Qt?
// we cut the args
std::wstring s=ws(args[0].s.c_str()); // "Title|c:\\tmp|Text (*.txt);; Image (*.png)"
size_t index = s.find(L"|");
size_t index2 = s.find(L"|", index+1);
std::wstring title = s.substr(0, index);
std::wstring place = s.substr(index+1, index2-index-1);
std::wstring extension = s.substr(index2+1);
// printf("t p e:\n %ls\n %ls\n %ls\n", title.c_str(),place.c_str(),extension.c_str()); // TEST OK
DWORD dwFlags; // new 20221028 XXX
HRESULT hr = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED | COINIT_DISABLE_OLE1DDE);
if (SUCCEEDED(hr))
{
if (strcmp(what, "openDirectoryDialog") == 0){
/* TO DO */
/*--------------------------------------------------*/
}else if (strcmp(what, "openFileDialog") == 0){
IFileOpenDialog *pFile;
COMDLG_FILTERSPEC fileTypes[] = /* TODO parse from wstring extension :-( */
{
{ L"Text Documents", L"*.txt" },
{ L"All Files", L"*.*" },
};
// Create the FileOpenDialog object.
hr = CoCreateInstance(CLSID_FileOpenDialog, NULL, CLSCTX_ALL,
IID_IFileOpenDialog, reinterpret_cast<void**>(&pFile));
if (SUCCEEDED(hr))
{
// get/set options
pFile->GetOptions(&dwFlags);
pFile->SetOptions(dwFlags | FOS_FORCEFILESYSTEM);
pFile->SetFileTypes(ARRAYSIZE(fileTypes), fileTypes); // SEE ABOVE fileTypes
pFile->SetFileTypeIndex(1); // index starts at 1
// pFile->SetDefaultExtension(L"obj;fbx"); // XXX
hr = pFile->SetTitle(title.c_str()); // need more check?
// set starting folder
IShellItem *pItem = NULL;
hr = SHCreateItemFromParsingName(place.c_str(), NULL, IID_IShellItem, (LPVOID *)&pItem);
if (SUCCEEDED(hr))
{
pFile->SetFolder(pItem);
pItem->Release();
pItem = NULL;
}
// Show the Open dialog box.
hr = pFile->Show(NULL);
// Get the file name from the dialog box.
if (SUCCEEDED(hr))
{
IShellItem *pItem;
hr = pFile->GetResult(&pItem);
if (SUCCEEDED(hr))
{
PWSTR pszFilePath;
hr = pItem->GetDisplayName(SIGDN_FILESYSPATH, &pszFilePath);
if (SUCCEEDED(hr))
{
r.type=gapplication_Variant::STRING;
r.s=us(pszFilePath);
rets.push_back(r);
CoTaskMemFree(pszFilePath);
}
pItem->Release();
}
}
pFile->Release();
}
CoUninitialize();
/*--------------------------------------------------*/
}else if (strcmp(what, "saveFileDialog") == 0){
/* TO DO */
/*--------------------------------------------------*/
}
}
}
/*------------------------------------------------------------------*/
}else if (strcmp(what, "temporaryDirectory") == 0)
openFileDialog Latest
platform-win32.cpp (updated and working piece of code)
Added:
- append file extension to saved files (1st extension from filters)
}else if ((strcmp(what, "openDirectoryDialog") == 0)
|| (strcmp(what, "openFileDialog") == 0)
|| (strcmp(what, "saveFileDialog") == 0))
{
if(args.size() <= 2){
/* INFO SHOWN IN GIDEROS STUDIO DEBUGGER, IMPLEMENTED IN QT, NOT NEEDED HERE? */
}
else
{
std::wstring title = ws(args[0].s.c_str());
std::wstring place = ws(args[1].s.c_str());
std::vector<std::pair<std::wstring,std::wstring>> filters;
if (args.size()>=3) {
std::wstring ext = ws(args[2].s.c_str());
while (!ext.empty()) {
std::wstring next;
size_t semicolon=ext.find(L";;");
if (semicolon!=std::wstring::npos) {
next=ext.substr(semicolon+2);
ext=ext.substr(0,semicolon);
}
size_t p1=ext.find_first_of(L'(');
size_t p2=ext.find_last_of(L')');
if ((p1!=std::wstring::npos)&&(p2!=std::wstring::npos)&&(p2>p1))
{
//Valid filter, extract label and extensions
std::wstring label=ext.substr(0,p1);
std::wstring exts=ext.substr(p1+1,p2-p1-1);
//QT uses space for extensions separator, while windows expects semicolon. Convert them.
std::replace(exts.begin(),exts.end(),L' ',L';');
filters.push_back(std::pair<std::wstring,std::wstring>(label,exts));
}
ext=next;
}
}
DWORD dwFlags;
HRESULT hr = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED | COINIT_DISABLE_OLE1DDE);
if (SUCCEEDED(hr))
{
COMDLG_FILTERSPEC *fileTypes=new COMDLG_FILTERSPEC[filters.size()];
for (size_t i=0;i<filters.size();i++) {
fileTypes[i].pszName=filters[i].first.c_str();
fileTypes[i].pszSpec=filters[i].second.c_str();
}
IFileDialog *pFile;
if (strcmp(what, "saveFileDialog") == 0)
hr = CoCreateInstance(CLSID_FileSaveDialog, NULL, CLSCTX_ALL,
IID_IFileSaveDialog, reinterpret_cast<void**>(&pFile));
else
hr = CoCreateInstance(CLSID_FileOpenDialog, NULL, CLSCTX_ALL,
IID_IFileOpenDialog, reinterpret_cast<void**>(&pFile));
if (SUCCEEDED(hr))
{
bool isFolder=(strcmp(what, "openDirectoryDialog") == 0);
// get/set options
pFile->GetOptions(&dwFlags);
pFile->SetOptions(dwFlags | FOS_FORCEFILESYSTEM | (isFolder?FOS_PICKFOLDERS:0));
if (!isFolder) {
pFile->SetFileTypes(filters.size(), fileTypes);
pFile->SetFileTypeIndex(1); // index starts at 1
//pFile->SetDefaultExtension(L"obj;fbx"); // append default extension
//printf("* fileTypes *, set default extension to %ls\n", fileTypes[0].pszSpec); OK
pFile->SetDefaultExtension(fileTypes[0].pszSpec); // append default 1st extension
}
hr = pFile->SetTitle(title.c_str()); // need more check?
// set starting folder
IShellItem *pItem = NULL;
hr = SHCreateItemFromParsingName(place.c_str(), NULL, IID_IShellItem, (LPVOID *)&pItem);
if (SUCCEEDED(hr))
{
pFile->SetFolder(pItem);
pItem->Release();
pItem = NULL;
}
// Show the Open dialog box.
hr = pFile->Show(NULL);
// Get the file name from the dialog box.
if (SUCCEEDED(hr))
{
IShellItem *pItem;
hr = pFile->GetResult(&pItem);
if (SUCCEEDED(hr))
{
PWSTR pszFilePath;
hr = pItem->GetDisplayName(SIGDN_FILESYSPATH, &pszFilePath);
if (SUCCEEDED(hr))
{
r.type=gapplication_Variant::STRING;
r.s=us(pszFilePath);
rets.push_back(r);
CoTaskMemFree(pszFilePath);
}
pItem->Release();
}
}
pFile->Release();
}
CoUninitialize();
delete[] fileTypes;
}
}
/*------------------------------------------------------------------*/
}else if (strcmp(what, "temporaryDirectory") == 0)
Locate first occurrence of character in wide string
platform-win32.cpp
refs:
std::wstring gs=ws(args[0].s.c_str()); // "Title|C:/tmp/|Text (*.txt);; Image (*.png)"
size_t index = gs.find(L"|");
size_t index2 = gs.find(L"|", index+1);
printf("args0: %ls\n", gs.c_str()); // output: Title|C:/tmp/|Text (*.txt);; Image (*.png)
printf("indices: %d, %d\n", index,index2); // output 5, 13
std::wstring title = gs.substr(0, index);
std::wstring path = gs.substr(index+1, index2-index-1);
std::wstring exts = gs.substr(index2+1);
printf("t p e:\n %ls\n %ls\n %ls\n", title.c_str(),path.c_str(),exts.c_str()); // Title C:/tmp/ Text (*.txt);; Image (*.png)
application:getKeyboardModifiers()
platform-win32.cpp
refs:
if(GetAsyncKeyState(VK_LSHIFT) & 0x8000)
; // left shift is currently down
mkDir
platform-win32.cpp
Tested and seems ok :-)
refs:
}else if (strcmp(what, "mkDir") == 0)
{
// new 20221114 XXX
std::wstring dir = ws(args[0].s.c_str());
if (_wmkdir(dir.c_str()) == 0)
printf("mkDir OK: %S\n", dir.c_str()); // can be useful for the w32 console
else
printf("mkDir failed or Dir may already exist: %S\n", dir.c_str()); // can be useful for the w32 console
/*------------------------------------------------------------------*/
}else if (strcmp(what, "documentDirectory") == 0)
pathfileexists
platform-win32.cpp
Tested and seems ok but not sure about what the return value should be :-/ and we can also check for access mode!
refs:
- SO (cc-by): https://stackoverflow.com/a/28011583/870125
- https://learn.microsoft.com/en-us/cpp/c-runtime-library/reference/access-waccess?view=msvc-170
}else if (strcmp(what, "pathfileexists") == 0) // new 20221116 XXX
{
if (args.size() > 0) {
std::wstring path = ws(args[0].s.c_str());
int retValue;
if (_waccess(path.c_str(), 0) == 0) { // modes: 0=Existence only, 2=Write-only, 4=Read-only, 6=Read and write
// path exists
retValue = 1;
} else {
retValue = 0;
}
r.type=gapplication_Variant::DOUBLE;
r.d=retValue;
rets.push_back(r);
}
/*------------------------------------------------------------------*/
}else if ((strcmp(what, "openDirectoryDialog") == 0)
WM_GETMINMAXINFO
win32.cpp
WIP
refs:
- SO (cc-by): https://stackoverflow.com/questions/22261804/how-to-set-minimum-window-size-using-winapi
- https://learn.microsoft.com/en-gb/windows/win32/winmsg/wm-getminmaxinfo?redirectedfrom=MSDN
LoadCursorA
platform-win32.cpp
WIP
refs:
- SO (cc-by): https://stackoverflow.com/questions/19257237/reset-cursor-in-wm-setcursor-handler-properly
- https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-loadcursora
else { // SET
if (strcmp(what, "cursor") == 0)
{
/* TODO */
std::string &shape = args[0].s;
// QStringList acceptedValue;
// acceptedValue << "arrow" << "upArrow" << "cross" << "wait" << "IBeam";
// acceptedValue << "sizeVer" << "sizeHor" << "sizeBDiag" << "sizeFDiag" << "sizeAll";
// acceptedValue << "blank" << "splitV" << "splitH" << "pointingHand" << "forbidden";
// acceptedValue << "whatsThis" << "busy" << "openHand" << "closedHand" << "dragCopy";
// acceptedValue << "dragMove" << "dragLink";
HCURSOR cursor;
if (shape == "arrow") {
printf("** cursor arrow\n");
cursor = LoadCursorA(NULL, (LPCSTR)IDC_ARROW);
SetCursor(cursor);
} else if (shape == "upArrow") {
printf("** cursor uparrow\n"); // LUA DEBUG OK BUT ARROW SHAPE DOESN'T CHANGE :-(
cursor = LoadCursorA(NULL, (LPCSTR)IDC_UPARROW);
SetCursor(cursor);
}
/*------------------------------------------------------------------*/
}else if (strcmp(what, "windowPosition") == 0)