// Program entry point function. int APIENTRY wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPTSTR lpCmdLine, int nCmdShow) { UNREFERENCED_PARAMETER(hPrevInstance); UNREFERENCED_PARAMETER(lpCmdLine); g_appStartupTime = timeGetTime(); CefMainArgs main_args(hInstance); CefRefPtr<ClientApp> app(new ClientApp); // Execute the secondary process, if any. int exit_code = CefExecuteProcess(main_args, app.get(), NULL); if (exit_code >= 0) return exit_code; // Retrieve the current working directory. if (_getcwd(szWorkingDir, MAX_UNC_PATH) == NULL) szWorkingDir[0] = 0; // Parse command line arguments. The passed in values are ignored on Windows. AppInitCommandLine(0, NULL); // Determine if we should use an already running instance of Brackets. HANDLE hMutex = ::OpenMutex(MUTEX_ALL_ACCESS, FALSE, FIRST_INSTANCE_MUTEX_NAME); if ((hMutex != NULL) && AppGetCommandLine()->HasArguments() && (lpCmdLine != NULL)) { // for subsequent instances, re-use an already running instance if we're being called to // open an existing file on the command-line (eg. Open With.. from Windows Explorer) HWND hFirstInstanceWnd = cef_main_window::FindFirstTopLevelInstance(); if (hFirstInstanceWnd != NULL) { ::SetForegroundWindow(hFirstInstanceWnd); if (::IsIconic(hFirstInstanceWnd)) ::ShowWindow(hFirstInstanceWnd, SW_RESTORE); // message the other Brackets instance to actually open the given filename std::wstring wstrFilename = lpCmdLine; ConvertToUnixPath(wstrFilename); // note: WM_COPYDATA will manage passing the string across process space COPYDATASTRUCT data; data.dwData = ID_WM_COPYDATA_SENDOPENFILECOMMAND; data.cbData = (wstrFilename.length() + 1) * sizeof(WCHAR); data.lpData = (LPVOID)wstrFilename.c_str(); ::SendMessage(hFirstInstanceWnd, WM_COPYDATA, (WPARAM)(HWND)hFirstInstanceWnd, (LPARAM)(LPVOID)&data); // exit this instance return 0; } // otherwise, fall thru and launch a new instance } if (hMutex == NULL) { // first instance of this app, so create the mutex and continue execution of this instance. hMutex = ::CreateMutex(NULL, FALSE, FIRST_INSTANCE_MUTEX_NAME); } CefSettings settings; // Populate the settings based on command line arguments. AppGetSettings(settings, app); // Check command if (CefString(&settings.cache_path).length() == 0) { CefString(&settings.cache_path) = AppGetCachePath(); } // Initialize CEF. CefInitialize(main_args, settings, app.get(), NULL); CefRefPtr<CefCommandLine> cmdLine = AppGetCommandLine(); if (cmdLine->HasSwitch(cefclient::kStartupPath)) { wcscpy(szInitialUrl, cmdLine->GetSwitchValue(cefclient::kStartupPath).c_str()); } else { // If the shift key is not pressed, look for the index.html file if (GetAsyncKeyState(VK_SHIFT) == 0) { // Get the full pathname for the app. We look for the index.html // file relative to this location. wchar_t appPath[MAX_UNC_PATH]; wchar_t *pathRoot; GetModuleFileName(NULL, appPath, MAX_UNC_PATH); // Strip the .exe filename (and preceding "\") from the appPath // and store in pathRoot pathRoot = wcsrchr(appPath, '\\'); // Look for .\dev\src\index.html first wcscpy(pathRoot, L"\\dev\\src\\index.html"); // If the file exists, use it if (GetFileAttributes(appPath) != INVALID_FILE_ATTRIBUTES) { wcscpy(szInitialUrl, appPath); } if (!wcslen(szInitialUrl)) { // Look for .\www\index.html next wcscpy(pathRoot, L"\\www\\index.html"); if (GetFileAttributes(appPath) != INVALID_FILE_ATTRIBUTES) { wcscpy(szInitialUrl, appPath); } } } } if (!wcslen(szInitialUrl)) { // If we got here, either the startup file couldn't be found, or the user pressed the // shift key while launching. Prompt to select the index.html file. OPENFILENAME ofn = {0}; ofn.lStructSize = sizeof(ofn); ofn.lpstrFile = szInitialUrl; ofn.nMaxFile = MAX_UNC_PATH; ofn.lpstrFilter = L"Web Files\0*.htm;*.html\0\0"; ofn.lpstrTitle = L"Please select the " APP_NAME L" index.html file."; ofn.Flags = OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST | OFN_NOCHANGEDIR | OFN_EXPLORER; if (!GetOpenFileName(&ofn)) { // User cancelled, exit the app CefShutdown(); return 0; } } // Perform application initialization if (!InitInstance (hInstance, nCmdShow)) return FALSE; // Start the node server process startNodeProcess(); gFilesToOpen = GetFilenamesFromCommandLine(); int result = 0; if (!settings.multi_threaded_message_loop) { // Run the CEF message loop. This function will block until the application // recieves a WM_QUIT message. CefRunMessageLoop(); } else { MSG msg; // Run the application message loop. while (GetMessage(&msg, NULL, 0, 0)) { if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg)) { TranslateMessage(&msg); DispatchMessage(&msg); } } result = static_cast<int>(msg.wParam); } OnBeforeShutdown(); // Shut down CEF. CefShutdown(); // release the first instance mutex if (hMutex != NULL) ReleaseMutex(hMutex); return result; }
int32 ShowOpenDialog(bool allowMultipleSelection, bool chooseDirectory, ExtensionString title, ExtensionString initialDirectory, ExtensionString fileTypes, CefRefPtr<CefListValue>& selectedFiles) { wchar_t szFile[MAX_PATH]; szFile[0] = 0; // TODO (issue #64) - This method should be using IFileDialog instead of the /* outdated SHGetPathFromIDList and GetOpenFileName. Useful function to parse fileTypesStr: template<class T> int inline findAndReplaceString(T& source, const T& find, const T& replace) { int num=0; int fLen = find.size(); int rLen = replace.size(); for (int pos=0; (pos=source.find(find, pos))!=T::npos; pos+=rLen) { num++; source.replace(pos, fLen, replace); } return num; } */ // SHBrowseForFolder can handle Windows path only, not Unix path. // ofn.lpstrInitialDir also needs Windows path on XP and not Unix path. ConvertToNativePath(initialDirectory); if (chooseDirectory) { BROWSEINFO bi = {0}; bi.hwndOwner = GetActiveWindow(); bi.lpszTitle = title.c_str(); bi.ulFlags = BIF_NEWDIALOGSTYLE; bi.lpfn = SetInitialPathCallback; bi.lParam = (LPARAM)initialDirectory.c_str(); LPITEMIDLIST pidl = SHBrowseForFolder(&bi); if (pidl != 0) { if (SHGetPathFromIDList(pidl, szFile)) { // Add directory path to the result ExtensionString pathName(szFile); ConvertToUnixPath(pathName); selectedFiles->SetString(0, pathName); } IMalloc* pMalloc = NULL; SHGetMalloc(&pMalloc); if (pMalloc) { pMalloc->Free(pidl); pMalloc->Release(); } } } else { OPENFILENAME ofn; ZeroMemory(&ofn, sizeof(ofn)); ofn.hwndOwner = GetActiveWindow(); ofn.lStructSize = sizeof(ofn); ofn.lpstrFile = szFile; ofn.nMaxFile = MAX_PATH; // TODO (issue #65) - Use passed in file types. Note, when fileTypesStr is null, all files should be shown /* findAndReplaceString( fileTypesStr, std::string(" "), std::string(";*.")); LPCWSTR allFilesFilter = L"All Files\0*.*\0\0";*/ ofn.lpstrFilter = L"All Files\0*.*\0Web Files\0*.js;*.css;*.htm;*.html\0\0"; ofn.lpstrInitialDir = initialDirectory.c_str(); ofn.Flags = OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST | OFN_NOCHANGEDIR | OFN_EXPLORER; if (allowMultipleSelection) ofn.Flags |= OFN_ALLOWMULTISELECT; if (GetOpenFileName(&ofn)) { if (allowMultipleSelection) { // Multiple selection encodes the files differently // If multiple files are selected, the first null terminator // signals end of directory that the files are all in std::wstring dir(szFile); // Check for two null terminators, which signal that only one file // was selected if (szFile[dir.length() + 1] == '\0') { ExtensionString filePath(dir); ConvertToUnixPath(filePath); selectedFiles->SetString(0, filePath); } else { // Multiple files are selected wchar_t fullPath[MAX_PATH]; for (int i = (dir.length() + 1), fileIndex = 0; ; fileIndex++) { // Get the next file name std::wstring file(&szFile[i]); // Two adjacent null characters signal the end of the files if (file.length() == 0) break; // The filename is relative to the directory that was specified as // the first string if (PathCombine(fullPath, dir.c_str(), file.c_str()) != NULL) { ExtensionString filePath(fullPath); ConvertToUnixPath(filePath); selectedFiles->SetString(fileIndex, filePath); } // Go to the start of the next file name i += file.length() + 1; } } } else { // If multiple files are not allowed, add the single file selectedFiles->SetString(0, szFile); } } } return NO_ERROR; }