From a90321860fcdfcd5636bf1a4d5c15ee01460eeaa Mon Sep 17 00:00:00 2001 From: Thomas Bluemel Date: Thu, 8 Mar 2007 17:44:10 +0000 Subject: [PATCH] Add the very beginnings of a mmc.exe implementation (not yet included in the build) svn path=/trunk/; revision=26031 --- reactos/base/applications/mmc/console.c | 311 ++++++++++++++++++ reactos/base/applications/mmc/lang/en-US.rc | 21 ++ reactos/base/applications/mmc/manifest.xml | 24 ++ reactos/base/applications/mmc/misc.c | 115 +++++++ reactos/base/applications/mmc/mmc.c | 65 ++++ reactos/base/applications/mmc/mmc.rbuild | 21 ++ reactos/base/applications/mmc/mmc.rc | 17 + reactos/base/applications/mmc/precomp.h | 38 +++ reactos/base/applications/mmc/resource.h | 14 + .../base/applications/mmc/resources/mmc.ico | Bin 0 -> 29926 bytes 10 files changed, 626 insertions(+) create mode 100644 reactos/base/applications/mmc/console.c create mode 100644 reactos/base/applications/mmc/lang/en-US.rc create mode 100644 reactos/base/applications/mmc/manifest.xml create mode 100644 reactos/base/applications/mmc/misc.c create mode 100644 reactos/base/applications/mmc/mmc.c create mode 100644 reactos/base/applications/mmc/mmc.rbuild create mode 100644 reactos/base/applications/mmc/mmc.rc create mode 100644 reactos/base/applications/mmc/precomp.h create mode 100644 reactos/base/applications/mmc/resource.h create mode 100644 reactos/base/applications/mmc/resources/mmc.ico diff --git a/reactos/base/applications/mmc/console.c b/reactos/base/applications/mmc/console.c new file mode 100644 index 00000000000..f189a6c4165 --- /dev/null +++ b/reactos/base/applications/mmc/console.c @@ -0,0 +1,311 @@ +/* + * ReactOS Management Console + * Copyright (C) 2006 - 2007 Thomas Weidenmueller + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "precomp.h" + +static const TCHAR szMMCMainFrame[] = TEXT("MMCMainFrame"); +static const TCHAR szMMCChildFrm[] = TEXT("MMCChildFrm"); + +static LONG MainFrameWndCount = 0; +static ULONG NewConsoleCount = 0; + +static LPTSTR +CreateNewConsoleTitle(VOID) +{ + LPTSTR lpTitle; + + if (LoadAndFormatString(hAppInstance, + IDS_CONSOLETITLE, + &lpTitle, + ++NewConsoleCount) == 0) + { + lpTitle = NULL; + } + + return lpTitle; +} + +typedef struct _CONSOLE_MAINFRAME_WND +{ + HWND hwnd; + LPCTSTR lpConsoleTitle; + HMENU hMenuConsoleRoot; + union + { + DWORD Flags; + struct + { + DWORD AppAuthorMode : 1; + }; + }; +} CONSOLE_MAINFRAME_WND, *PCONSOLE_MAINFRAME_WND; + +static LRESULT CALLBACK +ConsoleMainFrameWndProc(IN HWND hwnd, + IN UINT uMsg, + IN WPARAM wParam, + IN LPARAM lParam) +{ + PCONSOLE_MAINFRAME_WND Info; + LRESULT Ret = FALSE; + + Info = (PCONSOLE_MAINFRAME_WND)GetWindowLongPtr(hwnd, + 0); + + if (Info != NULL || uMsg == WM_NCCREATE) + { + switch (uMsg) + { + case WM_COMMAND: + { + switch (LOWORD(wParam)) + { + case ID_FILE_EXIT: + PostMessage(hwnd, + WM_CLOSE, + 0, + 0); + break; + } + break; + } + + case WM_NCCREATE: + { + MainFrameWndCount++; + + Info = HeapAlloc(hAppHeap, + 0, + sizeof(*Info)); + if (Info != NULL) + { + ZeroMemory(Info, + sizeof(*Info)); + + Info->hwnd = hwnd; + + SetWindowLongPtr(hwnd, + 0, + (LONG_PTR)Info); + + Info->hMenuConsoleRoot = LoadMenu(hAppInstance, + MAKEINTRESOURCE(IDM_CONSOLEROOT)); + Ret = TRUE; + } + break; + } + + case WM_CREATE: + { + LPCTSTR lpFileName = (LPCTSTR)(((LPCREATESTRUCT)lParam)->lpCreateParams); + + if (lpFileName != NULL) + { + /* FIXME */ + } + else + { + Info->AppAuthorMode = TRUE; + Info->lpConsoleTitle = CreateNewConsoleTitle(); + } + + SetWindowText(Info->hwnd, + Info->lpConsoleTitle); + break; + } + + case WM_NCDESTROY: + SetMenu(Info->hwnd, + NULL); + + if (Info->hMenuConsoleRoot != NULL) + { + DestroyMenu(Info->hMenuConsoleRoot); + Info->hMenuConsoleRoot = NULL; + } + + HeapFree(hAppHeap, + 0, + Info); + + if (--MainFrameWndCount == 0) + PostQuitMessage(0); + break; + + + case WM_CLOSE: + DestroyWindow(hwnd); + break; + + default: + goto HandleDefaultMsg; + } + } + else + { +HandleDefaultMsg: + Ret = DefWindowProc(hwnd, + uMsg, + wParam, + lParam); + } + + return Ret; +} + +typedef struct _CONSOLE_CHILDFRM_WND +{ + HWND hwnd; + PCONSOLE_MAINFRAME_WND MainFrame; +} CONSOLE_CHILDFRM_WND, *PCONSOLE_CHILDFRM_WND; + +static LRESULT CALLBACK +ConsoleChildFrmProc(IN HWND hwnd, + IN UINT uMsg, + IN WPARAM wParam, + IN LPARAM lParam) +{ + PCONSOLE_CHILDFRM_WND Info; + LRESULT Ret = FALSE; + + Info = (PCONSOLE_CHILDFRM_WND)GetWindowLongPtr(hwnd, + 0); + + if (Info != NULL || uMsg == WM_NCCREATE) + { + switch (uMsg) + { + case WM_NCCREATE: + Info = HeapAlloc(hAppHeap, + 0, + sizeof(*Info)); + if (Info != NULL) + { + ZeroMemory(Info, + sizeof(*Info)); + + Info->hwnd = hwnd; + + SetWindowLongPtr(hwnd, + 0, + (LONG_PTR)Info); + + Ret = TRUE; + } + break; + + + case WM_NCDESTROY: + HeapFree(hAppHeap, + 0, + Info); + break; + + default: + goto HandleDefaultMsg; + } + } + else + { +HandleDefaultMsg: + Ret = DefWindowProc(hwnd, + uMsg, + wParam, + lParam); + } + + return Ret; + +} + +BOOL +RegisterMMCWndClasses(VOID) +{ + WNDCLASS wc; + BOOL Ret; + + /* Register the MMCMainFrame window class */ + wc.style = 0; + wc.lpfnWndProc = ConsoleMainFrameWndProc; + wc.cbClsExtra = 0; + wc.cbWndExtra = sizeof(PCONSOLE_MAINFRAME_WND); + wc.hInstance = hAppInstance; + wc.hIcon = LoadIcon(hAppInstance, + MAKEINTRESOURCE(IDI_MAINAPP)); + wc.hCursor = LoadCursor(NULL, + MAKEINTRESOURCE(IDC_ARROW)); + wc.hbrBackground = (HBRUSH)(COLOR_BTNFACE + 1); + wc.lpszMenuName = NULL; + wc.lpszClassName = szMMCMainFrame; + + Ret = (RegisterClass(&wc) != (ATOM)0); + if (Ret) + { + /* Register the MMCChildFrm window class */ + wc.lpfnWndProc = ConsoleChildFrmProc; + wc.cbWndExtra = sizeof(PCONSOLE_CHILDFRM_WND); + wc.lpszClassName = szMMCChildFrm; + + Ret = (RegisterClass(&wc) != (ATOM)0); + if (!Ret) + { + UnregisterClass(szMMCMainFrame, + hAppInstance); + } + } + + return Ret; +} + +VOID +UnregisterMMCWndClasses(VOID) +{ + UnregisterClass(szMMCChildFrm, + hAppInstance); + UnregisterClass(szMMCMainFrame, + hAppInstance); +} + +HWND +CreateConsoleWindow(IN LPCTSTR lpFileName OPTIONAL) +{ + HWND hWndConsole; + LONG_PTR FileName = (LONG_PTR)lpFileName; + + hWndConsole = CreateWindowEx(WS_EX_WINDOWEDGE, + szMMCMainFrame, + NULL, + WS_OVERLAPPEDWINDOW | WS_CLIPSIBLINGS, + CW_USEDEFAULT, + CW_USEDEFAULT, + CW_USEDEFAULT, + CW_USEDEFAULT, + NULL, + NULL, + hAppInstance, + (PVOID)FileName); + + if (hWndConsole != NULL) + { + ShowWindow(hWndConsole, + SW_SHOWDEFAULT); + } + + return hWndConsole; +} diff --git a/reactos/base/applications/mmc/lang/en-US.rc b/reactos/base/applications/mmc/lang/en-US.rc new file mode 100644 index 00000000000..3d0052fd31a --- /dev/null +++ b/reactos/base/applications/mmc/lang/en-US.rc @@ -0,0 +1,21 @@ +LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US + +IDM_CONSOLEROOT MENU DISCARDABLE +BEGIN + POPUP "&File" + BEGIN + MENUITEM SEPARATOR + MENUITEM "E&xit\tAlt+F4", ID_FILE_EXIT + END + + POPUP "&Help" + BEGIN + MENUITEM "&About ReactOS Management Console...", ID_HELP_ABOUT + END +END + +STRINGTABLE DISCARDABLE +BEGIN + IDS_APPTITLE "ReactOS Management Console" + IDS_CONSOLETITLE "Console%1!u!" +END diff --git a/reactos/base/applications/mmc/manifest.xml b/reactos/base/applications/mmc/manifest.xml new file mode 100644 index 00000000000..d19e587942d --- /dev/null +++ b/reactos/base/applications/mmc/manifest.xml @@ -0,0 +1,24 @@ + + + + ReactOS System Management Console + + + + + + + + diff --git a/reactos/base/applications/mmc/misc.c b/reactos/base/applications/mmc/misc.c new file mode 100644 index 00000000000..82ed116cf63 --- /dev/null +++ b/reactos/base/applications/mmc/misc.c @@ -0,0 +1,115 @@ +/* + * ReactOS Management Console + * Copyright (C) 2006 - 2007 Thomas Weidenmueller + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "precomp.h" + +INT +LengthOfStrResource(IN HINSTANCE hInst, + IN UINT uID) +{ + HRSRC hrSrc; + HGLOBAL hRes; + LPWSTR lpName, lpStr; + + if (hInst == NULL) + { + return -1; + } + + /* There are always blocks of 16 strings */ + lpName = (LPWSTR)MAKEINTRESOURCE((uID >> 4) + 1); + + /* Find the string table block */ + if ((hrSrc = FindResourceW(hInst, lpName, (LPWSTR)RT_STRING)) && + (hRes = LoadResource(hInst, hrSrc)) && + (lpStr = LockResource(hRes))) + { + UINT x; + + /* Find the string we're looking for */ + uID &= 0xF; /* position in the block, same as % 16 */ + for (x = 0; x < uID; x++) + { + lpStr += (*lpStr) + 1; + } + + /* Found the string */ + return (int)(*lpStr); + } + return -1; +} + + +static INT +AllocAndLoadString(OUT LPTSTR *lpTarget, + IN HINSTANCE hInst, + IN UINT uID) +{ + INT ln; + + ln = LengthOfStrResource(hInst, + uID); + if (ln++ > 0) + { + (*lpTarget) = (LPWSTR)LocalAlloc(LMEM_FIXED, + ln * sizeof(TCHAR)); + if ((*lpTarget) != NULL) + { + INT Ret; + if (!(Ret = LoadString(hInst, uID, *lpTarget, ln))) + { + LocalFree((HLOCAL)(*lpTarget)); + } + return Ret; + } + } + return 0; +} + +DWORD +LoadAndFormatString(IN HINSTANCE hInstance, + IN UINT uID, + OUT LPTSTR *lpTarget, + ...) +{ + DWORD Ret = 0; + LPWSTR lpFormat; + va_list lArgs; + + if (AllocAndLoadString(&lpFormat, + hInstance, + uID) != 0) + { + va_start(lArgs, lpTarget); + /* let's use FormatMessage to format it because it has the ability to allocate + memory automatically */ + Ret = FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_STRING, + lpFormat, + 0, + 0, + (LPTSTR)lpTarget, + 0, + &lArgs); + va_end(lArgs); + + LocalFree((HLOCAL)lpFormat); + } + + return Ret; +} diff --git a/reactos/base/applications/mmc/mmc.c b/reactos/base/applications/mmc/mmc.c new file mode 100644 index 00000000000..fadffa92c6c --- /dev/null +++ b/reactos/base/applications/mmc/mmc.c @@ -0,0 +1,65 @@ +/* + * ReactOS Management Console + * Copyright (C) 2006 - 2007 Thomas Weidenmueller + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "precomp.h" + +HINSTANCE hAppInstance; +HANDLE hAppHeap; + +int +_tmain(IN int argc, + IN const TCHAR *argv[]) +{ + HWND hMainConsole; + MSG Msg; + BOOL bRet; + + hAppInstance = GetModuleHandle(NULL); + hAppHeap = GetProcessHeap(); + + InitCommonControls(); + + if (!RegisterMMCWndClasses()) + { + /* FIXME - Display error */ + return 1; + } + + hMainConsole = CreateConsoleWindow(argc > 1 ? argv[1] : NULL); + if (hMainConsole != NULL) + { + for (;;) + { + bRet = GetMessage(&Msg, + NULL, + 0, + 0); + if (bRet != 0 && bRet != -1) + { + TranslateMessage(&Msg); + DispatchMessage(&Msg); + } + else if (bRet == 0) + break; + } + } + + UnregisterMMCWndClasses(); + return 0; +} diff --git a/reactos/base/applications/mmc/mmc.rbuild b/reactos/base/applications/mmc/mmc.rbuild new file mode 100644 index 00000000000..8c71e01cff5 --- /dev/null +++ b/reactos/base/applications/mmc/mmc.rbuild @@ -0,0 +1,21 @@ + + + + . + + 0x0600 + 0x0501 + kernel32 + user32 + gdi32 + comdlg32 + advapi32 + shell32 + comctl32 + console.c + misc.c + mmc.c + mmc.rc + precomp.h + + \ No newline at end of file diff --git a/reactos/base/applications/mmc/mmc.rc b/reactos/base/applications/mmc/mmc.rc new file mode 100644 index 00000000000..d1f7931ca7d --- /dev/null +++ b/reactos/base/applications/mmc/mmc.rc @@ -0,0 +1,17 @@ +/* $Id: sndvol32.rc 23239 2006-07-23 09:59:30Z janderwald $ */ + +#include +#include "resource.h" + +#define REACTOS_STR_FILE_DESCRIPTION "ReactOS Management Console\0" +#define REACTOS_STR_INTERNAL_NAME "mmc\0" +#define REACTOS_STR_ORIGINAL_FILENAME "mmc.exe\0" +#include + +LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US + +1 24 DISCARDABLE "manifest.xml" + +IDI_MAINAPP ICON DISCARDABLE resources/mmc.ico + +#include "lang/en-US.rc" diff --git a/reactos/base/applications/mmc/precomp.h b/reactos/base/applications/mmc/precomp.h new file mode 100644 index 00000000000..460b8aef130 --- /dev/null +++ b/reactos/base/applications/mmc/precomp.h @@ -0,0 +1,38 @@ +#ifndef __PRECOMP_H +#define __PRECOMP_H + +#include +#include +#include +#include +#include "resource.h" + +/* console.c */ + +BOOL +RegisterMMCWndClasses(VOID); + +VOID +UnregisterMMCWndClasses(VOID); + +HWND +CreateConsoleWindow(IN LPCTSTR lpFileName OPTIONAL); + +/* misc.c */ + +INT +LengthOfStrResource(IN HINSTANCE hInst, + IN UINT uID); + +DWORD +LoadAndFormatString(IN HINSTANCE hInstance, + IN UINT uID, + OUT LPTSTR *lpTarget, + ...); + +/* mmc.c */ + +extern HINSTANCE hAppInstance; +extern HANDLE hAppHeap; + +#endif /* __PRECOMP_H */ diff --git a/reactos/base/applications/mmc/resource.h b/reactos/base/applications/mmc/resource.h new file mode 100644 index 00000000000..37f42f5af71 --- /dev/null +++ b/reactos/base/applications/mmc/resource.h @@ -0,0 +1,14 @@ +#ifndef __RESOURCE_H +#define __RESOURCE_H + +#define IDS_APPTITLE 101 +#define IDS_CONSOLETITLE 102 + +#define IDI_MAINAPP 101 + +#define IDM_CONSOLEROOT 101 + +#define ID_FILE_EXIT 1001 +#define ID_HELP_ABOUT 9001 + +#endif /* __RESOURCE_H */ diff --git a/reactos/base/applications/mmc/resources/mmc.ico b/reactos/base/applications/mmc/resources/mmc.ico new file mode 100644 index 0000000000000000000000000000000000000000..e95d36073652288ba48185a3800d8bf053e88140 GIT binary patch literal 29926 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 IkOjv4A6Z;8V*mgE literal 0 HcmV?d00001