Skip to content

Friendly overload should preserve null terminator for ref Span<char> parameters #1295

Open
@AArnott

Description

I am trying to work with CryptCATCDFEnumMembersByCDFTagEx, which enumerates file members in the CatalogFiles section of a catalog definition file (CDF). Support for this is newly added since Microsoft.Windows.SDK.Win32Metadata 62.0.23-preview.

The original API syntax is:

LPWSTR WINAPI CryptCATCDFEnumMembersByCDFTagEx(
  _In_    CRYPTCATCDF                  *pCDF,
  _Inout_ LPWSTR                       pwszPrevCDFTag,
  _In_    PFN_CDF_PARSE_ERROR_CALLBACK pfnParseError,
  _In_    CRYPTCATMEMBER               **ppMember,
  _In_    BOOL                         fContinueOnError,
  _In_    LPVOID                       pvReserved
);

The API returns a LPWSTR string pointer (of a null-terminated string) that identifies a file member in the CatalogFiles section. To enumerate the entire file, this return value needs to be passed into subsequent calls with parameter pwszPrevCDFTag, which is also of type LPWSTR.

The generated code from CsWin32 looks like:

/// <summary>Enumerates catalog-level attributes within the CatalogHeader section of a catalog definition file (CDF).</summary>
/// <param name="pCDF">A pointer to a [CRYPTCATCDF](/windows/desktop/api/mscat/ns-mscat-cryptcatcdf) structure.</param>
/// <param name="pPrevAttr">A pointer to a [CRYPTCATATTRIBUTE](/windows/desktop/api/mscat/ns-mscat-cryptcatattribute) structure for a catalog attribute in the CDF pointed to by <i>pCDF</i>.</param>
/// <param name="pfnParseError">A pointer to a user-defined function to handle file parse errors.</param>
/// <returns>Upon success, this function returns a pointer to a [CRYPTCATATTRIBUTE](/windows/desktop/api/mscat/ns-mscat-cryptcatattribute) structure. The <b>CryptCATCDFEnumCatAttributes</b> function returns a <b>NULL</b> pointer if it fails.</returns>
/// <remarks>You typically call this function in a loop to enumerate all of the catalog header attributes in a CDF. Before entering the loop, set <i>pPrevAttr</i> to <b>NULL</b>. The function returns a pointer to the first attribute. Set <i>pPrevAttr</i> to the return  value of the function for subsequent iterations of the loop.</remarks>
[DllImport("WINTRUST.dll", ExactSpelling = true)]
[DefaultDllImportSearchPaths(DllImportSearchPath.System32)]
internal static extern unsafe winmdroot.Security.Cryptography.Catalog.CRYPTCATATTRIBUTE* CryptCATCDFEnumCatAttributes(winmdroot.Security.Cryptography.Catalog.CRYPTCATCDF* pCDF, winmdroot.Security.Cryptography.Catalog.CRYPTCATATTRIBUTE* pPrevAttr, winmdroot.Security.Cryptography.Catalog.PFN_CDF_PARSE_ERROR_CALLBACK pfnParseError);

/// <inheritdoc cref="CryptCATCDFEnumMembersByCDFTagEx(winmdroot.Security.Cryptography.Catalog.CRYPTCATCDF*, winmdroot.Foundation.PWSTR, winmdroot.Security.Cryptography.Catalog.PFN_CDF_PARSE_ERROR_CALLBACK, winmdroot.Security.Cryptography.Catalog.CRYPTCATMEMBER**, winmdroot.Foundation.BOOL, void*)"/>
internal static unsafe winmdroot.Foundation.PWSTR CryptCATCDFEnumMembersByCDFTagEx(in winmdroot.Security.Cryptography.Catalog.CRYPTCATCDF pCDF, ref Span<char>pwszPrevCDFTag, winmdroot.Security.Cryptography.Catalog.PFN_CDF_PARSE_ERROR_CALLBACK pfnParseError, in winmdroot.Security.Cryptography.Catalog.CRYPTCATMEMBER* ppMember, winmdroot.Foundation.BOOL fContinueOnError, void* pvReserved)
{
	if (pwszPrevCDFTag != null && pwszPrevCDFTag.LastIndexOf('\0') == -1)				throw new ("Required null terminator missing.", "pwszPrevCDFTag");
	fixed (winmdroot.Security.Cryptography.Catalog.CRYPTCATMEMBER** ppMemberLocal = &ppMember)
	{
		fixed (char* ppwszPrevCDFTag = pwszPrevCDFTag)
		{
			fixed (winmdroot.Security.Cryptography.Catalog.CRYPTCATCDF* pCDFLocal = &pCDF)
			{
				winmdroot.Foundation.PWSTR wstrpwszPrevCDFTag = ppwszPrevCDFTag;
				winmdroot.Foundation.PWSTR __result = PInvoke.CryptCATCDFEnumMembersByCDFTagEx(pCDFLocal, wstrpwszPrevCDFTag, pfnParseError, ppMemberLocal, fContinueOnError, pvReserved);
				pwszPrevCDFTag = pwszPrevCDFTag.Slice(0, wstrpwszPrevCDFTag.Length);
				return __result;
			}
		}
	}
}

The generated code has return type of PWSTR, and the corresponding parameter pwszPrevCDFTag has type of ref Span<char>. I tried calling PWSTR.AsSpan() on the return value, but seems the null terminator \0 would be missing after the conversion and caused ArgumentException exception. Seeing Value is being an internal member of PWSTR, what is the recommended way of using the return value as pwszPrevCDFTag argument in this scenario?

Thanks for any advice.

Originally posted by @codgician in #1294

Metadata

Assignees

Labels

No labels
No labels

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions