[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:
Eric Kohl 2023-07-15 12:27:09 +02:00
parent dabe7fba46
commit d8f9f7f256
11 changed files with 1923 additions and 28 deletions

View file

@ -1,8 +1,25 @@
add_definitions(-D__WINESRC__)
include_directories(${REACTOS_SOURCE_DIR}/sdk/include/wine)
add_executable(netsh netsh.c)
target_link_libraries(netsh wine)
include_directories(${REACTOS_SOURCE_DIR}/sdk/lib/conutils)
spec2def(netsh.exe netsh.spec ADD_IMPORTLIB)
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)
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)

View 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;
}

View 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;
}

View 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;
}

View 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);
}
}

View 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

View file

@ -1,33 +1,254 @@
/*
* Copyright 2010 Hans Leidekker for CodeWeavers
*
* 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
* PROJECT: ReactOS NetSh
* LICENSE: GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later)
* PURPOSE: Network Shell main file
* COPYRIGHT: Copyright 2023 Eric Kohl <eric.kohl@reactos.org>
*/
#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:");
for (i = 0; i < argc; i++)
WINE_FIXME(" %s", wine_dbgstr_w(argv[i]));
WINE_FIXME("\n");
/* Open the file for processing */
script = _wfopen(filename, L"r");
if (script == NULL)
{
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;
}
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;
}

View 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

View 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)

View 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 */

View 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