0

Just trying to copy a single font file to the C:\Windows\Fonts folder using this specific method (I do already know about the other various methods of copying files).

Here's my code, issues are mentioned below the code:

Declarations:

Private Structure SHFILEOPSTRUCT

    Dim hwnd As Integer
    Dim wFunc As Integer
    Dim pFrom As String
    Dim pTo As String
    Dim fFlags As Short
    Dim fAnyOperationsAborted As Boolean
    Dim hNameMappings As Integer
    Dim lpszProgressTitle As String

End Structure

<DllImport("shell32.dll", EntryPoint:="SHFileOperation", CharSet:=CharSet.Auto, SetLastError:=True, ThrowOnUnmappableChar:=True)>
Private Function SHFileOperation(ByRef lpFileOp As SHFILEOPSTRUCT) As Integer
End Function

Private Const FO_COPY As Integer = &H2S
Private Const FOF_NOCONFIRMATION As Integer = &H10S
Private Const FOF_SILENT As Integer = &H4S

Function:

Dim shf As SHFILEOPSTRUCT
Dim strWinFontFolder As String = Environment.ExpandEnvironmentVariables("%WINDIR%" & "\Fonts")

With shf
    .wFunc = FO_COPY
    .pFrom = String.Format("{0}{1}{1}", strFontPath, vbNullChar)
    .pTo = String.Format("{0}{1}{1}", strWinFontFolder, vbNullChar)
    .fFlags = FOF_NOCONFIRMATION Or FOF_SILENT
    .lpszProgressTitle = String.Format("Sending {0} to the Font Folder", strFontPath)
End With

Try
    SHFileOperation(shf)
Catch ex As Exception
    Debug.WriteLine(String.Format("SHFILEOPSTRUCT: {0}", ex.Message))
End Try

Remark from MS Docs:

Important You must ensure that the source and destination paths are double-null terminated. A normal string ends in just a single null character. If you pass that value in either the source or destination members, the function will not realize when it has reached the end of the string and will continue to read on in memory until it comes to a random double null value. This can at least lead to a buffer overrun, and possibly the unintended deletion of unrelated data.

Issues:

When I double null the endings of both the .pTo and .pFrom lines as in the remark, nothing at all seems to happen and the file isn't copied. No errors, nothing at all. Crickets.

When I accidentally only single null terminated the endings, I got this error (on my English system, no idea why it shows Asian characters?)

enter image description here

I should also note that Before this function is even called, I do a:

If File.Exists(strFontPath) = True Then (yada yada yada)

and the file does indeed exist.

Anyone know why it won't copy?

J. Scott Elblein
  • 4,013
  • 15
  • 58
  • 94

1 Answers1

0

According to SHFileOperationA

This function has been replaced in Windows Vista by IFileOperation.

If you do not check fAnyOperationsAborted as well as the return value, you cannot know that the function accomplished the full task you asked of it and you might proceed under incorrect assumptions.

Do not use GetLastError with the return values of this function.

To examine the nonzero values for troubleshooting purposes, they largely map to those defined in Winerror.h. However, several of its possible return values are based on pre-Win32 error codes, which in some cases overlap the later Winerror.h values without matching their meaning. Those particular values are detailed here, and for these specific values only these meanings should be accepted over the Winerror.h codes. However, these values are provided with these warnings:

These are pre-Win32 error codes and are no longer supported or defined in any public header file. To use them, you must either define them yourself or compare against the numerical value. These error codes are subject to change and have historically done so. These values are provided only as an aid in debugging. They should not be regarded as definitive.

SHFileOperation returns a value. If an error occurs it will be in the return value.

Dim retVal As Integer = SHFileOperation(shf)
Debug.WriteLine($"retVal: {retVal.ToString("X2")}")

Note: %windir%\Fonts is a protected operating system folder and requires administrator privileges.


In the OP, is the following Dim fFlags As Short which is incorrect.

If one looks at shellapi.h (%ProgramFiles(x86)%\Windows Kits\10\Include\10.0.19041.0\um\shellapi.h), one sees:

typedef WORD FILEOP_FLAGS;

Looking at Windows Data Types one sees:

WORD: A 16-bit unsigned integer. The range is 0 through 65535 decimal.

and Data Type Summary (Visual Basic)

Integer: -2,147,483,648 through 2,147,483,647

Short: -32,768 through 32,767

UShort: 0 through 65,535


For installing a font, see How to install a Font programmatically (C#).

Additional Resources:

Tu deschizi eu inchid
  • 4,117
  • 3
  • 13
  • 24