#pragma comment(lib, "comctl32.lib") #pragma comment(linker, "\"/manifestdependency:type='Win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='X86' publicKeyToken='6595b64144ccf1df' language='*'\"") #include "stdafx.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "SimulatorWin.h" #include "glfw3.h" #include "glfw3native.h" #include "AppEvent.h" #include "AppLang.h" #include "runtime/ConfigParser.h" #include "runtime/Runtime.h" #include "platform/win32/PlayerWin.h" #include "platform/win32/PlayerMenuServiceWin.h" #include "resource.h" USING_NS_CC; static WNDPROC g_oldWindowProc = NULL; INT_PTR CALLBACK AboutDialogCallback(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam) { LOGFONT lf; HFONT hFont; UNREFERENCED_PARAMETER(lParam); switch (message) { case WM_INITDIALOG: ZeroMemory(&lf, sizeof(LOGFONT)); lf.lfHeight = 24; lf.lfWeight = 200; _tcscpy(lf.lfFaceName, _T("Arial")); hFont = CreateFontIndirect(&lf); if ((HFONT)0 != hFont) { SendMessage(GetDlgItem(hDlg, IDC_ABOUT_TITLE), WM_SETFONT, (WPARAM)hFont, (LPARAM)TRUE); } return (INT_PTR)TRUE; case WM_COMMAND: if (LOWORD(wParam) == IDOK || LOWORD(wParam) == IDCANCEL) { EndDialog(hDlg, LOWORD(wParam)); return (INT_PTR)TRUE; } break; } return (INT_PTR)FALSE; } void onHelpAbout() { DialogBox(GetModuleHandle(NULL), MAKEINTRESOURCE(IDD_DIALOG_ABOUT), Director::getInstance()->getOpenGLView()->getWin32Window(), AboutDialogCallback); } void shutDownApp() { auto glview = dynamic_cast (Director::getInstance()->getOpenGLView()); HWND hWnd = glview->getWin32Window(); ::SendMessage(hWnd, WM_CLOSE, NULL, NULL); } std::string getCurAppPath(void) { TCHAR szAppDir[MAX_PATH] = {0}; if (!GetModuleFileName(NULL, szAppDir, MAX_PATH)) return ""; int nEnd = 0; for (int i = 0; szAppDir[i]; i++) { if (szAppDir[i] == '\\') nEnd = i; } szAppDir[nEnd] = 0; int iLen = 2 * wcslen(szAppDir); char* chRtn = new char[iLen + 1]; wcstombs(chRtn, szAppDir, iLen + 1); std::string strPath = chRtn; delete[] chRtn; chRtn = NULL; char fuldir[MAX_PATH] = {0}; _fullpath(fuldir, strPath.c_str(), MAX_PATH); return fuldir; } static bool stringEndWith(const std::string str, const std::string needle) { if (str.length() >= needle.length()) { return (0 == str.compare(str.length() - needle.length(), needle.length(), needle)); } return false; } static void initGLContextAttrs() { // set OpenGL context attributes: red,green,blue,alpha,depth,stencil GLContextAttrs glContextAttrs = {8, 8, 8, 8, 24, 8}; GLView::setGLContextAttrs(glContextAttrs); } SimulatorWin *SimulatorWin::_instance = nullptr; SimulatorWin *SimulatorWin::getInstance() { if (!_instance) { _instance = new SimulatorWin(); } return _instance; } SimulatorWin::SimulatorWin() : _app(nullptr) , _hwnd(NULL) , _hwndConsole(NULL) , _writeDebugLogFile(nullptr) { } SimulatorWin::~SimulatorWin() { CC_SAFE_DELETE(_app); if (_writeDebugLogFile) { fclose(_writeDebugLogFile); } } void SimulatorWin::quit() { Director::getInstance()->end(); } void SimulatorWin::relaunch() { _project.setWindowOffset(Vec2(getPositionX(), getPositionY())); openNewPlayerWithProjectConfig(_project); quit(); } void SimulatorWin::openNewPlayer() { openNewPlayerWithProjectConfig(_project); } void SimulatorWin::openNewPlayerWithProjectConfig(const ProjectConfig &config) { static long taskid = 100; stringstream buf; buf << taskid++; string commandLine; commandLine.append(getApplicationExePath()); commandLine.append(" "); commandLine.append(config.makeCommandLine()); CCLOG("SimulatorWin::openNewPlayerWithProjectConfig(): %s", commandLine.c_str()); // http://msdn.microsoft.com/en-us/library/windows/desktop/ms682499(v=vs.85).aspx SECURITY_ATTRIBUTES sa = {0}; sa.nLength = sizeof(sa); PROCESS_INFORMATION pi = {0}; STARTUPINFO si = {0}; si.cb = sizeof(STARTUPINFO); #define MAX_COMMAND 1024 // lenth of commandLine is always beyond MAX_PATH WCHAR command[MAX_COMMAND]; memset(command, 0, sizeof(command)); MultiByteToWideChar(CP_UTF8, 0, commandLine.c_str(), -1, command, MAX_COMMAND); BOOL success = CreateProcess(NULL, command, // command line NULL, // process security attributes NULL, // primary thread security attributes FALSE, // handles are inherited 0, // creation flags NULL, // use parent's environment NULL, // use parent's current directory &si, // STARTUPINFO pointer &pi); // receives PROCESS_INFORMATION if (!success) { CCLOG("PlayerTaskWin::run() - create process failed, for execute %s", commandLine.c_str()); } } void SimulatorWin::openProjectWithProjectConfig(const ProjectConfig &config) { openNewPlayerWithProjectConfig(config); quit(); } int SimulatorWin::getPositionX() { RECT rect; GetWindowRect(_hwnd, &rect); return rect.left; } int SimulatorWin::getPositionY() { RECT rect; GetWindowRect(_hwnd, &rect); return rect.top; } int SimulatorWin::run() { INITCOMMONCONTROLSEX InitCtrls; InitCtrls.dwSize = sizeof(InitCtrls); InitCtrls.dwICC = ICC_WIN95_CLASSES; InitCommonControlsEx(&InitCtrls); parseCocosProjectConfig(_project); // load project config from command line args vector args; for (int i = 0; i < __argc; ++i) { wstring ws(__wargv[i]); string s; s.assign(ws.begin(), ws.end()); args.push_back(s); } _project.parseCommandLine(args); if (_project.getProjectDir().empty()) { if (args.size() == 2) { // for Code IDE before RC2 _project.setProjectDir(args.at(1)); _project.setDebuggerType(kCCRuntimeDebuggerCodeIDE); } } // create the application instance _app = new AppDelegate(); RuntimeEngine::getInstance()->setProjectConfig(_project); // create console window if (_project.isShowConsole()) { AllocConsole(); _hwndConsole = GetConsoleWindow(); if (_hwndConsole != NULL) { ShowWindow(_hwndConsole, SW_SHOW); BringWindowToTop(_hwndConsole); freopen("CONOUT$", "wt", stdout); freopen("CONOUT$", "wt", stderr); HMENU hmenu = GetSystemMenu(_hwndConsole, FALSE); if (hmenu != NULL) { DeleteMenu(hmenu, SC_CLOSE, MF_BYCOMMAND); } } } // log file if (_project.isWriteDebugLogToFile()) { const string debugLogFilePath = _project.getDebugLogFilePath(); _writeDebugLogFile = fopen(debugLogFilePath.c_str(), "w"); if (!_writeDebugLogFile) { CCLOG("Cannot create debug log file %s", debugLogFilePath.c_str()); } } // set environments SetCurrentDirectoryA(_project.getProjectDir().c_str()); FileUtils::getInstance()->setDefaultResourceRootPath(_project.getProjectDir()); FileUtils::getInstance()->setWritablePath(_project.getWritableRealPath().c_str()); // check screen DPI HDC screen = GetDC(0); int dpi = GetDeviceCaps(screen, LOGPIXELSX); ReleaseDC(0, screen); // set scale with DPI // 96 DPI = 100 % scaling // 120 DPI = 125 % scaling // 144 DPI = 150 % scaling // 192 DPI = 200 % scaling // http://msdn.microsoft.com/en-us/library/windows/desktop/dn469266%28v=vs.85%29.aspx#dpi_and_the_desktop_scaling_factor // // enable DPI-Aware with DeclareDPIAware.manifest // http://msdn.microsoft.com/en-us/library/windows/desktop/dn469266%28v=vs.85%29.aspx#declaring_dpi_awareness float screenScale = 1.0f; if (dpi >= 120 && dpi < 144) { screenScale = 1.25f; } else if (dpi >= 144 && dpi < 192) { screenScale = 1.5f; } else if (dpi >= 192) { screenScale = 2.0f; } CCLOG("SCREEN DPI = %d, SCREEN SCALE = %0.2f", dpi, screenScale); // check scale Size frameSize = _project.getFrameSize(); float frameScale = 1.0f; if (_project.isRetinaDisplay()) { frameSize.width *= screenScale; frameSize.height *= screenScale; } else { frameScale = screenScale; } // check screen workarea RECT workareaSize; if (SystemParametersInfo(SPI_GETWORKAREA, NULL, &workareaSize, NULL)) { float workareaWidth = fabsf(workareaSize.right - workareaSize.left); float workareaHeight = fabsf(workareaSize.bottom - workareaSize.top); float frameBorderCX = GetSystemMetrics(SM_CXSIZEFRAME); float frameBorderCY = GetSystemMetrics(SM_CYSIZEFRAME); workareaWidth -= frameBorderCX * 2; workareaHeight -= (frameBorderCY * 2 + GetSystemMetrics(SM_CYCAPTION) + GetSystemMetrics(SM_CYMENU)); CCLOG("WORKAREA WIDTH %0.2f, HEIGHT %0.2f", workareaWidth, workareaHeight); while (true && frameScale > 0.25f) { if (frameSize.width * frameScale > workareaWidth || frameSize.height * frameScale > workareaHeight) { frameScale = frameScale - 0.25f; } else { break; } } if (frameScale < 0.25f) frameScale = 0.25f; } _project.setFrameScale(frameScale); CCLOG("FRAME SCALE = %0.2f", frameScale); // create opengl view const Rect frameRect = Rect(0, 0, frameSize.width, frameSize.height); ConfigParser::getInstance()->setInitViewSize(frameSize); const bool isResize = _project.isResizeWindow(); std::stringstream title; title << "Cocos Simulator (" << _project.getFrameScale() * 100 << "%)"; initGLContextAttrs(); auto glview = GLViewImpl::createWithRect(title.str(), frameRect, frameScale); _hwnd = glview->getWin32Window(); player::PlayerWin::createWithHwnd(_hwnd); DragAcceptFiles(_hwnd, TRUE); //SendMessage(_hwnd, WM_SETICON, ICON_BIG, (LPARAM)icon); //SendMessage(_hwnd, WM_SETICON, ICON_SMALL, (LPARAM)icon); //FreeResource(icon); // path for looking Lang file, Studio Default images FileUtils::getInstance()->addSearchPath(getApplicationPath().c_str()); auto director = Director::getInstance(); director->setOpenGLView(glview); director->setAnimationInterval(1.0 / 60.0); // set window position if (_project.getProjectDir().length()) { setZoom(_project.getFrameScale()); } Vec2 pos = _project.getWindowOffset(); if (pos.x != 0 && pos.y != 0) { RECT rect; GetWindowRect(_hwnd, &rect); if (pos.x < 0) pos.x = 0; if (pos.y < 0) pos.y = 0; MoveWindow(_hwnd, pos.x, pos.y, rect.right - rect.left, rect.bottom - rect.top, FALSE); } // init player services setupUI(); DrawMenuBar(_hwnd); // prepare FileUtils::getInstance()->setPopupNotify(false); _project.dump(); auto app = Application::getInstance(); g_oldWindowProc = (WNDPROC)SetWindowLong(_hwnd, GWL_WNDPROC, (LONG)SimulatorWin::windowProc); // update window title updateWindowTitle(); // startup message loop int ret = app->run(); CC_SAFE_DELETE(_app); return ret; } // services void SimulatorWin::setupUI() { auto menuBar = player::PlayerProtocol::getInstance()->getMenuService(); // FILE menuBar->addItem("FILE_MENU", tr("File")); menuBar->addItem("OPEN_FILE_MENU", tr("Open File") + "...", "FILE_MENU"); menuBar->addItem("OPEN_PROJECT_MENU", tr("Open Project") + "...", "FILE_MENU"); menuBar->addItem("FILE_MENU_SEP1", "-", "FILE_MENU"); menuBar->addItem("EXIT_MENU", tr("Exit"), "FILE_MENU"); // VIEW menuBar->addItem("VIEW_MENU", tr("View")); SimulatorConfig *config = SimulatorConfig::getInstance(); int current = config->checkScreenSize(_project.getFrameSize()); for (int i = 0; i < config->getScreenSizeCount(); i++) { SimulatorScreenSize size = config->getScreenSize(i); std::stringstream menuId; menuId << "VIEWSIZE_ITEM_MENU_" << i; auto menuItem = menuBar->addItem(menuId.str(), size.title.c_str(), "VIEW_MENU"); if (i == current) { menuItem->setChecked(true); } } // About menuBar->addItem("HELP_MENU", tr("Help")); menuBar->addItem("ABOUT_MENUITEM", tr("About"), "HELP_MENU"); menuBar->addItem("DIRECTION_MENU_SEP", "-", "VIEW_MENU"); menuBar->addItem("DIRECTION_PORTRAIT_MENU", tr("Portrait"), "VIEW_MENU") ->setChecked(_project.isPortraitFrame()); menuBar->addItem("DIRECTION_LANDSCAPE_MENU", tr("Landscape"), "VIEW_MENU") ->setChecked(_project.isLandscapeFrame()); menuBar->addItem("VIEW_SCALE_MENU_SEP", "-", "VIEW_MENU"); std::vector scaleMenuVector; auto scale200Menu = menuBar->addItem("VIEW_SCALE_MENU_200", tr("Zoom Out").append(" (200%)"), "VIEW_MENU"); auto scale175Menu = menuBar->addItem("VIEW_SCALE_MENU_175", tr("Zoom Out").append(" (175%)"), "VIEW_MENU"); auto scale150Menu = menuBar->addItem("VIEW_SCALE_MENU_150", tr("Zoom Out").append(" (150%)"), "VIEW_MENU"); auto scale125Menu = menuBar->addItem("VIEW_SCALE_MENU_125", tr("Zoom Out").append(" (125%)"), "VIEW_MENU"); auto scale100Menu = menuBar->addItem("VIEW_SCALE_MENU_100", tr("Zoom Out").append(" (100%)"), "VIEW_MENU"); auto scale75Menu = menuBar->addItem("VIEW_SCALE_MENU_75", tr("Zoom Out").append(" (75%)"), "VIEW_MENU"); auto scale50Menu = menuBar->addItem("VIEW_SCALE_MENU_50", tr("Zoom Out").append(" (50%)"), "VIEW_MENU"); auto scale25Menu = menuBar->addItem("VIEW_SCALE_MENU_25", tr("Zoom Out").append(" (25%)"), "VIEW_MENU"); int frameScale = int(_project.getFrameScale() * 100); if (frameScale == 200) { scale200Menu->setChecked(true); } else if (frameScale == 175) { scale175Menu->setChecked(true); } else if (frameScale == 150) { scale150Menu->setChecked(true); } else if (frameScale == 125) { scale125Menu->setChecked(true); } else if (frameScale == 100) { scale100Menu->setChecked(true); } else if (frameScale == 75) { scale75Menu->setChecked(true); } else if (frameScale == 50) { scale50Menu->setChecked(true); } else if (frameScale == 25) { scale25Menu->setChecked(true); } else { scale100Menu->setChecked(true); } scaleMenuVector.push_back(scale200Menu); scaleMenuVector.push_back(scale175Menu); scaleMenuVector.push_back(scale150Menu); scaleMenuVector.push_back(scale125Menu); scaleMenuVector.push_back(scale100Menu); scaleMenuVector.push_back(scale75Menu); scaleMenuVector.push_back(scale50Menu); scaleMenuVector.push_back(scale25Menu); menuBar->addItem("REFRESH_MENU_SEP", "-", "VIEW_MENU"); menuBar->addItem("REFRESH_MENU", tr("Refresh"), "VIEW_MENU"); HWND &hwnd = _hwnd; ProjectConfig &project = _project; auto dispatcher = Director::getInstance()->getEventDispatcher(); dispatcher->addEventListenerWithFixedPriority(EventListenerCustom::create("APP.EVENT", [&project, &hwnd, scaleMenuVector](EventCustom* event){ auto menuEvent = dynamic_cast(event); if (menuEvent) { rapidjson::Document dArgParse; dArgParse.Parse<0>(menuEvent->getDataString().c_str()); if (dArgParse.HasMember("name")) { string strcmd = dArgParse["name"].GetString(); if (strcmd == "menuClicked") { player::PlayerMenuItem *menuItem = static_cast(menuEvent->getUserData()); if (menuItem) { if (menuItem->isChecked()) { return; } string data = dArgParse["data"].GetString(); if ((data == "CLOSE_MENU") || (data == "EXIT_MENU")) { _instance->quit(); } else if (data == "REFRESH_MENU") { _instance->relaunch(); } else if (data.find("VIEW_SCALE_MENU_") == 0) // begin with VIEW_SCALE_MENU_ { string tmp = data.erase(0, strlen("VIEW_SCALE_MENU_")); float scale = atof(tmp.c_str()) / 100.0f; project.setFrameScale(scale); _instance->setZoom(scale); // update scale menu state for (auto &it : scaleMenuVector) { it->setChecked(false); } menuItem->setChecked(true); // update window title _instance->updateWindowTitle(); // update window size RECT rect; GetWindowRect(hwnd, &rect); MoveWindow(hwnd, rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top + GetSystemMetrics(SM_CYMENU), FALSE); // fix: can not update window on some windows system ::SendMessage(hwnd, WM_MOVE, NULL, NULL); } else if (data.find("VIEWSIZE_ITEM_MENU_") == 0) // begin with VIEWSIZE_ITEM_MENU_ { string tmp = data.erase(0, strlen("VIEWSIZE_ITEM_MENU_")); int index = atoi(tmp.c_str()); SimulatorScreenSize size = SimulatorConfig::getInstance()->getScreenSize(index); if (project.isLandscapeFrame()) { std::swap(size.width, size.height); } project.setFrameSize(cocos2d::Size(size.width, size.height)); project.setWindowOffset(cocos2d::Vec2(_instance->getPositionX(), _instance->getPositionY())); _instance->openProjectWithProjectConfig(project); } else if (data == "DIRECTION_PORTRAIT_MENU") { project.changeFrameOrientationToPortait(); _instance->openProjectWithProjectConfig(project); } else if (data == "DIRECTION_LANDSCAPE_MENU") { project.changeFrameOrientationToLandscape(); _instance->openProjectWithProjectConfig(project); } else if (data == "OPEN_FILE_MENU") { auto fileDialog = player::PlayerProtocol::getInstance()->getFileDialogService(); stringstream extensions; extensions << "All Support File|config.json,*.csd,*csd;" << "Project Config File|config.json;" << "Cocos Studio File|*.csd;" << "Cocos Studio Binary File|*.csb"; auto entry = fileDialog->openFile(tr("Choose File"), "", extensions.str()); _instance->onOpenFile(entry); } else if (data == "OPEN_PROJECT_MENU") { auto fileDialog = player::PlayerProtocol::getInstance()->getFileDialogService(); auto path = fileDialog->openDirectory(tr("Choose Folder"), ""); _instance->onOpenProjectFolder(path); } else if (data == "ABOUT_MENUITEM") { onHelpAbout(); } } } } } }), 1); AppDelegate *app = _app; auto listener = EventListenerCustom::create(kAppEventDropName, [&project, app](EventCustom* event) { AppEvent *dropEvent = dynamic_cast(event); if (dropEvent) { string dirPath = dropEvent->getDataString() + "/"; string configFilePath = dirPath + CONFIG_FILE; if (FileUtils::getInstance()->isDirectoryExist(dirPath) && FileUtils::getInstance()->isFileExist(configFilePath)) { // parse config.json ConfigParser::getInstance()->readConfig(configFilePath); project.setProjectDir(dirPath); project.setScriptFile(ConfigParser::getInstance()->getEntryFile()); project.setWritablePath(dirPath); RuntimeEngine::getInstance()->setProjectConfig(project); } } }); dispatcher->addEventListenerWithFixedPriority(listener, 1); } void SimulatorWin::setZoom(float frameScale) { _project.setFrameScale(frameScale); cocos2d::Director::getInstance()->getOpenGLView()->setFrameZoomFactor(frameScale); } void SimulatorWin::updateWindowTitle() { std::stringstream title; title << "Cocos " << tr("Simulator") << " (" << _project.getFrameScale() * 100 << "%)"; std::u16string u16title; cocos2d::StringUtils::UTF8ToUTF16(title.str(), u16title); SetWindowText(_hwnd, (LPCTSTR)u16title.c_str()); } // debug log void SimulatorWin::writeDebugLog(const char *log) { if (!_writeDebugLogFile) return; fputs(log, _writeDebugLogFile); fputc('\n', _writeDebugLogFile); fflush(_writeDebugLogFile); } void SimulatorWin::parseCocosProjectConfig(ProjectConfig &config) { // get project directory ProjectConfig tmpConfig; // load project config from command line args vector args; for (int i = 0; i < __argc; ++i) { wstring ws(__wargv[i]); string s; s.assign(ws.begin(), ws.end()); args.push_back(s); } if (args.size() >= 2) { if (args.size() && args.at(1).at(0) == '/') { // FIXME: // for Code IDE before RC2 tmpConfig.setProjectDir(args.at(1)); } tmpConfig.parseCommandLine(args); } // set project directory as search root path string solutionDir = tmpConfig.getProjectDir(); if (!solutionDir.empty()) { for (int i = 0; i < solutionDir.size(); ++i) { if (solutionDir[i] == '\\') { solutionDir[i] = '/'; } } int nPos = -1; if (solutionDir[solutionDir.length() - 1] == '/') nPos = solutionDir.rfind('/', solutionDir.length() - 2); else nPos = solutionDir.rfind('/'); if (nPos > 0) solutionDir = solutionDir.substr(0, nPos + 1); FileUtils::getInstance()->setDefaultResourceRootPath(solutionDir); FileUtils::getInstance()->addSearchPath(solutionDir); FileUtils::getInstance()->addSearchPath(tmpConfig.getProjectDir().c_str()); } else { FileUtils::getInstance()->setDefaultResourceRootPath(tmpConfig.getProjectDir().c_str()); } // parse config.json auto parser = ConfigParser::getInstance(); auto configPath = solutionDir.append(CONFIG_FILE); parser->readConfig(configPath); // set information config.setConsolePort(parser->getConsolePort()); config.setFileUploadPort(parser->getUploadPort()); config.setFrameSize(parser->getInitViewSize()); if (parser->isLanscape()) { config.changeFrameOrientationToLandscape(); } else { config.changeFrameOrientationToPortait(); } config.setScriptFile(parser->getEntryFile()); } // // D:\aaa\bbb\ccc\ddd\abc.txt --> D:/aaa/bbb/ccc/ddd/abc.txt // std::string SimulatorWin::convertPathFormatToUnixStyle(const std::string& path) { std::string ret = path; int len = ret.length(); for (int i = 0; i < len; ++i) { if (ret[i] == '\\') { ret[i] = '/'; } } return ret; } // // @return: C:/Users/win8/Documents/ // std::string SimulatorWin::getUserDocumentPath() { TCHAR filePath[MAX_PATH]; SHGetSpecialFolderPath(NULL, filePath, CSIDL_PERSONAL, FALSE); int length = 2 * wcslen(filePath); char* tempstring = new char[length + 1]; wcstombs(tempstring, filePath, length + 1); string userDocumentPath(tempstring); delete [] tempstring; userDocumentPath = convertPathFormatToUnixStyle(userDocumentPath); userDocumentPath.append("/"); return userDocumentPath; } // // convert Unicode/LocalCode TCHAR to Utf8 char // char* SimulatorWin::convertTCharToUtf8(const TCHAR* src) { #ifdef UNICODE WCHAR* tmp = (WCHAR*)src; size_t size = wcslen(src) * 3 + 1; char* dest = new char[size]; memset(dest, 0, size); WideCharToMultiByte(CP_UTF8, 0, tmp, -1, dest, size, NULL, NULL); return dest; #else char* tmp = (char*)src; uint32 size = strlen(tmp) + 1; WCHAR* dest = new WCHAR[size]; memset(dest, 0, sizeof(WCHAR)*size); MultiByteToWideChar(CP_ACP, 0, src, -1, dest, (int)size); // convert local code to unicode. size = wcslen(dest) * 3 + 1; char* dest2 = new char[size]; memset(dest2, 0, size); WideCharToMultiByte(CP_UTF8, 0, dest, -1, dest2, size, NULL, NULL); // convert unicode to utf8. delete[] dest; return dest2; #endif } // std::string SimulatorWin::getApplicationExePath() { TCHAR szFileName[MAX_PATH]; GetModuleFileName(NULL, szFileName, MAX_PATH); std::u16string u16ApplicationName; char *applicationExePath = convertTCharToUtf8(szFileName); std::string path(applicationExePath); CC_SAFE_FREE(applicationExePath); return path; } std::string SimulatorWin::getApplicationPath() { std::string path = getApplicationExePath(); size_t pos; while ((pos = path.find_first_of("\\")) != std::string::npos) { path.replace(pos, 1, "/"); } size_t p = path.find_last_of("/"); string workdir; if (p != path.npos) { workdir = path.substr(0, p); } return workdir; } LRESULT CALLBACK SimulatorWin::windowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { if (!_instance) return 0; switch (uMsg) { case WM_SYSCOMMAND: case WM_COMMAND: { if (HIWORD(wParam) == 0) { // menu WORD menuId = LOWORD(wParam); auto menuService = dynamic_cast (player::PlayerProtocol::getInstance()->getMenuService()); auto menuItem = menuService->getItemByCommandId(menuId); if (menuItem) { AppEvent event("APP.EVENT", APP_EVENT_MENU); std::stringstream buf; buf << "{\"data\":\"" << menuItem->getMenuId().c_str() << "\""; buf << ",\"name\":" << "\"menuClicked\"" << "}"; event.setDataString(buf.str()); event.setUserData(menuItem); Director::getInstance()->getEventDispatcher()->dispatchEvent(&event); } if (menuId == ID_HELP_ABOUT) { onHelpAbout(); } } break; } case WM_KEYDOWN: { if (wParam == VK_F5) { _instance->relaunch(); } break; } case WM_COPYDATA: { PCOPYDATASTRUCT pMyCDS = (PCOPYDATASTRUCT)lParam; if (pMyCDS->dwData == 1) { const char *szBuf = (const char*)(pMyCDS->lpData); SimulatorWin::getInstance()->writeDebugLog(szBuf); break; } } case WM_DESTROY: { DragAcceptFiles(hWnd, FALSE); break; } case WM_DROPFILES: { HDROP hDrop = (HDROP)wParam; const int count = DragQueryFileW(hDrop, 0xffffffff, NULL, 0); if (count > 0) { int fileIndex = 0; const UINT length = DragQueryFileW(hDrop, fileIndex, NULL, 0); WCHAR* buffer = (WCHAR*)calloc(length + 1, sizeof(WCHAR)); DragQueryFileW(hDrop, fileIndex, buffer, length + 1); char *utf8 = SimulatorWin::convertTCharToUtf8(buffer); std::string firstFile(utf8); CC_SAFE_FREE(utf8); DragFinish(hDrop); _instance->onDrop(firstFile); } } // WM_DROPFILES } return g_oldWindowProc(hWnd, uMsg, wParam, lParam); } void SimulatorWin::onOpenFile(const std::string &filePath) { string entry = filePath; if (entry.empty()) return; if (stringEndWith(entry, "config.json") || stringEndWith(entry, ".csb") || stringEndWith(entry, ".csd")) { replaceAll(entry, "\\", "/"); size_t p = entry.find_last_of("/"); if (p != entry.npos) { string workdir = entry.substr(0, p); _project.setProjectDir(workdir); } _project.setScriptFile(entry); if (stringEndWith(entry, CONFIG_FILE)) { ConfigParser::getInstance()->readConfig(entry); _project.setScriptFile(ConfigParser::getInstance()->getEntryFile()); } openProjectWithProjectConfig(_project); } else { auto title = tr("Open File") + tr("Error"); auto msg = tr("Only support") + " config.json;*.csb;*.csd"; auto msgBox = player::PlayerProtocol::getInstance()->getMessageBoxService(); msgBox->showMessageBox(title, msg); } } /* 1. find @folderPath/config.json 2. get project name from file: @folderPath/folderName.ccs 3. find @folderPath/cocosstudio/MainScene.csd 4. find @folderPath/cocosstudio/MainScene.csb */ void SimulatorWin::onOpenProjectFolder(const std::string &folderPath) { string path = folderPath; if (!path.empty()) { replaceAll(path, "\\", "/"); auto fileUtils = FileUtils::getInstance(); bool foundProjectFile = false; // 1. check config.json auto configPath = path + "/" + CONFIG_FILE; if (fileUtils->isFileExist(configPath)) { ConfigParser::getInstance()->readConfig(configPath); _project.setProjectDir(path); _project.setScriptFile(ConfigParser::getInstance()->getEntryFile()); foundProjectFile = true; } // check ccs project else { // 2. if (path.at(path.size() - 1) == '/') path.erase(path.size() - 1); ssize_t pos = path.find_last_of('/'); if (pos != std::string::npos) { auto folderName = path.substr(path.find_last_of('/'), path.size()); auto ccsFilePath = path + folderName + ".ccs"; if (fileUtils->isFileExist(ccsFilePath)) { auto fileContent = fileUtils->getStringFromFile(ccsFilePath); string matchString("isFileExist(csdFilePath)) { _project.setProjectDir(path); _project.setScriptFile(csdFilePath); foundProjectFile = true; } // 4. else if (fileUtils->isFileExist(csbFilePath)) { _project.setProjectDir(path); _project.setScriptFile(csbFilePath); foundProjectFile = true; } } } if (foundProjectFile) { openProjectWithProjectConfig(_project); } else { auto title = tr("Open Project") + tr("Error"); auto msgBox = player::PlayerProtocol::getInstance()->getMessageBoxService(); msgBox->showMessageBox(title, tr("Can not find project")); } } } void SimulatorWin::onDrop(const std::string &path) { auto fileUtils = FileUtils::getInstance(); if (fileUtils->isDirectoryExist(path)) { onOpenProjectFolder(path); } else if (fileUtils->isFileExist(path)) { onOpenFile(path); } }