mirror of
https://github.com/reactos/reactos.git
synced 2024-12-28 18:15:11 +00:00
[NETSH] Replace the wine stub by a slightly more functional version
- Implement a basic command interpreter. - Add basic support for helper dlls and contexts. - Add interactive help system with context support. Everything is still under construction and subject to change.
This commit is contained in:
parent
dabe7fba46
commit
d8f9f7f256
11 changed files with 1923 additions and 28 deletions
|
@ -1,8 +1,25 @@
|
||||||
|
|
||||||
add_definitions(-D__WINESRC__)
|
include_directories(${REACTOS_SOURCE_DIR}/sdk/lib/conutils)
|
||||||
include_directories(${REACTOS_SOURCE_DIR}/sdk/include/wine)
|
spec2def(netsh.exe netsh.spec ADD_IMPORTLIB)
|
||||||
add_executable(netsh netsh.c)
|
|
||||||
target_link_libraries(netsh wine)
|
list(APPEND SOURCE
|
||||||
|
context.c
|
||||||
|
help.c
|
||||||
|
helper.c
|
||||||
|
interpreter.c
|
||||||
|
netsh.c
|
||||||
|
precomp.h)
|
||||||
|
|
||||||
|
add_executable(netsh ${SOURCE} netsh.rc ${CMAKE_CURRENT_BINARY_DIR}/netsh.def)
|
||||||
|
|
||||||
|
set_target_properties(netsh
|
||||||
|
PROPERTIES
|
||||||
|
ENABLE_EXPORTS TRUE
|
||||||
|
DEFINE_SYMBOL "")
|
||||||
|
|
||||||
set_module_type(netsh win32cui UNICODE)
|
set_module_type(netsh win32cui UNICODE)
|
||||||
add_importlibs(netsh msvcrt kernel32 ntdll)
|
target_link_libraries(netsh conutils ${PSEH_LIB})
|
||||||
|
add_importlibs(netsh advapi32 msvcrt user32 kernel32 ntdll)
|
||||||
|
|
||||||
|
add_pch(netsh precomp.h SOURCE)
|
||||||
add_cd_file(TARGET netsh DESTINATION reactos/system32 FOR all)
|
add_cd_file(TARGET netsh DESTINATION reactos/system32 FOR all)
|
||||||
|
|
374
base/applications/network/netsh/context.c
Normal file
374
base/applications/network/netsh/context.c
Normal file
|
@ -0,0 +1,374 @@
|
||||||
|
/*
|
||||||
|
* PROJECT: ReactOS NetSh
|
||||||
|
* LICENSE: GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later)
|
||||||
|
* PURPOSE: Network Shell context management functions
|
||||||
|
* COPYRIGHT: Copyright 2023 Eric Kohl <eric.kohl@reactos.org>
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* INCLUDES *******************************************************************/
|
||||||
|
|
||||||
|
#include "precomp.h"
|
||||||
|
|
||||||
|
#define NDEBUG
|
||||||
|
#include <debug.h>
|
||||||
|
|
||||||
|
/* GLOBALS ********************************************************************/
|
||||||
|
|
||||||
|
PCONTEXT_ENTRY pRootContext = NULL;
|
||||||
|
PCONTEXT_ENTRY pCurrentContext = NULL;
|
||||||
|
|
||||||
|
/* FUNCTIONS ******************************************************************/
|
||||||
|
|
||||||
|
PCONTEXT_ENTRY
|
||||||
|
AddContext(
|
||||||
|
PCONTEXT_ENTRY pParentContext,
|
||||||
|
PWSTR pszName,
|
||||||
|
GUID *pGuid)
|
||||||
|
{
|
||||||
|
PCONTEXT_ENTRY pEntry;
|
||||||
|
|
||||||
|
if (pParentContext != NULL && pszName == NULL)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
/* Allocate the entry */
|
||||||
|
pEntry = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(CONTEXT_ENTRY));
|
||||||
|
if (pEntry == NULL)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
/* Allocate the name buffer */
|
||||||
|
if (pszName != NULL)
|
||||||
|
{
|
||||||
|
pEntry->pszContextName = HeapAlloc(GetProcessHeap(),
|
||||||
|
HEAP_ZERO_MEMORY,
|
||||||
|
(wcslen(pszName) + 1) * sizeof(WCHAR));
|
||||||
|
if (pEntry->pszContextName == NULL)
|
||||||
|
{
|
||||||
|
HeapFree(GetProcessHeap(), 0, pEntry);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Fill the entry */
|
||||||
|
wcscpy(pEntry->pszContextName, pszName);
|
||||||
|
}
|
||||||
|
|
||||||
|
pEntry->pParentContext = pParentContext;
|
||||||
|
if (pGuid != NULL)
|
||||||
|
CopyMemory(&pEntry->Guid, pGuid, sizeof(pEntry->Guid));
|
||||||
|
|
||||||
|
/* Insert it */
|
||||||
|
if (pParentContext != NULL)
|
||||||
|
{
|
||||||
|
if (pParentContext->pSubContextHead == NULL && pParentContext->pSubContextTail == NULL)
|
||||||
|
{
|
||||||
|
pParentContext->pSubContextHead = pEntry;
|
||||||
|
pParentContext->pSubContextTail = pEntry;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
pEntry->pPrev = pParentContext->pSubContextTail;
|
||||||
|
pParentContext->pSubContextTail->pNext = pEntry;
|
||||||
|
pParentContext->pSubContextTail = pEntry;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return pEntry;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
PCOMMAND_ENTRY
|
||||||
|
AddContextCommand(
|
||||||
|
PCONTEXT_ENTRY pContext,
|
||||||
|
LPCWSTR pwszCmdToken,
|
||||||
|
PFN_HANDLE_CMD pfnCmdHandler,
|
||||||
|
DWORD dwShortCmdHelpToken,
|
||||||
|
DWORD dwCmdHlpToken,
|
||||||
|
DWORD dwFlags)
|
||||||
|
{
|
||||||
|
PCOMMAND_ENTRY pEntry;
|
||||||
|
|
||||||
|
if (pfnCmdHandler == NULL)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
/* Allocate the entry */
|
||||||
|
pEntry = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(COMMAND_ENTRY));
|
||||||
|
if (pEntry == NULL)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
pEntry->pwszCmdToken = HeapAlloc(GetProcessHeap(),
|
||||||
|
HEAP_ZERO_MEMORY,
|
||||||
|
(wcslen(pwszCmdToken) + 1) * sizeof(WCHAR));
|
||||||
|
if (pEntry->pwszCmdToken == NULL)
|
||||||
|
{
|
||||||
|
HeapFree(GetProcessHeap(), 0, pEntry);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
wcscpy((LPWSTR)pEntry->pwszCmdToken, pwszCmdToken);
|
||||||
|
|
||||||
|
pEntry->pfnCmdHandler = pfnCmdHandler;
|
||||||
|
pEntry->dwShortCmdHelpToken = dwShortCmdHelpToken;
|
||||||
|
pEntry->dwCmdHlpToken = dwCmdHlpToken;
|
||||||
|
pEntry->dwFlags = dwFlags;
|
||||||
|
|
||||||
|
if (pContext->pCommandListHead == NULL && pContext->pCommandListTail == NULL)
|
||||||
|
{
|
||||||
|
pContext->pCommandListHead = pEntry;
|
||||||
|
pContext->pCommandListTail = pEntry;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
pEntry->pPrev = pContext->pCommandListTail;
|
||||||
|
pContext->pCommandListTail->pNext = pEntry;
|
||||||
|
pContext->pCommandListTail = pEntry;
|
||||||
|
}
|
||||||
|
|
||||||
|
return pEntry;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
PCOMMAND_GROUP
|
||||||
|
AddCommandGroup(
|
||||||
|
PCONTEXT_ENTRY pContext,
|
||||||
|
LPCWSTR pwszCmdGroupToken,
|
||||||
|
DWORD dwShortCmdHelpToken,
|
||||||
|
DWORD dwFlags)
|
||||||
|
{
|
||||||
|
PCOMMAND_GROUP pEntry;
|
||||||
|
|
||||||
|
/* Allocate the entry */
|
||||||
|
pEntry = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(COMMAND_GROUP));
|
||||||
|
if (pEntry == NULL)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
pEntry->pwszCmdGroupToken = HeapAlloc(GetProcessHeap(),
|
||||||
|
HEAP_ZERO_MEMORY,
|
||||||
|
(wcslen(pwszCmdGroupToken) + 1) * sizeof(WCHAR));
|
||||||
|
if (pEntry->pwszCmdGroupToken == NULL)
|
||||||
|
{
|
||||||
|
HeapFree(GetProcessHeap(), 0, pEntry);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
wcscpy((LPWSTR)pEntry->pwszCmdGroupToken, pwszCmdGroupToken);
|
||||||
|
pEntry->dwShortCmdHelpToken = dwShortCmdHelpToken;
|
||||||
|
pEntry->dwFlags = dwFlags;
|
||||||
|
|
||||||
|
if (pContext->pGroupListHead == NULL && pContext->pGroupListTail == NULL)
|
||||||
|
{
|
||||||
|
pContext->pGroupListHead = pEntry;
|
||||||
|
pContext->pGroupListTail = pEntry;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
pEntry->pPrev = pContext->pGroupListTail;
|
||||||
|
pContext->pGroupListTail->pNext = pEntry;
|
||||||
|
pContext->pGroupListTail = pEntry;
|
||||||
|
}
|
||||||
|
|
||||||
|
return pEntry;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
PCOMMAND_ENTRY
|
||||||
|
AddGroupCommand(
|
||||||
|
PCOMMAND_GROUP pGroup,
|
||||||
|
LPCWSTR pwszCmdToken,
|
||||||
|
PFN_HANDLE_CMD pfnCmdHandler,
|
||||||
|
DWORD dwShortCmdHelpToken,
|
||||||
|
DWORD dwCmdHlpToken,
|
||||||
|
DWORD dwFlags)
|
||||||
|
{
|
||||||
|
PCOMMAND_ENTRY pEntry;
|
||||||
|
|
||||||
|
if (pfnCmdHandler == NULL)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
/* Allocate the entry */
|
||||||
|
pEntry = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(COMMAND_ENTRY));
|
||||||
|
if (pEntry == NULL)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
pEntry->pwszCmdToken = HeapAlloc(GetProcessHeap(),
|
||||||
|
HEAP_ZERO_MEMORY,
|
||||||
|
(wcslen(pwszCmdToken) + 1) * sizeof(WCHAR));
|
||||||
|
if (pEntry->pwszCmdToken == NULL)
|
||||||
|
{
|
||||||
|
HeapFree(GetProcessHeap(), 0, pEntry);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
wcscpy((LPWSTR)pEntry->pwszCmdToken, pwszCmdToken);
|
||||||
|
|
||||||
|
pEntry->pfnCmdHandler = pfnCmdHandler;
|
||||||
|
pEntry->dwShortCmdHelpToken = dwShortCmdHelpToken;
|
||||||
|
pEntry->dwCmdHlpToken = dwCmdHlpToken;
|
||||||
|
pEntry->dwFlags = dwFlags;
|
||||||
|
|
||||||
|
if (pGroup->pCommandListHead == NULL && pGroup->pCommandListTail == NULL)
|
||||||
|
{
|
||||||
|
pGroup->pCommandListHead = pEntry;
|
||||||
|
pGroup->pCommandListTail = pEntry;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
pEntry->pPrev = pGroup->pCommandListTail;
|
||||||
|
pGroup->pCommandListTail->pNext = pEntry;
|
||||||
|
pGroup->pCommandListTail = pEntry;
|
||||||
|
}
|
||||||
|
|
||||||
|
return pEntry;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
VOID
|
||||||
|
DeleteContext(
|
||||||
|
PWSTR pszName)
|
||||||
|
{
|
||||||
|
/* Delete all commands */
|
||||||
|
/* Delete the context */
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
DWORD
|
||||||
|
WINAPI
|
||||||
|
UpCommand(
|
||||||
|
LPCWSTR pwszMachine,
|
||||||
|
LPWSTR *argv,
|
||||||
|
DWORD dwCurrentIndex,
|
||||||
|
DWORD dwArgCount,
|
||||||
|
DWORD dwFlags,
|
||||||
|
LPCVOID pvData,
|
||||||
|
BOOL *pbDone)
|
||||||
|
{
|
||||||
|
if (pCurrentContext != pRootContext)
|
||||||
|
pCurrentContext = pCurrentContext->pParentContext;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
DWORD
|
||||||
|
WINAPI
|
||||||
|
ExitCommand(
|
||||||
|
LPCWSTR pwszMachine,
|
||||||
|
LPWSTR *argv,
|
||||||
|
DWORD dwCurrentIndex,
|
||||||
|
DWORD dwArgCount,
|
||||||
|
DWORD dwFlags,
|
||||||
|
LPCVOID pvData,
|
||||||
|
BOOL *pbDone)
|
||||||
|
{
|
||||||
|
*pbDone = TRUE;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
DWORD
|
||||||
|
WINAPI
|
||||||
|
RemCommand(
|
||||||
|
LPCWSTR pwszMachine,
|
||||||
|
LPWSTR *argv,
|
||||||
|
DWORD dwCurrentIndex,
|
||||||
|
DWORD dwArgCount,
|
||||||
|
DWORD dwFlags,
|
||||||
|
LPCVOID pvData,
|
||||||
|
BOOL *pbDone)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
BOOL
|
||||||
|
CreateRootContext(VOID)
|
||||||
|
{
|
||||||
|
PCOMMAND_GROUP pGroup;
|
||||||
|
|
||||||
|
pRootContext = AddContext(NULL, NULL, NULL);
|
||||||
|
DPRINT1("pRootContext: %p\n", pRootContext);
|
||||||
|
if (pRootContext == NULL)
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
|
pRootContext->hModule = GetModuleHandle(NULL);
|
||||||
|
|
||||||
|
AddContextCommand(pRootContext, L"..", UpCommand, IDS_HLP_UP, IDS_HLP_UP_EX, 0);
|
||||||
|
AddContextCommand(pRootContext, L"?", HelpCommand, IDS_HLP_HELP, IDS_HLP_HELP_EX, 0);
|
||||||
|
AddContextCommand(pRootContext, L"bye", ExitCommand, IDS_HLP_EXIT, IDS_HLP_EXIT_EX, 0);
|
||||||
|
AddContextCommand(pRootContext, L"exit", ExitCommand, IDS_HLP_EXIT, IDS_HLP_EXIT_EX, 0);
|
||||||
|
AddContextCommand(pRootContext, L"help", HelpCommand, IDS_HLP_HELP, IDS_HLP_HELP_EX, 0);
|
||||||
|
AddContextCommand(pRootContext, L"quit", ExitCommand, IDS_HLP_EXIT, IDS_HLP_EXIT_EX, 0);
|
||||||
|
|
||||||
|
pGroup = AddCommandGroup(pRootContext, L"add", IDS_HLP_GROUP_ADD, 0);
|
||||||
|
if (pGroup)
|
||||||
|
{
|
||||||
|
AddGroupCommand(pGroup, L"helper", AddHelperCommand, IDS_HLP_ADD_HELPER, IDS_HLP_ADD_HELPER_EX, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
pGroup = AddCommandGroup(pRootContext, L"delete", IDS_HLP_GROUP_DELETE, 0);
|
||||||
|
if (pGroup)
|
||||||
|
{
|
||||||
|
AddGroupCommand(pGroup, L"helper", DeleteHelperCommand, IDS_HLP_DEL_HELPER, IDS_HLP_DEL_HELPER_EX, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
pGroup = AddCommandGroup(pRootContext, L"show", IDS_HLP_GROUP_SHOW, 0);
|
||||||
|
if (pGroup)
|
||||||
|
{
|
||||||
|
AddGroupCommand(pGroup, L"helper", ShowHelperCommand, IDS_HLP_SHOW_HELPER, IDS_HLP_SHOW_HELPER_EX, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
pCurrentContext = pRootContext;
|
||||||
|
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
DWORD
|
||||||
|
WINAPI
|
||||||
|
RegisterContext(
|
||||||
|
_In_ const NS_CONTEXT_ATTRIBUTES *pChildContext)
|
||||||
|
{
|
||||||
|
PCONTEXT_ENTRY pContext;
|
||||||
|
DWORD i;
|
||||||
|
|
||||||
|
DPRINT1("RegisterContext(%p)\n", pChildContext);
|
||||||
|
if (pChildContext == NULL)
|
||||||
|
{
|
||||||
|
DPRINT1("Invalid child context!\n");
|
||||||
|
return ERROR_INVALID_PARAMETER;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((pChildContext->pwszContext == NULL) ||
|
||||||
|
(wcslen(pChildContext->pwszContext) == 0) ||
|
||||||
|
(wcschr(pChildContext->pwszContext, L' ') != 0) ||
|
||||||
|
(wcschr(pChildContext->pwszContext, L'=') != 0))
|
||||||
|
{
|
||||||
|
DPRINT1("Invalid context name!\n");
|
||||||
|
return ERROR_INVALID_PARAMETER;
|
||||||
|
}
|
||||||
|
|
||||||
|
DPRINT1("Name: %S\n", pChildContext->pwszContext);
|
||||||
|
|
||||||
|
pContext = AddContext(pRootContext, pChildContext->pwszContext, (GUID*)&pChildContext->guidHelper);
|
||||||
|
if (pContext != NULL)
|
||||||
|
{
|
||||||
|
for (i = 0; i < pChildContext->ulNumTopCmds; i++)
|
||||||
|
{
|
||||||
|
AddContextCommand(pContext,
|
||||||
|
pChildContext->pTopCmds[i].pwszCmdToken,
|
||||||
|
pChildContext->pTopCmds[i].pfnCmdHandler,
|
||||||
|
pChildContext->pTopCmds[i].dwShortCmdHelpToken,
|
||||||
|
pChildContext->pTopCmds[i].dwCmdHlpToken,
|
||||||
|
pChildContext->pTopCmds[i].dwFlags);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Add command groups */
|
||||||
|
for (i = 0; i < pChildContext->ulNumGroups; i++)
|
||||||
|
{
|
||||||
|
AddCommandGroup(pContext,
|
||||||
|
pChildContext->pCmdGroups[i].pwszCmdGroupToken,
|
||||||
|
pChildContext->pCmdGroups[i].dwShortCmdHelpToken,
|
||||||
|
pChildContext->pCmdGroups[i].dwFlags);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return ERROR_SUCCESS;
|
||||||
|
}
|
152
base/applications/network/netsh/help.c
Normal file
152
base/applications/network/netsh/help.c
Normal file
|
@ -0,0 +1,152 @@
|
||||||
|
/*
|
||||||
|
* PROJECT: ReactOS NetSh
|
||||||
|
* LICENSE: GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later)
|
||||||
|
* PURPOSE: Network Shell builtin help command and support functions
|
||||||
|
* COPYRIGHT: Copyright 2023 Eric Kohl <eric.kohl@reactos.org>
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* INCLUDES *******************************************************************/
|
||||||
|
|
||||||
|
#include "precomp.h"
|
||||||
|
|
||||||
|
#define NDEBUG
|
||||||
|
#include <debug.h>
|
||||||
|
|
||||||
|
/* FUNCTIONS ******************************************************************/
|
||||||
|
|
||||||
|
static
|
||||||
|
VOID
|
||||||
|
GetContextFullName(
|
||||||
|
_In_ PCONTEXT_ENTRY pContext,
|
||||||
|
_Inout_ LPWSTR pszBuffer,
|
||||||
|
_In_ DWORD cchLength)
|
||||||
|
{
|
||||||
|
if (pContext->pParentContext != NULL)
|
||||||
|
{
|
||||||
|
GetContextFullName(pContext->pParentContext, pszBuffer, cchLength);
|
||||||
|
wcscat(pszBuffer, L" ");
|
||||||
|
wcscat(pszBuffer, pContext->pszContextName);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
wcscpy(pszBuffer, L"netsh");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static
|
||||||
|
VOID
|
||||||
|
HelpContext(
|
||||||
|
PCONTEXT_ENTRY pContext)
|
||||||
|
{
|
||||||
|
PCONTEXT_ENTRY pSubContext;
|
||||||
|
PCOMMAND_ENTRY pCommand;
|
||||||
|
PCOMMAND_GROUP pGroup;
|
||||||
|
WCHAR szBuffer[80];
|
||||||
|
|
||||||
|
if (pContext != pRootContext)
|
||||||
|
HelpContext(pContext->pParentContext);
|
||||||
|
|
||||||
|
if (pContext == pCurrentContext)
|
||||||
|
{
|
||||||
|
ConPrintf(StdOut, L"\nCommands in this context:\n");
|
||||||
|
}
|
||||||
|
else if (pContext == pRootContext)
|
||||||
|
{
|
||||||
|
ConPrintf(StdOut, L"\nCommands in the netsh-context:\n");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
GetContextFullName(pContext, szBuffer, 80);
|
||||||
|
ConPrintf(StdOut, L"\nCommands in the %s-context:\n", szBuffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
pCommand = pContext->pCommandListHead;
|
||||||
|
while (pCommand != NULL)
|
||||||
|
{
|
||||||
|
if (LoadStringW(pContext->hModule, pCommand->dwShortCmdHelpToken, szBuffer, 80) == 0)
|
||||||
|
szBuffer[0] = UNICODE_NULL;
|
||||||
|
ConPrintf(StdOut, L"%-15s - %s\n", pCommand->pwszCmdToken, szBuffer);
|
||||||
|
pCommand = pCommand->pNext;
|
||||||
|
}
|
||||||
|
|
||||||
|
pGroup = pContext->pGroupListHead;
|
||||||
|
while (pGroup != NULL)
|
||||||
|
{
|
||||||
|
if (LoadStringW(pContext->hModule, pGroup->dwShortCmdHelpToken, szBuffer, 80) == 0)
|
||||||
|
szBuffer[0] = UNICODE_NULL;
|
||||||
|
ConPrintf(StdOut, L"%-15s - %s\n", pGroup->pwszCmdGroupToken, szBuffer);
|
||||||
|
pGroup = pGroup->pNext;
|
||||||
|
}
|
||||||
|
|
||||||
|
pSubContext = pContext->pSubContextHead;
|
||||||
|
while (pSubContext != NULL)
|
||||||
|
{
|
||||||
|
GetContextFullName(pSubContext, szBuffer, 80);
|
||||||
|
ConPrintf(StdOut, L"%-15s - Changes to the \"%s\" context.\n", pSubContext->pszContextName, szBuffer);
|
||||||
|
pSubContext = pSubContext->pNext;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
VOID
|
||||||
|
HelpGroup(
|
||||||
|
PCOMMAND_GROUP pGroup)
|
||||||
|
{
|
||||||
|
PCOMMAND_ENTRY pCommand;
|
||||||
|
WCHAR szBuffer[64];
|
||||||
|
|
||||||
|
ConResPrintf(StdOut, IDS_HELP_HEADER);
|
||||||
|
|
||||||
|
ConPrintf(StdOut, L"\nCommands in this context:\n");
|
||||||
|
|
||||||
|
pCommand = pGroup->pCommandListHead;
|
||||||
|
while (pCommand != NULL)
|
||||||
|
{
|
||||||
|
swprintf(szBuffer, L"%s %s", pGroup->pwszCmdGroupToken, pCommand->pwszCmdToken);
|
||||||
|
ConPrintf(StdOut, L"%-15s - ", szBuffer);
|
||||||
|
ConResPuts(StdOut, pCommand->dwShortCmdHelpToken);
|
||||||
|
pCommand = pCommand->pNext;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
DWORD
|
||||||
|
WINAPI
|
||||||
|
HelpCommand(
|
||||||
|
LPCWSTR pwszMachine,
|
||||||
|
LPWSTR *ppwcArguments,
|
||||||
|
DWORD dwCurrentIndex,
|
||||||
|
DWORD dwArgCount,
|
||||||
|
DWORD dwFlags,
|
||||||
|
LPCVOID pvData,
|
||||||
|
BOOL *pbDone)
|
||||||
|
{
|
||||||
|
PCONTEXT_ENTRY pContext;
|
||||||
|
|
||||||
|
ConResPrintf(StdOut, IDS_HELP_HEADER);
|
||||||
|
|
||||||
|
pContext = pCurrentContext;
|
||||||
|
if (pContext == NULL)
|
||||||
|
{
|
||||||
|
DPRINT1("HelpCommand: invalid context %p\n", pContext);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
HelpContext(pContext);
|
||||||
|
|
||||||
|
if (pCurrentContext->pSubContextHead != NULL)
|
||||||
|
{
|
||||||
|
ConResPrintf(StdOut, IDS_SUBCONTEXT_HEADER);
|
||||||
|
pContext = pCurrentContext->pSubContextHead;
|
||||||
|
while (pContext != NULL)
|
||||||
|
{
|
||||||
|
ConPrintf(StdOut, L" %s", pContext->pszContextName);
|
||||||
|
pContext = pContext->pNext;
|
||||||
|
}
|
||||||
|
ConPuts(StdOut, L"\n");
|
||||||
|
}
|
||||||
|
ConPuts(StdOut, L"\n");
|
||||||
|
|
||||||
|
return ERROR_SUCCESS;
|
||||||
|
}
|
593
base/applications/network/netsh/helper.c
Normal file
593
base/applications/network/netsh/helper.c
Normal file
|
@ -0,0 +1,593 @@
|
||||||
|
/*
|
||||||
|
* PROJECT: ReactOS NetSh
|
||||||
|
* LICENSE: GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later)
|
||||||
|
* PURPOSE: Network Shell helper dll management and support functions
|
||||||
|
* COPYRIGHT: Copyright 2023 Eric Kohl <eric.kohl@reactos.org>
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* INCLUDES *******************************************************************/
|
||||||
|
|
||||||
|
#include "precomp.h"
|
||||||
|
|
||||||
|
#define NDEBUG
|
||||||
|
#include <debug.h>
|
||||||
|
|
||||||
|
/* GLOBALS ********************************************************************/
|
||||||
|
|
||||||
|
PDLL_LIST_ENTRY pDllListHead = NULL;
|
||||||
|
PDLL_LIST_ENTRY pDllListTail = NULL;
|
||||||
|
|
||||||
|
PHELPER_ENTRY pHelperListHead = NULL;
|
||||||
|
PHELPER_ENTRY pHelperListTail = NULL;
|
||||||
|
|
||||||
|
PDLL_LIST_ENTRY pCurrentDll = NULL;
|
||||||
|
|
||||||
|
/* FUNCTIONS ******************************************************************/
|
||||||
|
|
||||||
|
static
|
||||||
|
VOID
|
||||||
|
StartHelpers(VOID)
|
||||||
|
{
|
||||||
|
PHELPER_ENTRY pHelper;
|
||||||
|
DWORD dwError;
|
||||||
|
|
||||||
|
pHelper = pHelperListHead;
|
||||||
|
while (pHelper != NULL)
|
||||||
|
{
|
||||||
|
if (pHelper->bStarted == FALSE)
|
||||||
|
{
|
||||||
|
if (pHelper->Attributes.pfnStart)
|
||||||
|
{
|
||||||
|
dwError = pHelper->Attributes.pfnStart(NULL, 0);
|
||||||
|
if (dwError == ERROR_SUCCESS)
|
||||||
|
pHelper->bStarted = TRUE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pHelper = pHelper->pNext;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static
|
||||||
|
VOID
|
||||||
|
RegisterHelperDll(
|
||||||
|
_In_ PDLL_LIST_ENTRY pEntry)
|
||||||
|
{
|
||||||
|
PWSTR pszValueName = NULL;
|
||||||
|
HKEY hKey;
|
||||||
|
DWORD dwError;
|
||||||
|
|
||||||
|
dwError = RegCreateKeyExW(HKEY_LOCAL_MACHINE,
|
||||||
|
REG_NETSH_PATH,
|
||||||
|
0,
|
||||||
|
NULL,
|
||||||
|
REG_OPTION_NON_VOLATILE,
|
||||||
|
KEY_WRITE,
|
||||||
|
NULL,
|
||||||
|
&hKey,
|
||||||
|
NULL);
|
||||||
|
if (dwError == ERROR_SUCCESS)
|
||||||
|
{
|
||||||
|
RegSetValueExW(hKey,
|
||||||
|
pEntry->pszValueName,
|
||||||
|
0,
|
||||||
|
REG_SZ,
|
||||||
|
(PBYTE)pEntry->pszDllName,
|
||||||
|
(wcslen(pEntry->pszDllName) + 1) * sizeof(WCHAR));
|
||||||
|
|
||||||
|
RegCloseKey(hKey);
|
||||||
|
}
|
||||||
|
|
||||||
|
HeapFree(GetProcessHeap(), 0, pszValueName);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static
|
||||||
|
VOID
|
||||||
|
FreeHelperDll(
|
||||||
|
_In_ PDLL_LIST_ENTRY pEntry)
|
||||||
|
{
|
||||||
|
if (pEntry->hModule)
|
||||||
|
FreeLibrary(pEntry->hModule);
|
||||||
|
|
||||||
|
if (pEntry->pszValueName)
|
||||||
|
HeapFree(GetProcessHeap(), 0, pEntry->pszValueName);
|
||||||
|
|
||||||
|
if (pEntry->pszShortName)
|
||||||
|
HeapFree(GetProcessHeap(), 0, pEntry->pszShortName);
|
||||||
|
|
||||||
|
if (pEntry->pszDllName)
|
||||||
|
HeapFree(GetProcessHeap(), 0, pEntry->pszDllName);
|
||||||
|
|
||||||
|
HeapFree(GetProcessHeap(), 0, pEntry);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static
|
||||||
|
DWORD
|
||||||
|
LoadHelperDll(
|
||||||
|
_In_ PWSTR pszDllName,
|
||||||
|
_In_ BOOL bRegister)
|
||||||
|
{
|
||||||
|
PNS_DLL_INIT_FN pInitHelperDll;
|
||||||
|
PDLL_LIST_ENTRY pEntry;
|
||||||
|
PWSTR pszStart, pszEnd;
|
||||||
|
BOOL bInserted = FALSE;
|
||||||
|
DWORD dwError;
|
||||||
|
|
||||||
|
pEntry = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(DLL_LIST_ENTRY));
|
||||||
|
if (pEntry == NULL)
|
||||||
|
{
|
||||||
|
return ERROR_OUTOFMEMORY;
|
||||||
|
}
|
||||||
|
|
||||||
|
pEntry->pszDllName = HeapAlloc(GetProcessHeap(),
|
||||||
|
HEAP_ZERO_MEMORY,
|
||||||
|
(wcslen(pszDllName) + 1) * sizeof(WCHAR));
|
||||||
|
if (pEntry->pszDllName == NULL)
|
||||||
|
{
|
||||||
|
dwError = ERROR_OUTOFMEMORY;
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
|
||||||
|
wcscpy(pEntry->pszDllName, pszDllName);
|
||||||
|
|
||||||
|
pszStart = wcsrchr(pszDllName, L'\\');
|
||||||
|
if (pszStart == NULL)
|
||||||
|
pszStart = pszDllName;
|
||||||
|
|
||||||
|
pEntry->pszShortName = HeapAlloc(GetProcessHeap(),
|
||||||
|
HEAP_ZERO_MEMORY,
|
||||||
|
(wcslen(pszStart) + 1) * sizeof(WCHAR));
|
||||||
|
if (pEntry->pszShortName == NULL)
|
||||||
|
{
|
||||||
|
dwError = ERROR_OUTOFMEMORY;
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
|
||||||
|
wcscpy(pEntry->pszShortName, pszStart);
|
||||||
|
|
||||||
|
pEntry->pszValueName = HeapAlloc(GetProcessHeap(),
|
||||||
|
HEAP_ZERO_MEMORY,
|
||||||
|
(wcslen(pEntry->pszShortName) + 1) * sizeof(WCHAR));
|
||||||
|
if (pEntry->pszValueName == NULL)
|
||||||
|
{
|
||||||
|
dwError = ERROR_OUTOFMEMORY;
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
|
||||||
|
wcscpy(pEntry->pszValueName, pEntry->pszShortName);
|
||||||
|
|
||||||
|
pszEnd = wcsrchr(pEntry->pszValueName, L'.');
|
||||||
|
if (pszEnd != NULL)
|
||||||
|
*pszEnd = UNICODE_NULL;
|
||||||
|
|
||||||
|
if (pDllListTail == NULL)
|
||||||
|
{
|
||||||
|
pEntry->pPrev = NULL;
|
||||||
|
pEntry->pNext = NULL;
|
||||||
|
pDllListHead = pEntry;
|
||||||
|
pDllListTail = pEntry;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
pEntry->pPrev = NULL;
|
||||||
|
pEntry->pNext = pDllListHead;
|
||||||
|
pDllListHead->pPrev = pEntry;
|
||||||
|
pDllListHead = pEntry;
|
||||||
|
}
|
||||||
|
|
||||||
|
bInserted = TRUE;
|
||||||
|
|
||||||
|
pEntry->hModule = LoadLibraryW(pEntry->pszDllName);
|
||||||
|
if (pEntry->hModule == NULL)
|
||||||
|
{
|
||||||
|
dwError = GetLastError();
|
||||||
|
DPRINT1("Could not load the helper dll %S (Error: %lu)\n", pEntry->pszDllName, dwError);
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
|
||||||
|
pInitHelperDll = (PNS_DLL_INIT_FN)GetProcAddress(pEntry->hModule, "InitHelperDll");
|
||||||
|
if (pInitHelperDll == NULL)
|
||||||
|
{
|
||||||
|
dwError = GetLastError();
|
||||||
|
DPRINT1("Could not find 'InitHelperDll' (Error: %lu)\n", dwError);
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
|
||||||
|
pCurrentDll = pEntry;
|
||||||
|
dwError = pInitHelperDll(5, NULL);
|
||||||
|
pCurrentDll = NULL;
|
||||||
|
|
||||||
|
DPRINT1("InitHelperDll returned %lu\n", dwError);
|
||||||
|
if (dwError != ERROR_SUCCESS)
|
||||||
|
{
|
||||||
|
DPRINT1("Call to InitHelperDll failed (Error: %lu)\n", dwError);
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
|
||||||
|
// if (pEntry->Attributes.pfnStart)
|
||||||
|
// pEntry->Attributes.pfnStart(NULL, 0);
|
||||||
|
|
||||||
|
if (bRegister)
|
||||||
|
RegisterHelperDll(pEntry);
|
||||||
|
|
||||||
|
done:
|
||||||
|
if (dwError != ERROR_SUCCESS)
|
||||||
|
{
|
||||||
|
if (bInserted)
|
||||||
|
{
|
||||||
|
if (pEntry->pPrev != NULL)
|
||||||
|
pEntry->pPrev->pNext = pEntry->pNext;
|
||||||
|
if (pEntry->pNext != NULL)
|
||||||
|
pEntry->pNext->pPrev = pEntry->pPrev;
|
||||||
|
if (pDllListTail == pEntry)
|
||||||
|
pDllListTail = pEntry->pPrev;
|
||||||
|
if (pDllListHead == pEntry)
|
||||||
|
pDllListHead = pEntry->pNext;
|
||||||
|
pEntry->pPrev = NULL;
|
||||||
|
pEntry->pNext = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
FreeHelperDll(pEntry);
|
||||||
|
}
|
||||||
|
|
||||||
|
return dwError;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
VOID
|
||||||
|
LoadHelpers(VOID)
|
||||||
|
{
|
||||||
|
PWSTR pszNameBuffer = NULL;
|
||||||
|
PWSTR pszValueBuffer = NULL;
|
||||||
|
HKEY hKey;
|
||||||
|
DWORD dwValueCount, dwMaxNameLength, dwMaxValueLength;
|
||||||
|
DWORD dwNameLength, dwValueLength, dwType;
|
||||||
|
DWORD dwIndex, dwError;
|
||||||
|
|
||||||
|
DPRINT1("LoadHelpers()\n");
|
||||||
|
|
||||||
|
dwError = RegOpenKeyExW(HKEY_LOCAL_MACHINE,
|
||||||
|
REG_NETSH_PATH,
|
||||||
|
0,
|
||||||
|
KEY_READ,
|
||||||
|
&hKey);
|
||||||
|
if (dwError != ERROR_SUCCESS)
|
||||||
|
return;
|
||||||
|
|
||||||
|
dwError = RegQueryInfoKeyW(hKey,
|
||||||
|
NULL,
|
||||||
|
NULL,
|
||||||
|
NULL,
|
||||||
|
NULL,
|
||||||
|
NULL,
|
||||||
|
NULL,
|
||||||
|
&dwValueCount,
|
||||||
|
&dwMaxNameLength,
|
||||||
|
&dwMaxValueLength,
|
||||||
|
NULL,
|
||||||
|
NULL);
|
||||||
|
if (dwError != ERROR_SUCCESS)
|
||||||
|
goto done;
|
||||||
|
|
||||||
|
pszNameBuffer = HeapAlloc(GetProcessHeap(), 0,
|
||||||
|
(dwMaxNameLength + 1) * sizeof(WCHAR));
|
||||||
|
if (pszNameBuffer == NULL)
|
||||||
|
goto done;
|
||||||
|
|
||||||
|
pszValueBuffer = HeapAlloc(GetProcessHeap(), 0,
|
||||||
|
dwMaxValueLength + sizeof(WCHAR));
|
||||||
|
if (pszValueBuffer == NULL)
|
||||||
|
goto done;
|
||||||
|
|
||||||
|
for (dwIndex = 0; dwIndex < dwValueCount; dwIndex++)
|
||||||
|
{
|
||||||
|
dwNameLength = dwMaxNameLength + 1;
|
||||||
|
dwValueLength = dwMaxValueLength + sizeof(WCHAR);
|
||||||
|
dwError = RegEnumValueW(hKey,
|
||||||
|
dwIndex,
|
||||||
|
pszNameBuffer,
|
||||||
|
&dwNameLength,
|
||||||
|
NULL,
|
||||||
|
&dwType,
|
||||||
|
(PBYTE)pszValueBuffer,
|
||||||
|
&dwValueLength);
|
||||||
|
if (dwError != ERROR_SUCCESS)
|
||||||
|
break;
|
||||||
|
|
||||||
|
DPRINT1("Dll: %S --> %S %lu\n", pszNameBuffer, pszValueBuffer, dwError);
|
||||||
|
LoadHelperDll(pszValueBuffer, FALSE);
|
||||||
|
}
|
||||||
|
|
||||||
|
done:
|
||||||
|
if (pszValueBuffer)
|
||||||
|
HeapFree(GetProcessHeap(), 0, pszValueBuffer);
|
||||||
|
|
||||||
|
if (pszNameBuffer)
|
||||||
|
HeapFree(GetProcessHeap(), 0, pszNameBuffer);
|
||||||
|
|
||||||
|
RegCloseKey(hKey);
|
||||||
|
|
||||||
|
StartHelpers();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
VOID
|
||||||
|
UnloadHelpers(VOID)
|
||||||
|
{
|
||||||
|
PDLL_LIST_ENTRY pEntry;
|
||||||
|
|
||||||
|
while (pDllListHead != NULL)
|
||||||
|
{
|
||||||
|
pEntry = pDllListHead;
|
||||||
|
pDllListHead = pEntry->pNext;
|
||||||
|
|
||||||
|
// if (pEntry->Attributes.pfnStop)
|
||||||
|
// pEntry->Attributes.pfnStop(0);
|
||||||
|
|
||||||
|
FreeHelperDll(pEntry);
|
||||||
|
}
|
||||||
|
|
||||||
|
pDllListTail = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
PHELPER_ENTRY
|
||||||
|
FindHelper(
|
||||||
|
_In_ const GUID *pguidHelper)
|
||||||
|
{
|
||||||
|
PHELPER_ENTRY pHelper;
|
||||||
|
|
||||||
|
pHelper = pHelperListHead;
|
||||||
|
while (pHelper != NULL)
|
||||||
|
{
|
||||||
|
if (IsEqualGUID(pguidHelper, &pHelper->Attributes.guidHelper))
|
||||||
|
return pHelper;
|
||||||
|
|
||||||
|
pHelper = pHelper->pNext;
|
||||||
|
}
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
DWORD
|
||||||
|
WINAPI
|
||||||
|
RegisterHelper(
|
||||||
|
_In_ const GUID *pguidParentHelper,
|
||||||
|
_In_ const NS_HELPER_ATTRIBUTES *pHelperAttributes)
|
||||||
|
{
|
||||||
|
PHELPER_ENTRY pHelper = NULL, pParentHelper;
|
||||||
|
DWORD dwError = ERROR_SUCCESS;
|
||||||
|
|
||||||
|
DPRINT("RegisterHelper(%p %p)\n", pguidParentHelper, pHelperAttributes);
|
||||||
|
|
||||||
|
if (FindHelper(&pHelperAttributes->guidHelper) != NULL)
|
||||||
|
{
|
||||||
|
DPRINT1("The Helper has already been registered!\n");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
pHelper = (PHELPER_ENTRY)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(HELPER_ENTRY));
|
||||||
|
if (pHelper == NULL)
|
||||||
|
{
|
||||||
|
dwError = ERROR_OUTOFMEMORY;
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
|
||||||
|
CopyMemory(&pHelper->Attributes, pHelperAttributes, sizeof(NS_HELPER_ATTRIBUTES));
|
||||||
|
pHelper->pDllEntry = pCurrentDll;
|
||||||
|
DPRINT("pHelper->pDllEntry: %p\n", pHelper->pDllEntry);
|
||||||
|
|
||||||
|
if (pguidParentHelper == NULL)
|
||||||
|
{
|
||||||
|
if (pHelperListTail == NULL)
|
||||||
|
{
|
||||||
|
pHelperListHead = pHelper;
|
||||||
|
pHelperListTail = pHelper;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
pHelper->pNext = pHelperListHead;
|
||||||
|
pHelperListHead->pPrev = pHelper;
|
||||||
|
pHelperListHead = pHelper;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
pParentHelper = FindHelper(&pHelperAttributes->guidHelper);
|
||||||
|
if (pParentHelper == NULL)
|
||||||
|
return ERROR_INVALID_PARAMETER;
|
||||||
|
|
||||||
|
if (pParentHelper->pSubHelperHead == NULL && pParentHelper->pSubHelperTail == NULL)
|
||||||
|
{
|
||||||
|
pParentHelper->pSubHelperHead = pHelper;
|
||||||
|
pParentHelper->pSubHelperTail = pHelper;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
pHelper->pPrev = pParentHelper->pSubHelperTail;
|
||||||
|
pParentHelper->pSubHelperTail->pNext = pHelper;
|
||||||
|
pParentHelper->pSubHelperTail = pHelper;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
done:
|
||||||
|
|
||||||
|
return dwError;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
DWORD
|
||||||
|
WINAPI
|
||||||
|
AddHelperCommand(
|
||||||
|
LPCWSTR pwszMachine,
|
||||||
|
LPWSTR *ppwcArguments,
|
||||||
|
DWORD dwCurrentIndex,
|
||||||
|
DWORD dwArgCount,
|
||||||
|
DWORD dwFlags,
|
||||||
|
LPCVOID pvData,
|
||||||
|
BOOL *pbDone)
|
||||||
|
{
|
||||||
|
DWORD dwError = ERROR_SUCCESS;
|
||||||
|
|
||||||
|
DPRINT("AddHelperCommand()\n");
|
||||||
|
|
||||||
|
if (dwArgCount == 2)
|
||||||
|
{
|
||||||
|
// ConResPrintf(StdErr, IDS_INVALID_SYNTAX);
|
||||||
|
// ConResPrintf(StdErr, IDS_HLP_ADD_HELPER_EX);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
dwError = LoadHelperDll(ppwcArguments[2], TRUE);
|
||||||
|
if (dwError != ERROR_SUCCESS)
|
||||||
|
return dwError;
|
||||||
|
|
||||||
|
StartHelpers();
|
||||||
|
|
||||||
|
return ERROR_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
DWORD
|
||||||
|
WINAPI
|
||||||
|
DeleteHelperCommand(
|
||||||
|
LPCWSTR pwszMachine,
|
||||||
|
LPWSTR *ppwcArguments,
|
||||||
|
DWORD dwCurrentIndex,
|
||||||
|
DWORD dwArgCount,
|
||||||
|
DWORD dwFlags,
|
||||||
|
LPCVOID pvData,
|
||||||
|
BOOL *pbDone)
|
||||||
|
{
|
||||||
|
PDLL_LIST_ENTRY pEntry;
|
||||||
|
HKEY hKey;
|
||||||
|
DWORD dwError;
|
||||||
|
|
||||||
|
DPRINT("DeleteHelper()\n");
|
||||||
|
|
||||||
|
if (dwArgCount == 2)
|
||||||
|
{
|
||||||
|
// ConResPrintf(StdErr, IDS_INVALID_SYNTAX);
|
||||||
|
// ConResPrintf(StdErr, IDS_HLP_DEL_HELPER_EX);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
pEntry = pDllListHead;
|
||||||
|
while (pEntry != NULL)
|
||||||
|
{
|
||||||
|
if (wcscmp(pEntry->pszShortName, ppwcArguments[2]) == 0)
|
||||||
|
{
|
||||||
|
DPRINT1("remove %S\n", pEntry->pszShortName);
|
||||||
|
|
||||||
|
if (pEntry->pPrev != NULL)
|
||||||
|
pEntry->pPrev->pNext = pEntry->pNext;
|
||||||
|
if (pEntry->pNext != NULL)
|
||||||
|
pEntry->pNext->pPrev = pEntry->pPrev;
|
||||||
|
if (pDllListTail == pEntry)
|
||||||
|
pDllListTail = pEntry->pPrev;
|
||||||
|
if (pDllListHead == pEntry)
|
||||||
|
pDllListHead = pEntry->pNext;
|
||||||
|
pEntry->pPrev = NULL;
|
||||||
|
pEntry->pNext = NULL;
|
||||||
|
|
||||||
|
dwError = RegOpenKeyExW(HKEY_LOCAL_MACHINE,
|
||||||
|
REG_NETSH_PATH,
|
||||||
|
0,
|
||||||
|
KEY_WRITE,
|
||||||
|
&hKey);
|
||||||
|
if (dwError == ERROR_SUCCESS)
|
||||||
|
{
|
||||||
|
RegDeleteValue(hKey, pEntry->pszValueName);
|
||||||
|
RegCloseKey(hKey);
|
||||||
|
}
|
||||||
|
|
||||||
|
FreeHelperDll(pEntry);
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
pEntry = pEntry->pNext;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ERROR_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static
|
||||||
|
VOID
|
||||||
|
PrintSubContext(
|
||||||
|
_In_ PCONTEXT_ENTRY pParentContext,
|
||||||
|
_In_ DWORD dwLevel)
|
||||||
|
{
|
||||||
|
PCONTEXT_ENTRY pContext;
|
||||||
|
PHELPER_ENTRY pHelper;
|
||||||
|
WCHAR szPrefix[22];
|
||||||
|
DWORD i;
|
||||||
|
|
||||||
|
if (pParentContext == NULL)
|
||||||
|
return;
|
||||||
|
|
||||||
|
pContext = pParentContext->pSubContextHead;
|
||||||
|
while (pContext != NULL)
|
||||||
|
{
|
||||||
|
pHelper = FindHelper(&pContext->Guid);
|
||||||
|
if (pHelper != NULL)
|
||||||
|
{
|
||||||
|
if (dwLevel > 10)
|
||||||
|
dwLevel = 10;
|
||||||
|
|
||||||
|
for (i = 0; i < dwLevel * 2; i++)
|
||||||
|
szPrefix[i] = L' ';
|
||||||
|
szPrefix[i] = UNICODE_NULL;
|
||||||
|
|
||||||
|
ConPrintf(StdOut, L"{%08lX-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X} %-16s %s%s\n",
|
||||||
|
pHelper->Attributes.guidHelper.Data1,
|
||||||
|
pHelper->Attributes.guidHelper.Data2,
|
||||||
|
pHelper->Attributes.guidHelper.Data3,
|
||||||
|
pHelper->Attributes.guidHelper.Data4[0],
|
||||||
|
pHelper->Attributes.guidHelper.Data4[1],
|
||||||
|
pHelper->Attributes.guidHelper.Data4[2],
|
||||||
|
pHelper->Attributes.guidHelper.Data4[3],
|
||||||
|
pHelper->Attributes.guidHelper.Data4[4],
|
||||||
|
pHelper->Attributes.guidHelper.Data4[5],
|
||||||
|
pHelper->Attributes.guidHelper.Data4[6],
|
||||||
|
pHelper->Attributes.guidHelper.Data4[7],
|
||||||
|
pHelper->pDllEntry->pszShortName,
|
||||||
|
szPrefix,
|
||||||
|
pContext->pszContextName);
|
||||||
|
}
|
||||||
|
|
||||||
|
PrintSubContext(pContext, dwLevel + 1);
|
||||||
|
|
||||||
|
pContext = pContext->pNext;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
DWORD
|
||||||
|
WINAPI
|
||||||
|
ShowHelperCommand(
|
||||||
|
LPCWSTR pwszMachine,
|
||||||
|
LPWSTR *ppwcArguments,
|
||||||
|
DWORD dwCurrentIndex,
|
||||||
|
DWORD dwArgCount,
|
||||||
|
DWORD dwFlags,
|
||||||
|
LPCVOID pvData,
|
||||||
|
BOOL *pbDone)
|
||||||
|
{
|
||||||
|
DPRINT("ShowHelperCommand()\n");
|
||||||
|
|
||||||
|
ConPrintf(StdOut, L"Helper GUID DLL Name Command\n");
|
||||||
|
ConPrintf(StdOut, L"-------------------------------------- ---------------- --------\n");
|
||||||
|
|
||||||
|
if (pRootContext == NULL)
|
||||||
|
return ERROR_SUCCESS;
|
||||||
|
|
||||||
|
PrintSubContext(pRootContext, 0);
|
||||||
|
|
||||||
|
return ERROR_SUCCESS;
|
||||||
|
}
|
238
base/applications/network/netsh/interpreter.c
Normal file
238
base/applications/network/netsh/interpreter.c
Normal file
|
@ -0,0 +1,238 @@
|
||||||
|
/*
|
||||||
|
* PROJECT: ReactOS NetSh
|
||||||
|
* LICENSE: GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later)
|
||||||
|
* PURPOSE: Network Shell command interpreter
|
||||||
|
* COPYRIGHT: Copyright 2023 Eric Kohl <eric.kohl@reactos.org>
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* INCLUDES *******************************************************************/
|
||||||
|
|
||||||
|
#include "precomp.h"
|
||||||
|
|
||||||
|
#define NDEBUG
|
||||||
|
#include <debug.h>
|
||||||
|
|
||||||
|
/* FUNCTIONS *****************************************************************/
|
||||||
|
|
||||||
|
BOOL
|
||||||
|
InterpretCommand(
|
||||||
|
_In_ LPWSTR *argv,
|
||||||
|
_In_ DWORD dwArgCount)
|
||||||
|
{
|
||||||
|
PCONTEXT_ENTRY pContext, pSubContext;
|
||||||
|
PCOMMAND_ENTRY pCommand;
|
||||||
|
PCOMMAND_GROUP pGroup;
|
||||||
|
BOOL bDone = FALSE;
|
||||||
|
DWORD dwHelpLevel = 0;
|
||||||
|
DWORD dwError = ERROR_SUCCESS;
|
||||||
|
|
||||||
|
/* If no args provided */
|
||||||
|
if (dwArgCount == 0)
|
||||||
|
return TRUE;
|
||||||
|
|
||||||
|
if (pCurrentContext == NULL)
|
||||||
|
{
|
||||||
|
DPRINT1("InterpretCmd: invalid context %p\n", pCurrentContext);
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((wcsicmp(argv[dwArgCount - 1], L"?") == 0) ||
|
||||||
|
(wcsicmp(argv[dwArgCount - 1], L"help") == 0))
|
||||||
|
{
|
||||||
|
dwHelpLevel = dwArgCount - 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
pContext = pCurrentContext;
|
||||||
|
|
||||||
|
while (TRUE)
|
||||||
|
{
|
||||||
|
pCommand = pContext->pCommandListHead;
|
||||||
|
while (pCommand != NULL)
|
||||||
|
{
|
||||||
|
if (wcsicmp(argv[0], pCommand->pwszCmdToken) == 0)
|
||||||
|
{
|
||||||
|
if (dwHelpLevel == 1)
|
||||||
|
{
|
||||||
|
ConResPrintf(StdOut, pCommand->dwCmdHlpToken);
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
dwError = pCommand->pfnCmdHandler(NULL, argv, 0, dwArgCount, 0, NULL, &bDone);
|
||||||
|
if (dwError != ERROR_SUCCESS)
|
||||||
|
{
|
||||||
|
ConPrintf(StdOut, L"Error: %lu\n\n");
|
||||||
|
ConResPrintf(StdOut, pCommand->dwCmdHlpToken);
|
||||||
|
}
|
||||||
|
return !bDone;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pCommand = pCommand->pNext;
|
||||||
|
}
|
||||||
|
|
||||||
|
pGroup = pContext->pGroupListHead;
|
||||||
|
while (pGroup != NULL)
|
||||||
|
{
|
||||||
|
if (wcsicmp(argv[0], pGroup->pwszCmdGroupToken) == 0)
|
||||||
|
{
|
||||||
|
if (dwHelpLevel == 1)
|
||||||
|
{
|
||||||
|
HelpGroup(pGroup);
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
pCommand = pGroup->pCommandListHead;
|
||||||
|
while (pCommand != NULL)
|
||||||
|
{
|
||||||
|
if ((dwArgCount > 1) && (wcsicmp(argv[1], pCommand->pwszCmdToken) == 0))
|
||||||
|
{
|
||||||
|
if (dwHelpLevel == 2)
|
||||||
|
{
|
||||||
|
ConResPrintf(StdOut, pCommand->dwCmdHlpToken);
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
dwError = pCommand->pfnCmdHandler(NULL, argv, 1, dwArgCount, 0, NULL, &bDone);
|
||||||
|
if (dwError != ERROR_SUCCESS)
|
||||||
|
{
|
||||||
|
ConPrintf(StdOut, L"Error: %lu\n\n");
|
||||||
|
ConResPrintf(StdOut, pCommand->dwCmdHlpToken);
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
return !bDone;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pCommand = pCommand->pNext;
|
||||||
|
}
|
||||||
|
|
||||||
|
HelpGroup(pGroup);
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
pGroup = pGroup->pNext;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pContext == pCurrentContext)
|
||||||
|
{
|
||||||
|
pSubContext = pContext->pSubContextHead;
|
||||||
|
while (pSubContext != NULL)
|
||||||
|
{
|
||||||
|
if (wcsicmp(argv[0], pSubContext->pszContextName) == 0)
|
||||||
|
{
|
||||||
|
pCurrentContext = pSubContext;
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
pSubContext = pSubContext->pNext;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pContext == pRootContext)
|
||||||
|
break;
|
||||||
|
|
||||||
|
pContext = pContext->pParentContext;
|
||||||
|
}
|
||||||
|
|
||||||
|
ConResPrintf(StdErr, IDS_INVALID_COMMAND, argv[0]);
|
||||||
|
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* InterpretScript(char *line):
|
||||||
|
* The main function used for when reading commands from scripts.
|
||||||
|
*/
|
||||||
|
BOOL
|
||||||
|
InterpretScript(
|
||||||
|
_In_ LPWSTR pszInputLine)
|
||||||
|
{
|
||||||
|
LPWSTR args_vector[MAX_ARGS_COUNT];
|
||||||
|
DWORD dwArgCount = 0;
|
||||||
|
BOOL bWhiteSpace = TRUE;
|
||||||
|
LPWSTR ptr;
|
||||||
|
|
||||||
|
memset(args_vector, 0, sizeof(args_vector));
|
||||||
|
|
||||||
|
ptr = pszInputLine;
|
||||||
|
while (*ptr != 0)
|
||||||
|
{
|
||||||
|
if (iswspace(*ptr) || *ptr == L'\n')
|
||||||
|
{
|
||||||
|
*ptr = 0;
|
||||||
|
bWhiteSpace = TRUE;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if ((bWhiteSpace != FALSE) && (dwArgCount < MAX_ARGS_COUNT))
|
||||||
|
{
|
||||||
|
args_vector[dwArgCount] = ptr;
|
||||||
|
dwArgCount++;
|
||||||
|
}
|
||||||
|
|
||||||
|
bWhiteSpace = FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
ptr++;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* sends the string to find the command */
|
||||||
|
return InterpretCommand(args_vector, dwArgCount);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
VOID
|
||||||
|
InterpretInteractive(VOID)
|
||||||
|
{
|
||||||
|
WCHAR input_line[MAX_STRING_SIZE];
|
||||||
|
LPWSTR args_vector[MAX_ARGS_COUNT];
|
||||||
|
DWORD dwArgCount = 0;
|
||||||
|
BOOL bWhiteSpace = TRUE;
|
||||||
|
BOOL bRun = TRUE;
|
||||||
|
LPWSTR ptr;
|
||||||
|
|
||||||
|
while (bRun != FALSE)
|
||||||
|
{
|
||||||
|
dwArgCount = 0;
|
||||||
|
memset(args_vector, 0, sizeof(args_vector));
|
||||||
|
|
||||||
|
/* Shown just before the input where the user places commands */
|
||||||
|
// ConResPuts(StdOut, IDS_APP_PROMPT);
|
||||||
|
ConPuts(StdOut, L"netsh");
|
||||||
|
if (pCurrentContext != pRootContext)
|
||||||
|
{
|
||||||
|
ConPuts(StdOut, L" ");
|
||||||
|
ConPuts(StdOut, pCurrentContext->pszContextName);
|
||||||
|
}
|
||||||
|
ConPuts(StdOut, L">");
|
||||||
|
|
||||||
|
/* Get input from the user. */
|
||||||
|
fgetws(input_line, MAX_STRING_SIZE, stdin);
|
||||||
|
|
||||||
|
ptr = input_line;
|
||||||
|
while (*ptr != 0)
|
||||||
|
{
|
||||||
|
if (iswspace(*ptr) || *ptr == L'\n')
|
||||||
|
{
|
||||||
|
*ptr = 0;
|
||||||
|
bWhiteSpace = TRUE;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if ((bWhiteSpace != FALSE) && (dwArgCount < MAX_ARGS_COUNT))
|
||||||
|
{
|
||||||
|
args_vector[dwArgCount] = ptr;
|
||||||
|
dwArgCount++;
|
||||||
|
}
|
||||||
|
bWhiteSpace = FALSE;
|
||||||
|
}
|
||||||
|
ptr++;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Send the string to find the command */
|
||||||
|
bRun = InterpretCommand(args_vector, dwArgCount);
|
||||||
|
}
|
||||||
|
}
|
36
base/applications/network/netsh/lang/en-US.rc
Normal file
36
base/applications/network/netsh/lang/en-US.rc
Normal file
|
@ -0,0 +1,36 @@
|
||||||
|
LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
|
||||||
|
|
||||||
|
/* Basic application information */
|
||||||
|
STRINGTABLE
|
||||||
|
BEGIN
|
||||||
|
IDS_APP_USAGE "\nUsage: netsh [-a AliasFile] [-c Context] [-r RemoteMachine] \
|
||||||
|
\n [Command | -f ScriptFile]\n"
|
||||||
|
IDS_INVALID_COMMAND "The following command was not found: %ls.\n"
|
||||||
|
IDS_OPEN_FAILED "The file %ls could not be openend.\n"
|
||||||
|
IDS_INVALID_SYNTAX "The syntax supplied for this command is not valid. Check help for the correct syntax.\n\n"
|
||||||
|
END
|
||||||
|
|
||||||
|
STRINGTABLE
|
||||||
|
BEGIN
|
||||||
|
IDS_HELP_HEADER "\nThe following commands are available:\n"
|
||||||
|
IDS_SUBCONTEXT_HEADER "\nThe following sub-contexts are available:\n"
|
||||||
|
IDS_HLP_UP "Goes up one context level."
|
||||||
|
IDS_HLP_UP_EX "Syntax: ..\n\n Goes up one context level.\n\n"
|
||||||
|
IDS_HLP_EXIT "Exits the program."
|
||||||
|
IDS_HLP_EXIT_EX "Syntax: exit\n\n Exits the program.\n\n"
|
||||||
|
IDS_HLP_HELP "Displays a list of commands."
|
||||||
|
IDS_HLP_HELP_EX "Syntax: help\n\n Displays a list of commands.\n\n"
|
||||||
|
|
||||||
|
IDS_HLP_ADD_HELPER "Installs a helper DLL."
|
||||||
|
IDS_HLP_ADD_HELPER_EX "Syntax: add helper <dll file name>\n\n Installs the specified helper DLL in netsh.\n\n"
|
||||||
|
|
||||||
|
IDS_HLP_DEL_HELPER "Removes a helper DLL."
|
||||||
|
IDS_HLP_DEL_HELPER_EX "Syntax: delete helper <dll file name>\n\n Removes the specified helper DLL from netsh.\n\n"
|
||||||
|
|
||||||
|
IDS_HLP_SHOW_HELPER "Lists all the top-level helpers."
|
||||||
|
IDS_HLP_SHOW_HELPER_EX "Syntax: show helper\n\n Lists all the top-level helpers.\n\n"
|
||||||
|
|
||||||
|
IDS_HLP_GROUP_ADD "Adds a configuration entry to a list of entries."
|
||||||
|
IDS_HLP_GROUP_DELETE "Deletes a configuration entry from a list of entries."
|
||||||
|
IDS_HLP_GROUP_SHOW "Displays information."
|
||||||
|
END
|
|
@ -1,33 +1,254 @@
|
||||||
/*
|
/*
|
||||||
* Copyright 2010 Hans Leidekker for CodeWeavers
|
* PROJECT: ReactOS NetSh
|
||||||
*
|
* LICENSE: GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later)
|
||||||
* This library is free software; you can redistribute it and/or
|
* PURPOSE: Network Shell main file
|
||||||
* modify it under the terms of the GNU Lesser General Public
|
* COPYRIGHT: Copyright 2023 Eric Kohl <eric.kohl@reactos.org>
|
||||||
* 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <wine/debug.h>
|
/* INCLUDES *******************************************************************/
|
||||||
|
|
||||||
WINE_DEFAULT_DEBUG_CHANNEL(netsh);
|
#include "precomp.h"
|
||||||
|
|
||||||
int wmain(int argc, WCHAR *argv[])
|
#define NDEBUG
|
||||||
|
#include <debug.h>
|
||||||
|
|
||||||
|
/* FUNCTIONS ******************************************************************/
|
||||||
|
|
||||||
|
BOOL
|
||||||
|
RunScript(
|
||||||
|
_In_ LPCWSTR filename)
|
||||||
{
|
{
|
||||||
int i;
|
FILE *script;
|
||||||
|
WCHAR tmp_string[MAX_STRING_SIZE];
|
||||||
|
|
||||||
WINE_FIXME("stub:");
|
/* Open the file for processing */
|
||||||
for (i = 0; i < argc; i++)
|
script = _wfopen(filename, L"r");
|
||||||
WINE_FIXME(" %s", wine_dbgstr_w(argv[i]));
|
if (script == NULL)
|
||||||
WINE_FIXME("\n");
|
{
|
||||||
|
ConResPrintf(StdErr, IDS_OPEN_FAILED, filename);
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Read and process the script */
|
||||||
|
while (fgetws(tmp_string, MAX_STRING_SIZE, script) != NULL)
|
||||||
|
{
|
||||||
|
if (InterpretScript(tmp_string) == FALSE)
|
||||||
|
{
|
||||||
|
fclose(script);
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Close the file */
|
||||||
|
fclose(script);
|
||||||
|
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* wmain():
|
||||||
|
* Main entry point of the application.
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
wmain(
|
||||||
|
_In_ int argc,
|
||||||
|
_In_ const LPWSTR argv[])
|
||||||
|
{
|
||||||
|
LPCWSTR tmpBuffer = NULL;
|
||||||
|
LPCWSTR pszFileName = NULL;
|
||||||
|
int index;
|
||||||
|
int result = EXIT_SUCCESS;
|
||||||
|
|
||||||
|
DPRINT("main()\n");
|
||||||
|
|
||||||
|
/* Initialize the Console Standard Streams */
|
||||||
|
ConInitStdStreams();
|
||||||
|
|
||||||
|
/* FIXME: Init code goes here */
|
||||||
|
CreateRootContext();
|
||||||
|
LoadHelpers();
|
||||||
|
|
||||||
|
if (argc < 2)
|
||||||
|
{
|
||||||
|
/* If there are no command arguments, then go straight to the interpreter */
|
||||||
|
InterpretInteractive();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* If there are command arguments, then process them */
|
||||||
|
for (index = 1; index < argc; index++)
|
||||||
|
{
|
||||||
|
if ((argv[index][0] == '/')||
|
||||||
|
(argv[index][0] == '-'))
|
||||||
|
{
|
||||||
|
tmpBuffer = argv[index] + 1;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (pszFileName != NULL)
|
||||||
|
{
|
||||||
|
ConResPuts(StdOut, IDS_APP_USAGE);
|
||||||
|
result = EXIT_FAILURE;
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Run a command from the command line */
|
||||||
|
if (InterpretCommand((LPWSTR*)&argv[index], argc - index) == FALSE)
|
||||||
|
result = EXIT_FAILURE;
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_wcsicmp(tmpBuffer, L"?") == 0)
|
||||||
|
{
|
||||||
|
/* Help option */
|
||||||
|
ConResPuts(StdOut, IDS_APP_USAGE);
|
||||||
|
result = EXIT_SUCCESS;
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
else if (_wcsicmp(tmpBuffer, L"a") == 0)
|
||||||
|
{
|
||||||
|
/* Aliasfile option */
|
||||||
|
if ((index + 1) < argc)
|
||||||
|
{
|
||||||
|
index++;
|
||||||
|
ConPuts(StdOut, L"\nThe -a option is not implemented yet\n");
|
||||||
|
// aliasfile = argv[index];
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ConResPuts(StdOut, IDS_APP_USAGE);
|
||||||
|
result = EXIT_FAILURE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (_wcsicmp(tmpBuffer, L"c") == 0)
|
||||||
|
{
|
||||||
|
/* Context option */
|
||||||
|
if ((index + 1) < argc)
|
||||||
|
{
|
||||||
|
index++;
|
||||||
|
ConPuts(StdOut, L"\nThe -c option is not implemented yet\n");
|
||||||
|
// context = argv[index];
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ConResPuts(StdOut, IDS_APP_USAGE);
|
||||||
|
result = EXIT_FAILURE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (_wcsicmp(tmpBuffer, L"f") == 0)
|
||||||
|
{
|
||||||
|
/* File option */
|
||||||
|
if ((index + 1) < argc)
|
||||||
|
{
|
||||||
|
index++;
|
||||||
|
pszFileName = argv[index];
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ConResPuts(StdOut, IDS_APP_USAGE);
|
||||||
|
result = EXIT_FAILURE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (_wcsicmp(tmpBuffer, L"r") == 0)
|
||||||
|
{
|
||||||
|
/* Remote option */
|
||||||
|
if ((index + 1) < argc)
|
||||||
|
{
|
||||||
|
index++;
|
||||||
|
ConPuts(StdOut, L"\nThe -r option is not implemented yet\n");
|
||||||
|
// remote = argv[index];
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ConResPuts(StdOut, IDS_APP_USAGE);
|
||||||
|
result = EXIT_FAILURE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* Invalid command */
|
||||||
|
ConResPrintf(StdOut, IDS_INVALID_COMMAND, argv[index]);
|
||||||
|
result = EXIT_FAILURE;
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Now we process the filename if it exists */
|
||||||
|
if (pszFileName != NULL)
|
||||||
|
{
|
||||||
|
if (RunScript(pszFileName) == FALSE)
|
||||||
|
{
|
||||||
|
result = EXIT_FAILURE;
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
done:
|
||||||
|
/* FIXME: Cleanup code goes here */
|
||||||
|
UnloadHelpers();
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
DWORD
|
||||||
|
WINAPI
|
||||||
|
MatchEnumTag(
|
||||||
|
_In_ HANDLE hModule,
|
||||||
|
_In_ LPCWSTR pwcArg,
|
||||||
|
_In_ DWORD dwNumArg,
|
||||||
|
_In_ const TOKEN_VALUE *pEnumTable,
|
||||||
|
_Out_ PDWORD pdwValue)
|
||||||
|
{
|
||||||
|
DPRINT1("MatchEnumTag()\n");
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
BOOL
|
||||||
|
WINAPI
|
||||||
|
MatchToken(
|
||||||
|
_In_ LPCWSTR pwszUserToken,
|
||||||
|
_In_ LPCWSTR pwszCmdToken)
|
||||||
|
{
|
||||||
|
DPRINT1("MatchToken %S %S\n", pwszUserToken, pwszCmdToken);
|
||||||
|
return (wcsicmp(pwszUserToken, pwszCmdToken) == 0) ? TRUE : FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
DWORD
|
||||||
|
CDECL
|
||||||
|
PrintError(
|
||||||
|
_In_opt_ HANDLE hModule,
|
||||||
|
_In_ DWORD dwErrId,
|
||||||
|
...)
|
||||||
|
{
|
||||||
|
DPRINT1("PrintError()\n");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
DWORD
|
||||||
|
CDECL
|
||||||
|
PrintMessageFromModule(
|
||||||
|
_In_ HANDLE hModule,
|
||||||
|
_In_ DWORD dwMsgId,
|
||||||
|
...)
|
||||||
|
{
|
||||||
|
DPRINT1("PrintMessageFromModule()\n");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
DWORD
|
||||||
|
CDECL
|
||||||
|
PrintMessage(
|
||||||
|
_In_ LPCWSTR pwszFormat,
|
||||||
|
...)
|
||||||
|
{
|
||||||
|
INT Length;
|
||||||
|
va_list ap;
|
||||||
|
|
||||||
|
va_start(ap, pwszFormat);
|
||||||
|
Length = ConPrintf(StdOut, pwszFormat);
|
||||||
|
va_end(ap);
|
||||||
|
|
||||||
|
return Length;
|
||||||
|
}
|
||||||
|
|
15
base/applications/network/netsh/netsh.rc
Normal file
15
base/applications/network/netsh/netsh.rc
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
#include <windef.h>
|
||||||
|
|
||||||
|
#include "resource.h"
|
||||||
|
|
||||||
|
#define REACTOS_STR_FILE_DESCRIPTION "Net Shell"
|
||||||
|
#define REACTOS_STR_INTERNAL_NAME "netsh"
|
||||||
|
#define REACTOS_STR_ORIGINAL_FILENAME "netsh.exe"
|
||||||
|
#include <reactos/version.rc>
|
||||||
|
|
||||||
|
/* UTF-8 */
|
||||||
|
#pragma code_page(65001)
|
||||||
|
|
||||||
|
#ifdef LANGUAGE_EN_US
|
||||||
|
#include "lang/en-US.rc"
|
||||||
|
#endif
|
7
base/applications/network/netsh/netsh.spec
Normal file
7
base/applications/network/netsh/netsh.spec
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
@ stdcall MatchEnumTag(ptr wstr long ptr ptr)
|
||||||
|
@ stdcall MatchToken(wstr wstr)
|
||||||
|
@ varargs PrintError(ptr long)
|
||||||
|
@ varargs PrintMessage(wstr)
|
||||||
|
@ varargs PrintMessageFromModule(ptr long)
|
||||||
|
@ stdcall RegisterContext(ptr)
|
||||||
|
@ stdcall RegisterHelper(ptr ptr)
|
205
base/applications/network/netsh/precomp.h
Normal file
205
base/applications/network/netsh/precomp.h
Normal file
|
@ -0,0 +1,205 @@
|
||||||
|
/*
|
||||||
|
* PROJECT: ReactOS NetSh
|
||||||
|
* LICENSE: GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later)
|
||||||
|
* PURPOSE: Network Shell main header file
|
||||||
|
* COPYRIGHT: Copyright 2023 Eric Kohl <eric.kohl@reactos.org>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef PRECOMP_H
|
||||||
|
#define PRECOMP_H
|
||||||
|
|
||||||
|
/* INCLUDES ******************************************************************/
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdarg.h>
|
||||||
|
|
||||||
|
#define WIN32_NO_STATUS
|
||||||
|
#include <windef.h>
|
||||||
|
#include <winbase.h>
|
||||||
|
#include <winreg.h>
|
||||||
|
#include <wincon.h>
|
||||||
|
#include <winuser.h>
|
||||||
|
|
||||||
|
#include <errno.h>
|
||||||
|
|
||||||
|
#include <conutils.h>
|
||||||
|
#include <netsh.h>
|
||||||
|
|
||||||
|
#include "resource.h"
|
||||||
|
|
||||||
|
|
||||||
|
/* DEFINES *******************************************************************/
|
||||||
|
|
||||||
|
#define MAX_STRING_SIZE 1024
|
||||||
|
#define MAX_ARGS_COUNT 256
|
||||||
|
|
||||||
|
#define REG_NETSH_PATH L"Software\\Microsoft\\NetSh"
|
||||||
|
|
||||||
|
|
||||||
|
/* TYPEDEFS ******************************************************************/
|
||||||
|
|
||||||
|
typedef struct _DLL_LIST_ENTRY
|
||||||
|
{
|
||||||
|
struct _DLL_LIST_ENTRY *pPrev;
|
||||||
|
struct _DLL_LIST_ENTRY *pNext;
|
||||||
|
|
||||||
|
PWSTR pszDllName;
|
||||||
|
PWSTR pszShortName;
|
||||||
|
PWSTR pszValueName;
|
||||||
|
|
||||||
|
HMODULE hModule;
|
||||||
|
|
||||||
|
} DLL_LIST_ENTRY, *PDLL_LIST_ENTRY;
|
||||||
|
|
||||||
|
typedef struct _HELPER_ENTRY
|
||||||
|
{
|
||||||
|
struct _HELPER_ENTRY *pPrev;
|
||||||
|
struct _HELPER_ENTRY *pNext;
|
||||||
|
|
||||||
|
NS_HELPER_ATTRIBUTES Attributes;
|
||||||
|
|
||||||
|
PDLL_LIST_ENTRY pDllEntry;
|
||||||
|
BOOL bStarted;
|
||||||
|
|
||||||
|
struct _HELPER_ENTRY *pSubHelperHead;
|
||||||
|
struct _HELPER_ENTRY *pSubHelperTail;
|
||||||
|
|
||||||
|
} HELPER_ENTRY, *PHELPER_ENTRY;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
typedef struct _COMMAND_ENTRY
|
||||||
|
{
|
||||||
|
struct _COMMAND_ENTRY *pPrev;
|
||||||
|
struct _COMMAND_ENTRY *pNext;
|
||||||
|
|
||||||
|
LPCWSTR pwszCmdToken;
|
||||||
|
PFN_HANDLE_CMD pfnCmdHandler;
|
||||||
|
DWORD dwShortCmdHelpToken;
|
||||||
|
DWORD dwCmdHlpToken;
|
||||||
|
DWORD dwFlags;
|
||||||
|
} COMMAND_ENTRY, *PCOMMAND_ENTRY;
|
||||||
|
|
||||||
|
typedef struct _COMMAND_GROUP
|
||||||
|
{
|
||||||
|
struct _COMMAND_GROUP *pPrev;
|
||||||
|
struct _COMMAND_GROUP *pNext;
|
||||||
|
|
||||||
|
LPCWSTR pwszCmdGroupToken;
|
||||||
|
DWORD dwShortCmdHelpToken;
|
||||||
|
DWORD dwFlags;
|
||||||
|
|
||||||
|
PCOMMAND_ENTRY pCommandListHead;
|
||||||
|
PCOMMAND_ENTRY pCommandListTail;
|
||||||
|
} COMMAND_GROUP, *PCOMMAND_GROUP;
|
||||||
|
|
||||||
|
typedef struct _CONTEXT_ENTRY
|
||||||
|
{
|
||||||
|
struct _CONTEXT_ENTRY *pPrev;
|
||||||
|
struct _CONTEXT_ENTRY *pNext;
|
||||||
|
|
||||||
|
struct _CONTEXT_ENTRY *pParentContext;
|
||||||
|
|
||||||
|
PWSTR pszContextName;
|
||||||
|
GUID Guid;
|
||||||
|
HMODULE hModule;
|
||||||
|
|
||||||
|
PCOMMAND_ENTRY pCommandListHead;
|
||||||
|
PCOMMAND_ENTRY pCommandListTail;
|
||||||
|
|
||||||
|
PCOMMAND_GROUP pGroupListHead;
|
||||||
|
PCOMMAND_GROUP pGroupListTail;
|
||||||
|
|
||||||
|
struct _CONTEXT_ENTRY *pSubContextHead;
|
||||||
|
struct _CONTEXT_ENTRY *pSubContextTail;
|
||||||
|
} CONTEXT_ENTRY, *PCONTEXT_ENTRY;
|
||||||
|
|
||||||
|
|
||||||
|
/* GLOBAL VARIABLES ***********************************************************/
|
||||||
|
|
||||||
|
extern PCONTEXT_ENTRY pRootContext;
|
||||||
|
extern PCONTEXT_ENTRY pCurrentContext;
|
||||||
|
|
||||||
|
|
||||||
|
/* PROTOTYPES *****************************************************************/
|
||||||
|
|
||||||
|
/* context.c */
|
||||||
|
|
||||||
|
BOOL
|
||||||
|
CreateRootContext(VOID);
|
||||||
|
|
||||||
|
|
||||||
|
/* help.c */
|
||||||
|
DWORD
|
||||||
|
WINAPI
|
||||||
|
HelpCommand(
|
||||||
|
LPCWSTR pwszMachine,
|
||||||
|
LPWSTR *ppwcArguments,
|
||||||
|
DWORD dwCurrentIndex,
|
||||||
|
DWORD dwArgCount,
|
||||||
|
DWORD dwFlags,
|
||||||
|
LPCVOID pvData,
|
||||||
|
BOOL *pbDone);
|
||||||
|
|
||||||
|
VOID
|
||||||
|
HelpGroup(
|
||||||
|
PCOMMAND_GROUP pGroup);
|
||||||
|
|
||||||
|
|
||||||
|
/* helper.c */
|
||||||
|
VOID
|
||||||
|
LoadHelpers(VOID);
|
||||||
|
|
||||||
|
VOID
|
||||||
|
UnloadHelpers(VOID);
|
||||||
|
|
||||||
|
|
||||||
|
DWORD
|
||||||
|
WINAPI
|
||||||
|
AddHelperCommand(
|
||||||
|
LPCWSTR pwszMachine,
|
||||||
|
LPWSTR *ppwcArguments,
|
||||||
|
DWORD dwCurrentIndex,
|
||||||
|
DWORD dwArgCount,
|
||||||
|
DWORD dwFlags,
|
||||||
|
LPCVOID pvData,
|
||||||
|
BOOL *pbDone);
|
||||||
|
|
||||||
|
DWORD
|
||||||
|
WINAPI
|
||||||
|
DeleteHelperCommand(
|
||||||
|
LPCWSTR pwszMachine,
|
||||||
|
LPWSTR *ppwcArguments,
|
||||||
|
DWORD dwCurrentIndex,
|
||||||
|
DWORD dwArgCount,
|
||||||
|
DWORD dwFlags,
|
||||||
|
LPCVOID pvData,
|
||||||
|
BOOL *pbDone);
|
||||||
|
|
||||||
|
DWORD
|
||||||
|
WINAPI
|
||||||
|
ShowHelperCommand(
|
||||||
|
LPCWSTR pwszMachine,
|
||||||
|
PWSTR *ppwcArguments,
|
||||||
|
DWORD dwCurrentIndex,
|
||||||
|
DWORD dwArgCount,
|
||||||
|
DWORD dwFlags,
|
||||||
|
LPCVOID pvData,
|
||||||
|
BOOL *pbDone);
|
||||||
|
|
||||||
|
|
||||||
|
/* interpreter.c */
|
||||||
|
BOOL
|
||||||
|
InterpretScript(
|
||||||
|
LPWSTR pszFileName);
|
||||||
|
|
||||||
|
BOOL
|
||||||
|
InterpretCommand(
|
||||||
|
LPWSTR *argv,
|
||||||
|
DWORD dwArgCount);
|
||||||
|
|
||||||
|
VOID
|
||||||
|
InterpretInteractive(VOID);
|
||||||
|
|
||||||
|
#endif /* PRECOMP_H */
|
37
base/applications/network/netsh/resource.h
Normal file
37
base/applications/network/netsh/resource.h
Normal file
|
@ -0,0 +1,37 @@
|
||||||
|
/*
|
||||||
|
* PROJECT: ReactOS NetSh
|
||||||
|
* LICENSE: GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later)
|
||||||
|
* PURPOSE: Network Shell resource id header file
|
||||||
|
* COPYRIGHT: Copyright 2023 Eric Kohl <eric.kohl@reactos.org>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#define IDS_NONE -1
|
||||||
|
|
||||||
|
#define IDS_APP_USAGE 100
|
||||||
|
#define IDS_APP_PROMPT 101
|
||||||
|
#define IDS_INVALID_COMMAND 102
|
||||||
|
#define IDS_OPEN_FAILED 103
|
||||||
|
#define IDS_INVALID_SYNTAX 104
|
||||||
|
|
||||||
|
#define IDS_HELP_HEADER 200
|
||||||
|
#define IDS_SUBCONTEXT_HEADER 201
|
||||||
|
|
||||||
|
#define IDS_HLP_EXIT 300
|
||||||
|
#define IDS_HLP_EXIT_EX 301
|
||||||
|
#define IDS_HLP_HELP 302
|
||||||
|
#define IDS_HLP_HELP_EX 303
|
||||||
|
#define IDS_HLP_UP 304
|
||||||
|
#define IDS_HLP_UP_EX 305
|
||||||
|
|
||||||
|
#define IDS_HLP_ADD_HELPER 310
|
||||||
|
#define IDS_HLP_ADD_HELPER_EX 311
|
||||||
|
#define IDS_HLP_DEL_HELPER 312
|
||||||
|
#define IDS_HLP_DEL_HELPER_EX 313
|
||||||
|
#define IDS_HLP_SHOW_HELPER 314
|
||||||
|
#define IDS_HLP_SHOW_HELPER_EX 315
|
||||||
|
|
||||||
|
#define IDS_HLP_GROUP_ADD 320
|
||||||
|
#define IDS_HLP_GROUP_DELETE 321
|
||||||
|
#define IDS_HLP_GROUP_SHOW 322
|
Loading…
Reference in a new issue