/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ /* ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1/GPL 2.0/LGPL 2.1 * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * The Original Code is mozilla.org code. * * The Initial Developer of the Original Code is * Netscape Communications Corporation. * Portions created by the Initial Developer are Copyright (C) 1998 * the Initial Developer. All Rights Reserved. * * Contributor(s): * * Alternatively, the contents of this file may be used under the terms of * either of the GNU General Public License Version 2 or later (the "GPL"), * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), * in which case the provisions of the GPL or the LGPL are applicable instead * of those above. If you wish to allow use of your version of this file only * under the terms of either the GPL or the LGPL, and not to allow others to * use your version of this file under the terms of the MPL, indicate your * decision by deleting the provisions above and replace them with the notice * and other provisions required by the GPL or the LGPL. If you do not delete * the provisions above, a recipient may use your version of this file under * the terms of any one of the MPL, the GPL or the LGPL. * * ***** END LICENSE BLOCK ***** */ //is case this is defined from the outside... MMP #ifdef WIN32_LEAN_AND_MEAN #undef WIN32_LEAN_AND_MEAN #endif #include "JSConsole.h" #include "jsconsres.h" #include "nsIScriptContext.h" #include #include "jsapi.h" #include "nsReadableUtils.h" HINSTANCE JSConsole::sAppInstance = 0; HACCEL JSConsole::sAccelTable = 0; CHAR JSConsole::sDefaultCaption[] = "JavaScript Console"; BOOL JSConsole::mRegistered = FALSE; // display an error string along with the error returned from // the GetLastError functions #define MESSAGE_LENGTH 256 void DisplayError(LPSTR lpMessage) { CHAR lpMsgBuf[MESSAGE_LENGTH * 2]; CHAR lpLastError[MESSAGE_LENGTH]; ::FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, NULL, GetLastError(), 0, (LPTSTR)&lpLastError, MESSAGE_LENGTH, NULL); strcpy(lpMsgBuf, lpMessage); strcat(lpMsgBuf, "\nThe WWS (Worthless Windows System) reports:\n"); strcat(lpMsgBuf, lpLastError); // Display the string. ::MessageBox(NULL, lpMsgBuf, "JSConsole Error", MB_OK | MB_ICONSTOP); } #if defined(_DEBUG) #define VERIFY(value, errorCondition, message) \ if((value) == (errorCondition)) DisplayError(message); #else // !_DEBUG #define VERIFY(value, errorCondition, message) (value) #endif // _DEBUG // // Register the window class // BOOL JSConsole::RegisterWidget() { WNDCLASS wc; wc.style = 0; wc.lpfnWndProc = JSConsole::WindowProc; wc.cbClsExtra = 0; wc.cbWndExtra = 0; wc.hInstance = JSConsole::sAppInstance; wc.hIcon = NULL; wc.hCursor = NULL; wc.hbrBackground = (HBRUSH)(COLOR_WINDOW); wc.lpszMenuName = MAKEINTRESOURCE(JSCONSOLE_MENU); wc.lpszClassName = "JavaScript Console"; return (BOOL)::RegisterClass(&wc); } // // Create the main application window // JSConsole* JSConsole::CreateConsole() { if (!JSConsole::mRegistered){ JSConsole::mRegistered = RegisterWidget(); } HWND hWnd = ::CreateWindowEx(WS_EX_ACCEPTFILES | WS_EX_CLIENTEDGE | WS_EX_CONTROLPARENT, "JavaScript Console", JSConsole::sDefaultCaption, WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, 450, 500, NULL, NULL, JSConsole::sAppInstance, NULL); if (hWnd) { ::ShowWindow(hWnd, SW_SHOW); ::UpdateWindow(hWnd); JSConsole *console = (JSConsole*)::GetWindowLong(hWnd, GWL_USERDATA); return console; } return NULL; } // // Window Procedure // LRESULT CALLBACK JSConsole::WindowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { JSConsole *console = (JSConsole*)::GetWindowLong(hWnd, GWL_USERDATA); // just ignore the message unless is WM_NCCREATE if (!console) { if (uMsg == WM_NCCREATE) { HWND hWndEdit = ::CreateWindow("EDIT", NULL, WS_CHILDWINDOW | WS_VISIBLE | ES_MULTILINE | ES_AUTOHSCROLL | ES_AUTOVSCROLL | WS_HSCROLL | WS_VSCROLL, 0, 0, 0, 0, hWnd, NULL, JSConsole::sAppInstance, NULL); if (!hWndEdit) { ::DisplayError("Cannot Create Edit Window"); return FALSE; } ::SendMessage(hWndEdit, EM_SETLIMITTEXT, (WPARAM)0, (LPARAM)0); console = new JSConsole(hWnd, hWndEdit); ::SetWindowLong(hWnd, GWL_USERDATA, (DWORD)console); ::SetFocus(hWndEdit); } #if defined(STRICT) return ::CallWindowProc((WNDPROC)::DefWindowProc, hWnd, uMsg, wParam, lParam); #else return ::CallWindowProc((FARPROC)::DefWindowProc, hWnd, uMsg, wParam, lParam); #endif /* STRICT */ } switch(uMsg) { // make sure the edit window covers the whole client area case WM_SIZE: return console->OnSize(wParam, (UINT)LOWORD(lParam), (UINT)HIWORD(lParam)); // exit the application case WM_DESTROY: console->OnDestroy(); #if defined(STRICT) return ::CallWindowProc((WNDPROC)::DefWindowProc, hWnd, uMsg, wParam, lParam); #else return ::CallWindowProc((FARPROC)::DefWindowProc, hWnd, uMsg, wParam, lParam); #endif /* STRICT */ // enable/disable menu items case WM_INITMENUPOPUP: return console->OnInitMenu((HMENU)wParam, (UINT)LOWORD(lParam), (BOOL)HIWORD(lParam)); case WM_COMMAND: // menu or accelerator if (HIWORD(wParam) == 0 || HIWORD(wParam) == 1) { switch(LOWORD(wParam)) { case ID_FILENEW: console->OnFileNew(); break; case ID_FILEOPEN: if (console->OpenFileDialog(OPEN_DIALOG)) { console->LoadFile(); } break; case ID_FILESAVE: if (console->CanSave()) { console->SaveFile(); break; } // fall through so it can "Save As..." case ID_FILESAVEAS: if (console->OpenFileDialog(SAVE_DIALOG)) { console->SaveFile(); } break; case ID_FILEEXIT: ::DestroyWindow(hWnd); break; case ID_EDITUNDO: console->OnEditUndo(); break; case ID_EDITCUT: console->OnEditCut(); break; case ID_EDITCOPY: console->OnEditCopy(); break; case ID_EDITPASTE: console->OnEditPaste(); break; case ID_EDITDELETE: console->OnEditDelete(); break; case ID_EDITSELECTALL: console->OnEditSelectAll(); break; case ID_COMMANDSEVALALL: console->OnCommandEvaluateAll(); break; case ID_COMMANDSEVALSEL: console->OnCommandEvaluateSelection(); break; case ID_COMMANDSINSPECTOR: console->OnCommandInspector(); break; } } break; case WM_DROPFILES: { HDROP hDropInfo = (HDROP)wParam; if (::DragQueryFile(hDropInfo, (UINT)-1L, NULL, 0) != 1) { ::MessageBox(hWnd, "Just One File Please...", "JSConsole Error", MB_OK | MB_ICONINFORMATION); } else { CHAR fileName[MAX_PATH]; ::DragQueryFile(hDropInfo, 0, fileName, MAX_PATH); console->SetFileName(fileName); console->LoadFile(); } break; } case WM_SETFOCUS: return console->OnSetFocus((HWND)wParam); default: #if defined(STRICT) return ::CallWindowProc((WNDPROC)::DefWindowProc, hWnd, uMsg, wParam, lParam); #else return ::CallWindowProc((FARPROC)::DefWindowProc, hWnd, uMsg, wParam, lParam); #endif /* STRICT */ } return 0; } // // Constructor // The main window and the edit control must have been created already // JSConsole::JSConsole(HWND aMainWindow, HWND aEditControl) : mMainWindow(aMainWindow), mEditWindow(aEditControl), mContext(NULL) { mFileInfo.Init(); } // // Destructor // JSConsole::~JSConsole() { NS_IF_RELEASE(mContext); } // // Load a file into the edit field // BOOL JSConsole::LoadFile() { BOOL result = FALSE; if (mMainWindow) { // open the file HANDLE file = ::CreateFile(mFileInfo.mCurrentFileName, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN, NULL); if (file != INVALID_HANDLE_VALUE) { // check the file size. Max is 64k DWORD sizeHiWord; DWORD sizeLoWord = ::GetFileSize(file, &sizeHiWord); if (sizeLoWord < 0x10000 && sizeHiWord == 0) { // alloc a buffer big enough to contain the file (account for '\0' CHAR *buffer = new CHAR[sizeLoWord + 1]; if (buffer) { // read the file in memory if (::ReadFile(file, buffer, sizeLoWord, &sizeHiWord, NULL)) { NS_ASSERTION(sizeLoWord == sizeHiWord, "ReadFile inconsistency"); buffer[sizeLoWord] = '\0'; // terminate the buffer // write the file to the edit field ::SendMessage(mEditWindow, WM_SETTEXT, (WPARAM)0, (LPARAM)buffer); // update the caption CHAR caption[80]; ::wsprintf(caption, "%s - %s", mFileInfo.mCurrentFileName + mFileInfo.mFileOffset, sDefaultCaption); ::SendMessage(mMainWindow, WM_SETTEXT, (WPARAM)0, (LPARAM)caption); result = TRUE; } else { ::DisplayError("Error Reading the File"); } // free the allocated buffer delete[] buffer; } else { ::MessageBox(mMainWindow, "Cannot Allocate Enough Memory to Copy the File in Memory", "JSConsole Error", MB_OK | MB_ICONSTOP); } } else { ::MessageBox(mMainWindow, "File too big. Max is 64k", "JSConsole Error", MB_OK | MB_ICONSTOP); } // close the file handle ::CloseHandle(file); } #ifdef _DEBUG else { CHAR message[MAX_PATH + 20]; wsprintf(message, "Cannot Open File: %s", mFileInfo.mCurrentFileName); ::DisplayError(message); } #endif } return result; } // // Save the current text into a file // BOOL JSConsole::SaveFile() { BOOL result = FALSE; if (mMainWindow && mFileInfo.mCurrentFileName[0] != '\0') { // create the new file HANDLE file = ::CreateFile(mFileInfo.mCurrentFileName, GENERIC_WRITE, FILE_SHARE_READ, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN, NULL); if (file != INVALID_HANDLE_VALUE) { DWORD size; // get the text size size = ::SendMessage(mEditWindow, WM_GETTEXTLENGTH, (WPARAM)0, (LPARAM)0); // alloc a buffer big enough to contain the file CHAR *buffer = new CHAR[++size]; if (buffer) { DWORD byteRead; // read the text area content ::SendMessage(mEditWindow, WM_GETTEXT, (WPARAM)size, (LPARAM)buffer); // write the buffer to disk if (::WriteFile(file, buffer, size, &byteRead, NULL)) { NS_ASSERTION(byteRead == size, "WriteFile inconsistency"); // update the caption CHAR caption[80]; ::wsprintf(caption, "%s - %s", mFileInfo.mCurrentFileName + mFileInfo.mFileOffset, sDefaultCaption); ::SendMessage(mMainWindow, WM_SETTEXT, (WPARAM)0, (LPARAM)caption); result = TRUE; } else { ::DisplayError("Error Writing the File"); } // free the allocated buffer delete[] buffer; } else { ::MessageBox(mMainWindow, "Cannot Allocate Enough Memory to Copy the Edit Text in Memory", "JSConsole Error", MB_OK | MB_ICONSTOP); } // close the file handle ::CloseHandle(file); } #ifdef _DEBUG else { CHAR message[MAX_PATH + 20]; wsprintf(message, "Cannot Open File: %s", mFileInfo.mCurrentFileName); ::DisplayError(message); } #endif } return result; } // // Open a FileOpen or FileSave dialog // BOOL JSConsole::OpenFileDialog(UINT aWhichDialog) { BOOL result = FALSE; OPENFILENAME ofn; if (mMainWindow) { // *.js is the standard File Name on the Save/Open Dialog if (mFileInfo.mCurrentFileName[0] == '\0') ::strcpy(mFileInfo.mCurrentFileName, "*.js"); // fill the OPENFILENAME sruct ofn.lStructSize = sizeof(OPENFILENAME); ofn.hwndOwner = mMainWindow; ofn.hInstance = JSConsole::sAppInstance; ofn.lpstrFilter = "JavaScript Files (*.js)\0*.js\0Text Files (*.txt)\0*.txt\0All Files\0*.*\0\0"; ofn.lpstrCustomFilter = NULL; ofn.nMaxCustFilter = 0; ofn.nFilterIndex = 1; // the first one in lpstrFilter ofn.lpstrFile = mFileInfo.mCurrentFileName; // contains the file path name on return ofn.nMaxFile = sizeof(mFileInfo.mCurrentFileName); ofn.lpstrFileTitle = NULL; ofn.nMaxFileTitle = 0; ofn.lpstrInitialDir = NULL; // use default ofn.lpstrTitle = NULL; // use default ofn.Flags = OFN_CREATEPROMPT | OFN_HIDEREADONLY | OFN_PATHMUSTEXIST; ofn.nFileOffset = 0; ofn.nFileExtension = 0; ofn.lpstrDefExt = "js"; // default extension is .js ofn.lCustData = NULL; ofn.lpfnHook = NULL; ofn.lpTemplateName = NULL; // call the open file dialog or the save file dialog according to aIsOpenDialog if (aWhichDialog == OPEN_DIALOG) { result = ::GetOpenFileName(&ofn); } else if (aWhichDialog == SAVE_DIALOG) { result = ::GetSaveFileName(&ofn); } if (!result) { mFileInfo.mCurrentFileName[0] = '\0'; ::CommDlgExtendedError(); } else { mFileInfo.mFileOffset = ofn.nFileOffset; mFileInfo.mFileExtension = ofn.nFileExtension; } } return result; } // // set the mFileInfo structure with the proper value given a generic path // void JSConsole::SetFileName(LPSTR aFileName) { strcpy(mFileInfo.mCurrentFileName, aFileName); for (int i = strlen(aFileName); i >= 0; i--) { if (mFileInfo.mCurrentFileName[i] == '.') { mFileInfo.mFileExtension = i; } if (mFileInfo.mCurrentFileName[i] == '\\') { mFileInfo.mFileOffset = i + 1; break; } } } // // Move the edit window to cover the all client area // LRESULT JSConsole::OnSize(DWORD aResizeFlags, UINT aWidth, UINT aHeight) { ::MoveWindow(mEditWindow, 0, 0, aWidth, aHeight, TRUE); RECT textArea; textArea.left = 3; textArea.top = 1; textArea.right = aWidth - 20; textArea.bottom = aHeight - 17; ::SendMessage(mEditWindow, EM_SETRECTNP, (WPARAM)0, (LPARAM)&textArea); return 0L; } // // Initialize properly menu items // LRESULT JSConsole::OnInitMenu(HMENU aMenu, UINT aPos, BOOL aIsSystem) { if (!aIsSystem) { if (aPos == EDITMENUPOS) { InitEditMenu(aMenu); } else if (aPos == COMMANDSMENUPOS) { InitCommandMenu(aMenu); } } return 0L; } // // Pass the focus to the edit window // LRESULT JSConsole::OnSetFocus(HWND aWnd) { ::SetFocus(mEditWindow); return 0L; } // // Destroy message // void JSConsole::OnDestroy() { if (mDestroyNotification) (*mDestroyNotification)(); } // // File/New. Reset caption, text area and file info // void JSConsole::OnFileNew() { SendMessage(mEditWindow, WM_SETTEXT, (WPARAM)0, (LPARAM)0); SendMessage(mMainWindow, WM_SETTEXT, (WPARAM)0, (LPARAM)JSConsole::sDefaultCaption); mFileInfo.Init(); } // // Edit/Undo. Undo the last operation on the edit field // void JSConsole::OnEditUndo() { SendMessage(mEditWindow, WM_UNDO, (WPARAM)0, (LPARAM)0); } // // Edit/Cut. Cut the current selection // void JSConsole::OnEditCut() { SendMessage(mEditWindow, WM_CUT, (WPARAM)0, (LPARAM)0); } // // Edit/Copy. Copy the current selection // void JSConsole::OnEditCopy() { SendMessage(mEditWindow, WM_COPY, (WPARAM)0, (LPARAM)0); } // // Edit/Paste. Paste from the clipboard // void JSConsole::OnEditPaste() { SendMessage(mEditWindow, WM_PASTE, (WPARAM)0, (LPARAM)0); } // // Edit/Delete. Delete the current selection // void JSConsole::OnEditDelete() { SendMessage(mEditWindow, WM_CLEAR, (WPARAM)0, (LPARAM)0); } // // Edit/Select All. Select the whole text in the text area // void JSConsole::OnEditSelectAll() { //SendMessage(mEditWindow, EM_SETSEL, (WPARAM)0, (LPARAM)-1); } // // Command/Evaluate All. Take the text area content and evaluate in the js context // void JSConsole::OnCommandEvaluateAll() { EvaluateText(0, (UINT)-1); } // // Command/Evaluate Selection. Take the current text area selection and evaluate in the js context // void JSConsole::OnCommandEvaluateSelection() { // // get the selection and evaluate it // DWORD startSel, endSel; // get selection range ::SendMessage(mEditWindow, EM_GETSEL, (WPARAM)&startSel, (LPARAM)&endSel); EvaluateText(startSel, endSel); } // // Command/Inspector. Run the js inspector on the global object // void JSConsole::OnCommandInspector() { ::MessageBox(mMainWindow, "Inspector not yet available", "JSConsole Error", MB_OK | MB_ICONINFORMATION); } // // Help // void JSConsole::OnHelp() { } // // private method. Deal with the "Edit" menu // void JSConsole::InitEditMenu(HMENU aMenu) { CHAR someText[2] = {'\0', '\0'}; // some buffer // set flags to "disable" UINT undoFlags = MF_BYPOSITION | MF_DISABLED | MF_GRAYED; UINT cutFlags = MF_BYPOSITION | MF_DISABLED | MF_GRAYED; UINT copyFlags = MF_BYPOSITION | MF_DISABLED | MF_GRAYED; UINT pasteFlags = MF_BYPOSITION | MF_DISABLED | MF_GRAYED; UINT deleteFlags = MF_BYPOSITION | MF_DISABLED | MF_GRAYED; UINT selectAllFlags = MF_BYPOSITION | MF_DISABLED | MF_GRAYED; // check if the edit area has any text SendMessage(mEditWindow, WM_GETTEXT, (WPARAM)2, (LPARAM)someText); if (someText[0] != '\0') { // enable the "Select All" selectAllFlags = MF_BYPOSITION | MF_ENABLED; // enable "Copy/Cut/Paste" if there is any selection UINT startPos, endPos; SendMessage(mEditWindow, EM_GETSEL, (WPARAM)&startPos, (LPARAM)&endPos); if (startPos != endPos) { cutFlags = MF_BYPOSITION | MF_ENABLED; copyFlags = MF_BYPOSITION | MF_ENABLED; deleteFlags = MF_BYPOSITION | MF_ENABLED; } } // undo is available if the edit control says so if (SendMessage(mEditWindow, EM_CANUNDO, (WPARAM)0, (LPARAM)0)) { undoFlags = MF_BYPOSITION | MF_ENABLED; } // check whether or not the clipboard contains text data if (IsClipboardFormatAvailable(CF_TEXT)) { pasteFlags = MF_BYPOSITION | MF_ENABLED; } // do enable/disable VERIFY(EnableMenuItem(aMenu, ID_EDITUNDO - ID_EDITMENU - 1, undoFlags), -1L, "Disable/Enable \"Undo\" Failed"); VERIFY(EnableMenuItem(aMenu, ID_EDITCUT - ID_EDITMENU - 1, cutFlags), -1L, "Disable/Enable \"Cut\" Failed"); VERIFY(EnableMenuItem(aMenu, ID_EDITCOPY - ID_EDITMENU - 1, copyFlags), -1L, "Disable/Enable \"Copy\" Failed"); VERIFY(EnableMenuItem(aMenu, ID_EDITPASTE - ID_EDITMENU - 1, pasteFlags), -1L, "Disable/Enable \"Paste\" Failed"); VERIFY(EnableMenuItem(aMenu, ID_EDITDELETE - ID_EDITMENU - 1, deleteFlags), -1L, "Disable/Enable \"Delete\" Failed"); VERIFY(EnableMenuItem(aMenu, ID_EDITSELECTALL - ID_EDITMENU - 1, selectAllFlags), -1L, "Disable/Enable \"Select All\" Failed"); } // // private method. Deal with the "Command" menu // void JSConsole::InitCommandMenu(HMENU aMenu) { CHAR someText[2] = {'\0', '\0'}; // some buffer // set flags to "disable" UINT evaluateAllFlags = MF_BYPOSITION | MF_DISABLED | MF_GRAYED; UINT evaluateSelectionFlags = MF_BYPOSITION | MF_DISABLED | MF_GRAYED; // check if the edit area has any text SendMessage(mEditWindow, WM_GETTEXT, (WPARAM)2, (LPARAM)someText); if (someText[0] != 0) { // if there is some text enable "Evaluate All" evaluateAllFlags = MF_BYPOSITION | MF_ENABLED; // enable "Evaluate Selection" if there is any selection UINT startPos, endPos; SendMessage(mEditWindow, EM_GETSEL, (WPARAM)&startPos, (LPARAM)&endPos); if (startPos != endPos) { evaluateSelectionFlags = MF_BYPOSITION | MF_ENABLED; } } // disable/enable commands VERIFY(EnableMenuItem(aMenu, ID_COMMANDSEVALALL - ID_COMMANDSMENU - 1, evaluateAllFlags), -1L, "Disable/Enable \"Evaluate All\" Failed"); VERIFY(EnableMenuItem(aMenu, ID_COMMANDSEVALSEL - ID_COMMANDSMENU - 1, evaluateSelectionFlags), -1L, "Disable/Enable \"Evaluate Selection\" Failed"); } // // normailize a buffer of char coming from a text area. // Basically get rid of the 0x0D char // LPSTR NormalizeBuffer(LPSTR aBuffer) { // trim all the 0x0D at the beginning (should be 1 at most, but hey...) while (*aBuffer == 0x0D) { aBuffer++; } LPSTR readPointer = aBuffer; LPSTR writePointer = aBuffer; do { // compact the buffer if needed *writePointer = *readPointer; // skip the 0x0D if (*readPointer != 0x0D) { writePointer++; } } while (*readPointer++ != '\0'); return aBuffer; } LPSTR PrepareForTextArea(LPSTR aBuffer, PRInt32 aSize) { PRInt32 count = 0; LPSTR newBuffer = aBuffer; LPSTR readPointer = aBuffer; // count the '\n' while (*readPointer != '\0' && (*readPointer++ != '\n' || ++count)); if (0 != count) { readPointer = aBuffer; newBuffer = new CHAR[aSize + count + 1]; LPSTR writePointer = newBuffer; while (*readPointer != '\0') { if (*readPointer == '\n') { *writePointer++ = 0x0D; } *writePointer++ = *readPointer++; } *writePointer = '\0'; } return newBuffer; } // // Evaluate the text enclosed between startSel and endSel // void JSConsole::EvaluateText(UINT aStartSel, UINT aEndSel) { if (mContext) { // get the text size UINT size = ::SendMessage(mEditWindow, WM_GETTEXTLENGTH, (WPARAM)0, (LPARAM)0); // alloc a buffer big enough to contain the file CHAR *buffer = new CHAR[++size]; if (buffer) { // get the whole text ::SendMessage(mEditWindow, WM_GETTEXT, (WPARAM)size, (LPARAM)buffer); // get the portion of the text to be evaluated if (aEndSel != (UINT)-1) { size = aEndSel - aStartSel; strncpy(buffer, buffer + aStartSel, size); buffer[size] = '\0'; } else { aEndSel = size; } // change the 0x0D0x0A couple in 0x0A ('\n') // no new buffer allocation, the pointer may be in the middle // of the old buffer though, so keep buffer to call delete LPSTR cleanBuffer = ::NormalizeBuffer(buffer); // evaluate the string nsAutoString returnValue; PRBool isUndefined; if (NS_SUCCEEDED(mContext->EvaluateString(NS_ConvertASCIItoUCS2(cleanBuffer), nsnull, nsnull, nsnull, 0, nsnull, &returnValue, &isUndefined))) { // output the result in the edit area CHAR result[128]; LPSTR res = result; int bDelete = 0; JSContext *cx = (JSContext *)mContext->GetNativeContext(); char *str = ToNewCString(returnValue); // make a string with 0xA changed to 0xD0xA res = PrepareForTextArea(str, returnValue.Length()); if (res != str) { bDelete = 1; // if the buffer was new'ed } // set the position at the end of the selection ::SendMessage(mEditWindow, EM_SETSEL, (WPARAM)aEndSel, (LPARAM)aEndSel); // write the result ::SendMessage(mEditWindow, EM_REPLACESEL, (WPARAM)TRUE, (LPARAM)res); // highlight the result ::SendMessage(mEditWindow, EM_SETSEL, (WPARAM)aEndSel - 1, (LPARAM)(aEndSel + strlen(res))); // deal with the "big string" case if (bDelete > 0) { delete[] res; } delete[] str; // clean up a bit JS_GC((JSContext *)mContext->GetNativeContext()); } else { ::MessageBox(mMainWindow, "Error evaluating the Script", "JSConsole Error", MB_OK | MB_ICONERROR); } delete[] buffer; } else { ::MessageBox(mMainWindow, "Not Enough Memory to Allocate a Buffer to Evaluate the Script", "JSConsole Error", MB_OK | MB_ICONSTOP); } } else { ::MessageBox(mMainWindow, "Java Script Context not initialized", "JSConsole Error", MB_OK | MB_ICONSTOP); } }