From e0aa2e87810e3d9ac99042ef7a0d7c0701434ce7 Mon Sep 17 00:00:00 2001 From: David Hall Date: Fri, 26 Jul 2019 09:43:19 -0600 Subject: [PATCH] Finished unit tests and fixes for winbase.h profile functions --- PInvoke/Kernel32/WinBase.Profile.cs | 286 +++++++++++++-------- UnitTests/PInvoke/Kernel32/Kernel32.csproj | 1 + UnitTests/PInvoke/Kernel32/WinBase.ProfileTests.cs | 76 ++++++ 3 files changed, 262 insertions(+), 101 deletions(-) create mode 100644 UnitTests/PInvoke/Kernel32/WinBase.ProfileTests.cs diff --git a/PInvoke/Kernel32/WinBase.Profile.cs b/PInvoke/Kernel32/WinBase.Profile.cs index e690455a..9368c114 100644 --- a/PInvoke/Kernel32/WinBase.Profile.cs +++ b/PInvoke/Kernel32/WinBase.Profile.cs @@ -1,6 +1,7 @@ using System; using System.Runtime.InteropServices; using System.Text; +using Vanara.InteropServices; namespace Vanara.PInvoke { @@ -9,16 +10,17 @@ namespace Vanara.PInvoke /// Retrieves an integer associated with a key in the specified section of an initialization file. /// The name of the section in the initialization file. /// - /// The name of the key whose value is to be retrieved. This value is in the form of a string; the GetPrivateProfileInt function converts the - /// string into an integer and returns the integer. + /// The name of the key whose value is to be retrieved. This value is in the form of a string; the GetPrivateProfileInt + /// function converts the string into an integer and returns the integer. /// /// The default value to return if the key name cannot be found in the initialization file. /// - /// The name of the initialization file. If this parameter does not contain a full path to the file, the system searches for the file in the Windows directory. + /// The name of the initialization file. If this parameter does not contain a full path to the file, the system searches for the file + /// in the Windows directory. /// /// - /// The return value is the integer equivalent of the string following the specified key name in the specified initialization file. If the key is not - /// found, the return value is the specified default value. + /// The return value is the integer equivalent of the string following the specified key name in the specified initialization file. + /// If the key is not found, the return value is the specified default value. /// // UINT WINAPI GetPrivateProfileInt( _In_ LPCTSTR lpAppName, _In_ LPCTSTR lpKeyName, _In_ INT nDefault, _In_ LPCTSTR lpFileName); https://msdn.microsoft.com/en-us/library/windows/desktop/ms724345(v=vs.85).aspx [DllImport(Lib.Kernel32, SetLastError = false, CharSet = CharSet.Auto)] @@ -28,38 +30,41 @@ namespace Vanara.PInvoke /// Retrieves all the keys and values for the specified section of an initialization file. /// The name of the section in the initialization file. /// - /// A pointer to a buffer that receives the key name and value pairs associated with the named section. The buffer is filled with one or more - /// null-terminated strings; the last string is followed by a second null character. + /// A pointer to a buffer that receives the key name and value pairs associated with the named section. The buffer is filled with one + /// or more null-terminated strings; the last string is followed by a second null character. /// /// /// The size of the buffer pointed to by the lpReturnedString parameter, in characters. The maximum profile section size is 32,767 characters. /// /// - /// The name of the initialization file. If this parameter does not contain a full path to the file, the system searches for the file in the Windows directory. + /// The name of the initialization file. If this parameter does not contain a full path to the file, the system searches for the file + /// in the Windows directory. /// /// - /// The return value specifies the number of characters copied to the buffer, not including the terminating null character. If the buffer is not large - /// enough to contain all the key name and value pairs associated with the named section, the return value is equal to nSize minus two. + /// The return value specifies the number of characters copied to the buffer, not including the terminating null character. If the + /// buffer is not large enough to contain all the key name and value pairs associated with the named section, the return value is + /// equal to nSize minus two. /// - // DWORD WINAPI GetPrivateProfileSection( _In_ LPCTSTR lpAppName, _Out_ LPTSTR lpReturnedString, _In_ DWORD nSize, _In_ LPCTSTR lpFileName); https://msdn.microsoft.com/en-us/library/windows/desktop/ms724348(v=vs.85).aspx + // DWORD WINAPI GetPrivateProfileSection( _In_ LPCTSTR lpAppName, _Out_ LPTSTR lpReturnedString, _In_ DWORD nSize, _In_ LPCTSTR + // lpFileName); https://msdn.microsoft.com/en-us/library/windows/desktop/ms724348(v=vs.85).aspx [DllImport(Lib.Kernel32, SetLastError = false, CharSet = CharSet.Auto)] [PInvokeData("Winbase.h", MSDNShortId = "ms724348")] public static extern uint GetPrivateProfileSection(string lpAppName, StringBuilder lpReturnedString, uint nSize, string lpFileName); /// Retrieves the names of all sections in an initialization file. /// - /// A pointer to a buffer that receives the section names associated with the named file. The buffer is filled with one or more null-terminated - /// strings; the last string is followed by a second null character. + /// A pointer to a buffer that receives the section names associated with the named file. The buffer is filled with one or more + /// null-terminated strings; the last string is followed by a second null character. /// /// The size of the buffer pointed to by the lpszReturnBuffer parameter, in characters. /// - /// The name of the initialization file. If this parameter is NULL, the function searches the Win.ini file. If this parameter does not contain a - /// full path to the file, the system searches for the file in the Windows directory. + /// The name of the initialization file. If this parameter is NULL, the function searches the Win.ini file. If this parameter + /// does not contain a full path to the file, the system searches for the file in the Windows directory. /// /// - /// The return value specifies the number of characters copied to the specified buffer, not including the terminating null character. If the - /// buffer is not large enough to contain all the section names associated with the specified initialization file, the return value is equal to the size - /// specified by nSize minus two. + /// The return value specifies the number of characters copied to the specified buffer, not including the terminating null + /// character. If the buffer is not large enough to contain all the section names associated with the specified initialization file, + /// the return value is equal to the size specified by nSize minus two. /// // DWORD WINAPI GetPrivateProfileSectionNames( _Out_ LPTSTR lpszReturnBuffer, _In_ DWORD nSize, _In_ LPCTSTR lpFileName); https://msdn.microsoft.com/en-us/library/windows/desktop/ms724352(v=vs.85).aspx [DllImport(Lib.Kernel32, SetLastError = false, CharSet = CharSet.Auto)] @@ -68,100 +73,130 @@ namespace Vanara.PInvoke /// Retrieves a string from the specified section in an initialization file. /// - /// The name of the section containing the key name. If this parameter is NULL, the GetPrivateProfileString function copies all section - /// names in the file to the supplied buffer. + /// The name of the section containing the key name. If this parameter is NULL, the GetPrivateProfileString function + /// copies all section names in the file to the supplied buffer. /// /// - /// The name of the key whose associated string is to be retrieved. If this parameter is NULL, all key names in the section specified by the - /// lpAppName parameter are copied to the buffer specified by the lpReturnedString parameter. + /// The name of the key whose associated string is to be retrieved. If this parameter is NULL, all key names in the section + /// specified by the lpAppName parameter are copied to the buffer specified by the lpReturnedString parameter. /// /// /// - /// A default string. If the lpKeyName key cannot be found in the initialization file, GetPrivateProfileString copies the default string to the - /// lpReturnedString buffer. If this parameter is NULL, the default is an empty string, "". + /// A default string. If the lpKeyName key cannot be found in the initialization file, GetPrivateProfileString copies the + /// default string to the lpReturnedString buffer. If this parameter is NULL, the default is an empty string, "". /// /// - /// Avoid specifying a default string with trailing blank characters. The function inserts a null character in the lpReturnedString buffer to - /// strip any trailing blanks. + /// Avoid specifying a default string with trailing blank characters. The function inserts a null character in the + /// lpReturnedString buffer to strip any trailing blanks. /// /// /// A pointer to the buffer that receives the retrieved string. /// The size of the buffer pointed to by the lpReturnedString parameter, in characters. /// - /// The name of the initialization file. If this parameter does not contain a full path to the file, the system searches for the file in the Windows directory. + /// The name of the initialization file. If this parameter does not contain a full path to the file, the system searches for the file + /// in the Windows directory. /// /// /// The return value is the number of characters copied to the buffer, not including the terminating null character. /// - /// If neither lpAppName nor lpKeyName is NULL and the supplied destination buffer is too small to hold the requested string, the string is - /// truncated and followed by a null character, and the return value is equal to nSize minus one. + /// If neither lpAppName nor lpKeyName is NULL and the supplied destination buffer is too small to hold the requested string, + /// the string is truncated and followed by a null character, and the return value is equal to nSize minus one. /// /// - /// If either lpAppName or lpKeyName is NULL and the supplied destination buffer is too small to hold all the strings, the last string is - /// truncated and followed by two null characters. In this case, the return value is equal to nSize minus two. + /// If either lpAppName or lpKeyName is NULL and the supplied destination buffer is too small to hold all the strings, the + /// last string is truncated and followed by two null characters. In this case, the return value is equal to nSize minus two. /// /// - /// In the event the initialization file specified by lpFileName is not found, or contains invalid values, this function will set errorno with a - /// value of '0x2' (File Not Found). To retrieve extended error information, call GetLastError. + /// In the event the initialization file specified by lpFileName is not found, or contains invalid values, this function will set + /// errorno with a value of '0x2' (File Not Found). To retrieve extended error information, call GetLastError. /// /// - // DWORD WINAPI GetPrivateProfileString( _In_ LPCTSTR lpAppName, _In_ LPCTSTR lpKeyName, _In_ LPCTSTR lpDefault, _Out_ LPTSTR lpReturnedString, _In_ - // DWORD nSize, _In_ LPCTSTR lpFileName); https://msdn.microsoft.com/en-us/library/windows/desktop/ms724353(v=vs.85).aspx + // DWORD WINAPI GetPrivateProfileString( _In_ LPCTSTR lpAppName, _In_ LPCTSTR lpKeyName, _In_ LPCTSTR lpDefault, _Out_ LPTSTR + // lpReturnedString, _In_ DWORD nSize, _In_ LPCTSTR lpFileName); https://msdn.microsoft.com/en-us/library/windows/desktop/ms724353(v=vs.85).aspx [DllImport(Lib.Kernel32, SetLastError = true, CharSet = CharSet.Auto)] [PInvokeData("Winbase.h", MSDNShortId = "ms724353")] public static extern uint GetPrivateProfileString(string lpAppName, string lpKeyName, string lpDefault, StringBuilder lpReturnedString, uint nSize, string lpFileName); /// - /// Retrieves the data associated with a key in the specified section of an initialization file. As it retrieves the data, the function calculates a - /// checksum and compares it with the checksum calculated by the WritePrivateProfileStruct function when the data was added to the file. + /// Retrieves the data associated with a key in the specified section of an initialization file. As it retrieves the data, the + /// function calculates a checksum and compares it with the checksum calculated by the WritePrivateProfileStruct function when + /// the data was added to the file. /// /// The name of the section in the initialization file. /// The name of the key whose data is to be retrieved. /// A pointer to the buffer that receives the data associated with the file, section, and key names. /// The size of the buffer pointed to by the lpStruct parameter, in bytes. /// - /// The name of the initialization file. If this parameter does not contain a full path to the file, the system searches for the file in the Windows directory. + /// The name of the initialization file. If this parameter does not contain a full path to the file, the system searches for the file + /// in the Windows directory. /// /// /// If the function succeeds, the return value is nonzero. /// If the function fails, the return value is zero. /// - // BOOL WINAPI GetPrivateProfileStruct( _In_ LPCTSTR lpszSection, _In_ LPCTSTR lpszKey, _Out_ LPVOID lpStruct, _In_ UINT uSizeStruct, _In_ LPCTSTR - // szFile); https://msdn.microsoft.com/en-us/library/windows/desktop/ms724356(v=vs.85).aspx + // BOOL WINAPI GetPrivateProfileStruct( _In_ LPCTSTR lpszSection, _In_ LPCTSTR lpszKey, _Out_ LPVOID lpStruct, _In_ UINT uSizeStruct, + // _In_ LPCTSTR szFile); https://msdn.microsoft.com/en-us/library/windows/desktop/ms724356(v=vs.85).aspx [DllImport(Lib.Kernel32, SetLastError = false, CharSet = CharSet.Auto)] [PInvokeData("Winbase.h", MSDNShortId = "ms724356")] [return: MarshalAs(UnmanagedType.Bool)] public static extern bool GetPrivateProfileStruct(string lpszSection, string lpszKey, IntPtr lpStruct, uint uSizeStruct, string szFile); + /// + /// Retrieves the data associated with a key in the specified section of an initialization file. As it retrieves the data, the + /// function calculates a checksum and compares it with the checksum calculated by the WritePrivateProfileStruct function when + /// the data was added to the file. + /// + /// The type of the structure to retrieve. + /// The name of the section in the initialization file. + /// The name of the key whose data is to be retrieved. + /// Receives the data associated with the file, section, and key names. + /// + /// The name of the initialization file. If this parameter does not contain a full path to the file, the system searches for the file + /// in the Windows directory. + /// + /// + /// If the function succeeds, the return value is nonzero. + /// If the function fails, the return value is zero. + /// + public static bool GetPrivateProfileStruct(string lpszSection, string lpszKey, out T lpStruct, string szFile) where T : unmanaged + { + using (var mem = SafeHGlobalHandle.CreateFromStructure()) + { + var b = GetPrivateProfileStruct(lpszSection, lpszKey, mem, mem.Size, szFile); + lpStruct = mem.ToStructure(); + return b; + } + } + /// Retrieves an integer from a key in the specified section of the Win.ini file. /// The name of the section containing the key name. /// - /// The name of the key whose value is to be retrieved. This value is in the form of a string; the GetProfileInt function converts the string into - /// an integer and returns the integer. + /// The name of the key whose value is to be retrieved. This value is in the form of a string; the GetProfileInt function + /// converts the string into an integer and returns the integer. /// /// The default value to return if the key name cannot be found in the initialization file. /// - /// The return value is the integer equivalent of the string following the key name in Win.ini. If the function cannot find the key, the return value is - /// the default value. If the value of the key is less than zero, the return value is zero. + /// The return value is the integer equivalent of the string following the key name in Win.ini. If the function cannot find the key, + /// the return value is the default value. If the value of the key is less than zero, the return value is zero. /// // UINT WINAPI GetProfileInt( _In_ LPCTSTR lpAppName, _In_ LPCTSTR lpKeyName, _In_ INT nDefault); https://msdn.microsoft.com/en-us/library/windows/desktop/ms724360(v=vs.85).aspx [DllImport(Lib.Kernel32, SetLastError = false, CharSet = CharSet.Auto)] [PInvokeData("Winbase.h", MSDNShortId = "ms724360")] - [return: MarshalAs(UnmanagedType.Bool)] public static extern uint GetProfileInt(string lpAppName, string lpKeyName, int nDefault); /// Retrieves all the keys and values for the specified section of the Win.ini file. /// The name of the section in the Win.ini file. /// - /// A pointer to a buffer that receives the keys and values associated with the named section. The buffer is filled with one or more null-terminated - /// strings; the last string is followed by a second null character. + /// A pointer to a buffer that receives the keys and values associated with the named section. The buffer is filled with one or more + /// null-terminated strings; the last string is followed by a second null character. /// /// /// The size of the buffer pointed to by the lpReturnedString parameter, in characters. The maximum profile section size is 32,767 characters. /// /// - /// The return value specifies the number of characters copied to the specified buffer, not including the terminating null character. If the buffer is - /// not large enough to contain all the keys and values associated with the named section, the return value is equal to the size specified by nSize minus two. + /// The return value specifies the number of characters copied to the specified buffer, not including the terminating null character. + /// If the buffer is not large enough to contain all the keys and values associated with the named section, the return value is equal + /// to the size specified by nSize minus two. /// // DWORD WINAPI GetProfileSection( _In_ LPCTSTR lpAppName, _Out_ LPTSTR lpReturnedString, _In_ DWORD nSize); https://msdn.microsoft.com/en-us/library/windows/desktop/ms724363(v=vs.85).aspx [DllImport(Lib.Kernel32, SetLastError = false, CharSet = CharSet.Auto)] @@ -170,20 +205,22 @@ namespace Vanara.PInvoke /// Retrieves the string associated with a key in the specified section of the Win.ini file. /// - /// The name of the section containing the key. If this parameter is NULL, the function copies all section names in the file to the supplied buffer. + /// The name of the section containing the key. If this parameter is NULL, the function copies all section names in the file + /// to the supplied buffer. /// /// - /// The name of the key whose associated string is to be retrieved. If this parameter is NULL, the function copies all keys in the given section - /// to the supplied buffer. Each string is followed by a null character, and the final string is followed by a second null character. + /// The name of the key whose associated string is to be retrieved. If this parameter is NULL, the function copies all keys in + /// the given section to the supplied buffer. Each string is followed by a null character, and the final string is followed by + /// a second null character. /// /// /// - /// A default string. If the lpKeyName key cannot be found in the initialization file, GetProfileString copies the default string to the - /// lpReturnedString buffer. If this parameter is NULL, the default is an empty string, "". + /// A default string. If the lpKeyName key cannot be found in the initialization file, GetProfileString copies the default + /// string to the lpReturnedString buffer. If this parameter is NULL, the default is an empty string, "". /// /// - /// Avoid specifying a default string with trailing blank characters. The function inserts a null character in the lpReturnedString buffer to - /// strip any trailing blanks. + /// Avoid specifying a default string with trailing blank characters. The function inserts a null character in the + /// lpReturnedString buffer to strip any trailing blanks. /// /// /// A pointer to a buffer that receives the character string. @@ -191,31 +228,36 @@ namespace Vanara.PInvoke /// /// The return value is the number of characters copied to the buffer, not including the null-terminating character. /// - /// If neither lpAppName nor lpKeyName is NULL and the supplied destination buffer is too small to hold the requested string, the string is - /// truncated and followed by a null character, and the return value is equal to nSize minus one. + /// If neither lpAppName nor lpKeyName is NULL and the supplied destination buffer is too small to hold the requested string, + /// the string is truncated and followed by a null character, and the return value is equal to nSize minus one. /// /// - /// If either lpAppName or lpKeyName is NULL and the supplied destination buffer is too small to hold all the strings, the last string is - /// truncated and followed by two null characters. In this case, the return value is equal to nSize minus two. + /// If either lpAppName or lpKeyName is NULL and the supplied destination buffer is too small to hold all the strings, the + /// last string is truncated and followed by two null characters. In this case, the return value is equal to nSize minus two. /// /// - // DWORD WINAPI GetProfileString( _In_ LPCTSTR lpAppName, _In_ LPCTSTR lpKeyName, _In_ LPCTSTR lpDefault, _Out_ LPTSTR lpReturnedString, _In_ DWORD - // nSize); https://msdn.microsoft.com/en-us/library/windows/desktop/ms724366(v=vs.85).aspx + // DWORD WINAPI GetProfileString( _In_ LPCTSTR lpAppName, _In_ LPCTSTR lpKeyName, _In_ LPCTSTR lpDefault, _Out_ LPTSTR + // lpReturnedString, _In_ DWORD nSize); https://msdn.microsoft.com/en-us/library/windows/desktop/ms724366(v=vs.85).aspx [DllImport(Lib.Kernel32, SetLastError = false, CharSet = CharSet.Auto)] [PInvokeData("Winbase.h", MSDNShortId = "ms724366")] public static extern uint GetProfileString(string lpAppName, string lpKeyName, string lpDefault, StringBuilder lpReturnedString, uint nSize); /// Replaces the keys and values for the specified section in an initialization file. - /// The name of the section in which data is written. This section name is typically the name of the calling application. - /// The new key names and associated values that are to be written to the named section. This string is limited to 65,535 bytes. + /// + /// The name of the section in which data is written. This section name is typically the name of the calling application. + /// + /// + /// The new key names and associated values that are to be written to the named section. This string is limited to 65,535 bytes. + /// /// /// - /// The name of the initialization file. If this parameter does not contain a full path for the file, the function searches the Windows directory for the - /// file. If the file does not exist and lpFileName does not contain a full path, the function creates the file in the Windows directory. + /// The name of the initialization file. If this parameter does not contain a full path for the file, the function searches the + /// Windows directory for the file. If the file does not exist and lpFileName does not contain a full path, the function creates the + /// file in the Windows directory. /// /// - /// If the file exists and was created using Unicode characters, the function writes Unicode characters to the file. Otherwise, the function creates a - /// file using ANSI characters. + /// If the file exists and was created using Unicode characters, the function writes Unicode characters to the file. Otherwise, the + /// function creates a file using ANSI characters. /// /// /// @@ -230,79 +272,117 @@ namespace Vanara.PInvoke /// Copies a string into the specified section of an initialization file. /// - /// The name of the section to which the string will be copied. If the section does not exist, it is created. The name of the section is - /// case-independent; the string can be any combination of uppercase and lowercase letters. + /// The name of the section to which the string will be copied. If the section does not exist, it is created. The name of the section + /// is case-independent; the string can be any combination of uppercase and lowercase letters. /// /// - /// The name of the key to be associated with a string. If the key does not exist in the specified section, it is created. If this parameter is - /// NULL, the entire section, including all entries within the section, is deleted. + /// The name of the key to be associated with a string. If the key does not exist in the specified section, it is created. If this + /// parameter is NULL, the entire section, including all entries within the section, is deleted. /// /// - /// A null-terminated string to be written to the file. If this parameter is NULL, the key pointed to by the lpKeyName parameter is deleted. + /// A null-terminated string to be written to the file. If this parameter is NULL, the key pointed to by the lpKeyName + /// parameter is deleted. /// /// /// The name of the initialization file. /// - /// If the file was created using Unicode characters, the function writes Unicode characters to the file. Otherwise, the function writes ANSI characters. + /// If the file was created using Unicode characters, the function writes Unicode characters to the file. Otherwise, the function + /// writes ANSI characters. /// /// /// /// If the function successfully copies the string to the initialization file, the return value is nonzero. /// - /// If the function fails, or if it flushes the cached version of the most recently accessed initialization file, the return value is zero. To get - /// extended error information, call GetLastError. + /// If the function fails, or if it flushes the cached version of the most recently accessed initialization file, the return value is + /// zero. To get extended error information, call GetLastError. /// /// - // BOOL WINAPI WritePrivateProfileString( _In_ LPCTSTR lpAppName, _In_ LPCTSTR lpKeyName, _In_ LPCTSTR lpString, _In_ LPCTSTR lpFileName); https://msdn.microsoft.com/en-us/library/windows/desktop/ms725501(v=vs.85).aspx + // BOOL WINAPI WritePrivateProfileString( _In_ LPCTSTR lpAppName, _In_ LPCTSTR lpKeyName, _In_ LPCTSTR lpString, _In_ LPCTSTR + // lpFileName); https://msdn.microsoft.com/en-us/library/windows/desktop/ms725501(v=vs.85).aspx [DllImport(Lib.Kernel32, SetLastError = true, CharSet = CharSet.Auto)] [PInvokeData("Winbase.h", MSDNShortId = "ms725501")] [return: MarshalAs(UnmanagedType.Bool)] public static extern bool WritePrivateProfileString(string lpAppName, string lpKeyName, string lpString, string lpFileName); /// - /// Copies data into a key in the specified section of an initialization file. As it copies the data, the function calculates a checksum and appends it - /// to the end of the data. The GetPrivateProfileStruct function uses the checksum to ensure the integrity of the data. + /// Copies data into a key in the specified section of an initialization file. As it copies the data, the function calculates a + /// checksum and appends it to the end of the data. The GetPrivateProfileStruct function uses the checksum to ensure the + /// integrity of the data. /// /// - /// The name of the section to which the string will be copied. If the section does not exist, it is created. The name of the section is case - /// independent, the string can be any combination of uppercase and lowercase letters. + /// The name of the section to which the string will be copied. If the section does not exist, it is created. The name of the section + /// is case independent, the string can be any combination of uppercase and lowercase letters. /// /// - /// The name of the key to be associated with a string. If the key does not exist in the specified section, it is created. If this parameter is - /// NULL, the entire section, including all keys and entries within the section, is deleted. + /// The name of the key to be associated with a string. If the key does not exist in the specified section, it is created. If this + /// parameter is NULL, the entire section, including all keys and entries within the section, is deleted. /// /// The data to be copied. If this parameter is NULL, the key is deleted. /// The size of the buffer pointed to by the lpStruct parameter, in bytes. /// /// The name of the initialization file. If this parameter is NULL, the information is copied into the Win.ini file. /// - /// If the file was created using Unicode characters, the function writes Unicode characters to the file. Otherwise, the function writes ANSI characters. + /// If the file was created using Unicode characters, the function writes Unicode characters to the file. Otherwise, the function + /// writes ANSI characters. /// /// /// /// If the function successfully copies the string to the initialization file, the return value is nonzero. /// - /// If the function fails, or if it flushes the cached version of the most recently accessed initialization file, the return value is zero. To get - /// extended error information, call GetLastError. + /// If the function fails, or if it flushes the cached version of the most recently accessed initialization file, the return value is + /// zero. To get extended error information, call GetLastError. /// /// - // BOOL WINAPI WritePrivateProfileStruct( _In_ LPCTSTR lpszSection, _In_ LPCTSTR lpszKey, _In_ LPVOID lpStruct, _In_ UINT uSizeStruct, _In_ LPCTSTR - // szFile); https://msdn.microsoft.com/en-us/library/windows/desktop/ms725502(v=vs.85).aspx + // BOOL WINAPI WritePrivateProfileStruct( _In_ LPCTSTR lpszSection, _In_ LPCTSTR lpszKey, _In_ LPVOID lpStruct, _In_ UINT + // uSizeStruct, _In_ LPCTSTR szFile); https://msdn.microsoft.com/en-us/library/windows/desktop/ms725502(v=vs.85).aspx [DllImport(Lib.Kernel32, SetLastError = true, CharSet = CharSet.Auto)] [PInvokeData("Winbase.h", MSDNShortId = "ms725502")] [return: MarshalAs(UnmanagedType.Bool)] public static extern bool WritePrivateProfileStruct(string lpszSection, string lpszKey, [In] IntPtr lpStruct, uint uSizeStruct, string szFile); /// - /// Replaces the contents of the specified section in the Win.ini file with specified keys and values. If Win.ini uses Unicode characters, the function - /// writes Unicode characters to the file. Otherwise, the function writes ANSI characters. + /// Copies data into a key in the specified section of an initialization file. As it copies the data, the function calculates a + /// checksum and appends it to the end of the data. The GetPrivateProfileStruct function uses the checksum to ensure the + /// integrity of the data. + /// + /// + /// The name of the section to which the string will be copied. If the section does not exist, it is created. The name of the section + /// is case independent, the string can be any combination of uppercase and lowercase letters. + /// + /// + /// The name of the key to be associated with a string. If the key does not exist in the specified section, it is created. If this + /// parameter is NULL, the entire section, including all keys and entries within the section, is deleted. + /// + /// The data to be copied. + /// + /// The name of the initialization file. If this parameter is NULL, the information is copied into the Win.ini file. + /// + /// If the file was created using Unicode characters, the function writes Unicode characters to the file. Otherwise, the function + /// writes ANSI characters. + /// + /// + /// + /// If the function successfully copies the string to the initialization file, the return value is nonzero. + /// + /// If the function fails, or if it flushes the cached version of the most recently accessed initialization file, the return value is + /// zero. To get extended error information, call GetLastError. + /// + /// + public static bool WritePrivateProfileStruct(string lpszSection, string lpszKey, in T lpStruct, string szFile) where T : unmanaged => + WritePrivateProfileStruct(lpszSection, lpszKey, new PinnedObject(lpStruct), (uint)Marshal.SizeOf(lpStruct), szFile); + + /// + /// Replaces the contents of the specified section in the Win.ini file with specified keys and values. If Win.ini uses Unicode + /// characters, the function writes Unicode characters to the file. Otherwise, the function writes ANSI characters. /// /// The name of the section. This section name is typically the name of the calling application. /// - /// The new key names and associated values that are to be written to the named section. This string is limited to 65,535 bytes. /// - /// If the file exists and was created using Unicode characters, the function writes Unicode characters to the file. Otherwise, the function creates a - /// file using ANSI characters. + /// The new key names and associated values that are to be written to the named section. This string is limited to 65,535 bytes. + /// + /// + /// If the file exists and was created using Unicode characters, the function writes Unicode characters to the file. Otherwise, the + /// function creates a file using ANSI characters. /// /// /// @@ -316,23 +396,27 @@ namespace Vanara.PInvoke public static extern bool WriteProfileSection(string lpAppName, string lpString); /// - /// Copies a string into the specified section of the Win.ini file. If Win.ini uses Unicode characters, the function writes Unicode characters to the - /// file. Otherwise, the function writes ANSI characters. + /// Copies a string into the specified section of the Win.ini file. If Win.ini uses Unicode characters, the function writes Unicode + /// characters to the file. Otherwise, the function writes ANSI characters. /// /// - /// The section to which the string is to be copied. If the section does not exist, it is created. The name of the section is not case-sensitive; the - /// string can be any combination of uppercase and lowercase letters. + /// The section to which the string is to be copied. If the section does not exist, it is created. The name of the section is not + /// case-sensitive; the string can be any combination of uppercase and lowercase letters. /// /// - /// The key to be associated with the string. If the key does not exist in the specified section, it is created. If this parameter is NULL, the - /// entire section, including all entries in the section, is deleted. + /// The key to be associated with the string. If the key does not exist in the specified section, it is created. If this parameter is + /// NULL, the entire section, including all entries in the section, is deleted. /// /// - /// A null-terminated string to be written to the file. If this parameter is NULL, the key pointed to by the lpKeyName parameter is deleted. + /// A null-terminated string to be written to the file. If this parameter is NULL, the key pointed to by the lpKeyName + /// parameter is deleted. /// /// /// If the function successfully copies the string to the Win.ini file, the return value is nonzero. - /// If the function fails, or if it flushes the cached version of Win.ini, the return value is zero. To get extended error information, call GetLastError. + /// + /// If the function fails, or if it flushes the cached version of Win.ini, the return value is zero. To get extended error + /// information, call GetLastError. + /// /// // BOOL WINAPI WriteProfileString( _In_ LPCTSTR lpAppName, _In_ LPCTSTR lpKeyName, _In_ LPCTSTR lpString); https://msdn.microsoft.com/en-us/library/windows/desktop/ms725504(v=vs.85).aspx [DllImport(Lib.Kernel32, SetLastError = true, CharSet = CharSet.Auto)] diff --git a/UnitTests/PInvoke/Kernel32/Kernel32.csproj b/UnitTests/PInvoke/Kernel32/Kernel32.csproj index d190ff90..eed23566 100644 --- a/UnitTests/PInvoke/Kernel32/Kernel32.csproj +++ b/UnitTests/PInvoke/Kernel32/Kernel32.csproj @@ -48,6 +48,7 @@ + diff --git a/UnitTests/PInvoke/Kernel32/WinBase.ProfileTests.cs b/UnitTests/PInvoke/Kernel32/WinBase.ProfileTests.cs new file mode 100644 index 00000000..8782d7ad --- /dev/null +++ b/UnitTests/PInvoke/Kernel32/WinBase.ProfileTests.cs @@ -0,0 +1,76 @@ +using NUnit.Framework; +using System.Text; +using static Vanara.PInvoke.Kernel32; + +namespace Vanara.PInvoke.Tests +{ + [TestFixture] + public partial class WinBaseTests_Profile + { + [Test] + public void PrivateProfileTest() + { + const string sec = "Section"; + + using (var tmp = new TempFile("")) + { + Assert.That(WritePrivateProfileSection(sec, "Key0=10\0", tmp.FullName), ResultIs.Successful); + Assert.That(WritePrivateProfileString(sec, "Key1", "Value1", tmp.FullName), ResultIs.Successful); + Assert.That(WritePrivateProfileStruct(sec, "Key2", new RECT(1, 2, 3, 4), tmp.FullName), ResultIs.Successful); + Assert.That(WritePrivateProfileStruct(sec, "Key3", 4, tmp.FullName), ResultIs.Successful); + TestContext.WriteLine(System.IO.File.ReadAllText(tmp.FullName)); + + Assert.That(GetPrivateProfileInt(sec, "Key0", 0, tmp.FullName), Is.EqualTo(10)); + Assert.That(GetPrivateProfileInt(sec, "Key3", 0, tmp.FullName), Is.Not.EqualTo(4)); + Assert.That(GetPrivateProfileInt(sec, "Key4", 0, tmp.FullName), Is.EqualTo(0)); + + var sb = new StringBuilder(1024); + Assert.That(GetPrivateProfileSection(sec, sb, (uint)sb.Capacity, tmp.FullName), Is.GreaterThan(0).And.Not.EqualTo(sb.Capacity - 2)); + TestContext.WriteLine(sb); + + sb.Clear(); + Assert.That(GetPrivateProfileSectionNames(sb, (uint)sb.Capacity, tmp.FullName), Is.GreaterThan(0).And.Not.EqualTo(sb.Capacity - 2)); + TestContext.WriteLine(sb); + + sb.Clear(); + Assert.That(GetPrivateProfileString(sec, "Key0", null, sb, (uint)sb.Capacity, tmp.FullName), Is.GreaterThan(0).And.Not.EqualTo(sb.Capacity - 2)); + Assert.That(sb.ToString(), Is.EqualTo("10")); + sb.Clear(); + Assert.That(GetPrivateProfileString(sec, "Key1", null, sb, (uint)sb.Capacity, tmp.FullName), Is.GreaterThan(0).And.Not.EqualTo(sb.Capacity - 2)); + Assert.That(sb.ToString(), Is.EqualTo("Value1")); + sb.Clear(); + Assert.That(GetPrivateProfileString(sec, "Key3", null, sb, (uint)sb.Capacity, tmp.FullName), Is.GreaterThan(0).And.Not.EqualTo(sb.Capacity - 2)); + Assert.That(sb.ToString(), Is.EqualTo("0400000004")); + + Assert.That(GetPrivateProfileStruct(sec, "Key2", out RECT r, tmp.FullName), Is.True); + Assert.That(r.bottom, Is.EqualTo(4)); + Assert.That(GetPrivateProfileStruct(sec, "Key3", out int i, tmp.FullName), Is.True); + Assert.That(i, Is.EqualTo(4)); + Assert.That(GetPrivateProfileStruct(sec, "Key0", out i, tmp.FullName), Is.False); + } + } + + [Test] + public void ProfileTest() + { + const string sec = "Section"; + + Assert.That(WriteProfileSection(sec, "Key0=10\0"), ResultIs.Successful); + Assert.That(WriteProfileString(sec, "Key1", "Value1"), ResultIs.Successful); + + Assert.That(GetProfileInt(sec, "Key0", 0), Is.EqualTo(10)); + Assert.That(GetProfileInt(sec, "Key4", 0), Is.EqualTo(0)); + + var sb = new StringBuilder(1024); + Assert.That(GetProfileSection(sec, sb, (uint)sb.Capacity), Is.GreaterThan(0).And.Not.EqualTo(sb.Capacity - 2)); + TestContext.WriteLine(sb); + + sb.Clear(); + Assert.That(GetProfileString(sec, "Key0", null, sb, (uint)sb.Capacity), Is.GreaterThan(0).And.Not.EqualTo(sb.Capacity - 2)); + Assert.That(sb.ToString(), Is.EqualTo("10")); + sb.Clear(); + Assert.That(GetProfileString(sec, "Key1", null, sb, (uint)sb.Capacity), Is.GreaterThan(0).And.Not.EqualTo(sb.Capacity - 2)); + Assert.That(sb.ToString(), Is.EqualTo("Value1")); + } + } +} \ No newline at end of file