using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using System.Text;
using Vanara.Extensions;
using Vanara.InteropServices;
namespace Vanara.PInvoke
{
public static partial class Kernel32
{
/// Retrieves the application-specific portion of the search path used to locate DLLs for the application.
/// The size of the output buffer, in characters.
/// A pointer to a buffer that receives the application-specific portion of the search path.
///
///
/// If the function succeeds, the return value is the length of the string copied to lpBuffer, in characters, not including the
/// terminating null character. If the return value is greater than nBufferLength, it specifies the size of the buffer required for
/// the path.
///
/// If the function fails, the return value is zero. To get extended error information, call GetLastError.
///
// DWORD WINAPI GetDllDirectory( _In_ DWORD nBufferLength, _Out_ LPTSTR lpBuffer); https://msdn.microsoft.com/en-us/library/windows/desktop/ms683186(v=vs.85).aspx
[DllImport(Lib.Kernel32, SetLastError = true, CharSet = CharSet.Auto)]
[PInvokeData("WinBase.h", MSDNShortId = "ms683186")]
public static extern uint GetDllDirectory(uint nBufferLength, StringBuilder lpBuffer);
/// Retrieves the application-specific portion of the search path used to locate DLLs for the application.
/// The application-specific portion of the search path.
public static string GetDllDirectory() => FunctionHelper.CallMethodWithStrBuf((StringBuilder sb, ref uint sz) => GetDllDirectory(sz, sb), out var str, (sz, r) => r <= sz) > 0 ? str : throw Win32Error.GetLastError().GetException();
///
/// Loads and executes an application or creates a new instance of an existing application.
///
/// Note This function is provided only for compatibility with 16-bit versions of Windows. Applications should use the
/// CreateProcess function.
///
///
///
/// The file name of the application to be run. When specifying a path, be sure to use backslashes (), not forward slashes (/). If
/// the lpModuleName parameter does not contain a directory path, the system searches for the executable file in this order:
///
///
/// -
/// The directory from which the application loaded.
///
/// -
/// The current directory.
///
/// -
/// The system directory. Use the GetSystemDirectory function to get the path of this directory.
///
/// -
///
/// The 16-bit system directory. There is no function that obtains the path of this directory, but it is searched. The name of this
/// directory is System.
///
///
/// -
/// The Windows directory. Use the GetWindowsDirectory function to get the path of this directory.
///
/// -
/// The directories that are listed in the PATH environment variable.
///
///
/// A pointer to an application-defined LOADPARMS32 structure that defines the new application's parameter block.
///
/// Set all unused members to NULL, except for lpCmdLine, which must point to a null-terminated string if it is not used. For
/// more information, see Remarks.
///
///
/// If the function succeeds, the return value is greater than 31.
/// If the function fails, the return value is an error value, which may be one of the following values.
///
///
/// Return code/value
/// Description
///
/// -
/// 0
/// The system is out of memory or resources.
///
/// -
/// ERROR_BAD_FORMAT 11L
/// The .exe file is invalid.
///
/// -
/// ERROR_FILE_NOT_FOUND 2L
/// The specified file was not found.
///
/// -
/// ERROR_PATH_NOT_FOUND 3L
/// The specified path was not found.
///
///
///
///
/// The LOADPARMS32 structure has the following form:
///
///
/// Member
/// Meaning
///
/// -
/// lpEnvAddress
///
/// Pointer to an array of null-terminated strings that supply the environment strings for the new process. The array has a value of
/// NULL as its last entry. A value of NULL for this parameter causes the new process to start with the same environment as the
/// calling process.
///
///
/// -
/// lpCmdLine
///
/// Pointer to a Pascal-style string that contains a correctly formed command line. The first byte of the string contains the number
/// of bytes in the string. The remainder of the string contains the command line arguments, excluding the name of the child process.
/// If there are no command line arguments, this parameter must point to a zero length string; it cannot be NULL.
///
///
/// -
/// lpCmdShow
///
/// Pointer to a structure containing two WORD values. The first value must always be set to two. The second value specifies how the
/// application window is to be shown and is used to supply the wShowWindow member of the STARTUPINFO structure to the CreateProcess
/// function. See the description of the nCmdShow parameter of the ShowWindow function for a list of acceptable values.
///
///
/// -
/// dwReserved
/// This parameter is reserved; it must be zero.
///
///
///
/// Applications should use the CreateProcess function instead of LoadModule. The LoadModule function calls
/// CreateProcess by forming the parameters as follows.
///
///
///
/// CreateProcess parameter
/// Argument used
///
/// -
/// lpszApplicationName
/// lpModuleName
///
/// -
/// lpszCommandLine
/// lpParameterBlock.lpCmdLine
///
/// -
/// lpProcessAttributes
/// NULL
///
/// -
/// lpThreadAttributes
/// NULL
///
/// -
/// bInheritHandles
/// FALSE
///
/// -
/// dwCreationFlags
/// 0
///
/// -
/// lpEnvironment
/// lpParameterBlock.lpEnvAddress
///
/// -
/// lpCurrentDirectory
/// NULL
///
/// -
/// lpStartupInfo
///
/// The structure is initialized to zero. The cb member is set to the size of the structure. The wShowWindow member is set to the
/// value of the second word of lpParameterBlock.lpCmdShow.
///
///
/// -
/// lpProcessInformation.hProcess
/// The handle is immediately closed.
///
/// -
/// lpProcessInformation.hThread
/// The handle is immediately closed.
///
///
///
// https://docs.microsoft.com/en-us/windows/win32/api/winbase/nf-winbase-loadmodule DWORD LoadModule( LPCSTR lpModuleName, LPVOID
// lpParameterBlock );
[DllImport(Lib.Kernel32, SetLastError = false, ExactSpelling = true)]
[PInvokeData("winbase.h", MSDNShortId = "80571b80-851a-4272-bfa6-d26e217e714a")]
public static extern uint LoadModule([MarshalAs(UnmanagedType.LPStr)] string lpModuleName, [In] LOADPARMS32 lpParameterBlock);
/// Adds a directory to the search path used to locate DLLs for the application.
///
/// The directory to be added to the search path. If this parameter is an empty string (""), the call removes the current directory
/// from the default DLL search order. If this parameter is NULL, the function restores the default search order.
///
///
/// If the function succeeds, the return value is nonzero.
/// If the function fails, the return value is zero. To get extended error information, call GetLastError.
///
// BOOL WINAPI SetDllDirectory( _In_opt_ LPCTSTR lpPathName); https://msdn.microsoft.com/en-us/library/windows/desktop/ms686203(v=vs.85).aspx
[DllImport(Lib.Kernel32, SetLastError = true, CharSet = CharSet.Auto)]
[PInvokeData("Winbase.h", MSDNShortId = "ms686203")]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool SetDllDirectory(string lpPathName);
/// Defines the new application's parameter block.
[PInvokeData("winbase.h", MSDNShortId = "80571b80-851a-4272-bfa6-d26e217e714a")]
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
public class LOADPARMS32 : IDisposable
{
///
/// Pointer to an array of null-terminated strings that supply the environment strings for the new process. The array has a value
/// of NULL as its last entry. A value of NULL for this parameter causes the new process to start with the same environment as
/// the calling process.
///
private IntPtr lpEnvAddress;
///
/// Pointer to a Pascal-style string that contains a correctly formed command line. The first byte of the string contains the
/// number of bytes in the string. The remainder of the string contains the command line arguments, excluding the name of the
/// child process. If there are no command line arguments, this parameter must point to a zero length string; it cannot be NULL.
///
private IntPtr lpCmdLine;
///
/// Pointer to a structure containing two WORD values. The first value must always be set to two. The second value specifies how
/// the application window is to be shown and is used to supply the wShowWindow member of the STARTUPINFO structure to the
/// CreateProcess function. See the description of the nCmdShow parameter of the ShowWindow function for a list of acceptable values.
///
private IntPtr lpCmdShow;
/// This parameter is reserved; it must be zero.
private readonly uint dwReserved;
/// Initializes a new instance of the class.
public LOADPARMS32()
{
lpCmdShow = Marshal.AllocHGlobal(4);
Marshal.WriteInt16(lpCmdShow, 2);
lpCmdLine = StringHelper.AllocChars(1, Marshal.AllocHGlobal, CharSet.Ansi);
}
/// A string that contains a correctly formed command line, excluding the name of the child process.
public string CmdLine
{
get
{
var l = Marshal.ReadByte(lpCmdLine);
return l == 0 ? string.Empty : StringHelper.GetString(lpCmdLine.Offset(1), CharSet.Ansi, l);
}
set
{
Marshal.FreeHGlobal(lpCmdLine);
if (string.IsNullOrEmpty(value))
lpCmdLine = StringHelper.AllocChars(1, Marshal.AllocHGlobal, CharSet.Ansi);
else
{
lpCmdLine = Marshal.AllocHGlobal(value.Length + 1);
Marshal.WriteByte(lpCmdLine, (byte)value.Length);
StringHelper.Write(value, lpCmdLine.Offset(1), out _, false, CharSet.Ansi);
}
}
}
///
/// Specifies how application window is to be shown and is used to supply the wShowWindow member of the STARTUPINFO structure to
/// the CreateProcess function.
///
public ShowWindowCommand CmdShow
{
get => (ShowWindowCommand)Marshal.ReadInt16(lpCmdShow, 2);
set => Marshal.WriteInt16(lpCmdShow, 2, (short)value);
}
///
/// A list of strings that supply the environment strings for the new process. A value of for this
/// parameter causes the new process to start with the same environment as the calling process.
///
public IEnumerable EnvAddress
{
get => lpEnvAddress == IntPtr.Zero ? null : lpEnvAddress.ToStringEnum(CharSet.Ansi);
set
{
if (lpEnvAddress != IntPtr.Zero)
Marshal.FreeHGlobal(lpEnvAddress);
lpEnvAddress = value is null ? IntPtr.Zero : value.MarshalToPtr(StringListPackMethod.Concatenated, Marshal.AllocHGlobal, out _, CharSet.Ansi);
}
}
void IDisposable.Dispose()
{
Marshal.FreeHGlobal(lpEnvAddress);
Marshal.FreeHGlobal(lpCmdLine);
Marshal.FreeHGlobal(lpCmdShow);
lpEnvAddress = lpCmdLine = lpCmdShow = IntPtr.Zero;
}
}
}
}