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