Re: Copying files from the CD using SHFileOperation API

From: MikeD (nobody_at_nowhere.edu)
Date: 01/24/05


Date: Mon, 24 Jan 2005 08:22:58 -0500


"Al" <alr@ihostuhost.net> wrote in message
news:uM3zhndAFHA.2568@TK2MSFTNGP10.phx.gbl...
> I am using the SHFileOperation API to copy some install files from the CD
to
> an install folder on the target computer. The code works fine on my
machine,
> but when I try to run it on a different machine it errors out saying, it
> cannot read the files to copy. Here is the code below:
>
> Option Explicit
>
>
> Private Type SHFILEOPSTRUCT
> hwnd As Long
> wFunc As Long
> pFrom As String
> pTo As String
> fFlags As Integer
> fAborted As Boolean
> hNameMaps As Long
> sProgress As String
> End Type
>

First of all, your structure's defined incorrectly. Very seldom (actually,
as far as I know, never) should you use Boolean with any API. You might
find where something is of type BOOL, but that's C++. In C++, a BOOL is 4
bytes whereas VB's Boolean is 2 bytes. Therefore, using Boolean screws up
byte-alignment. In some cases, this is inconsequential. Other times, it's
not.

> Const FO_COPY = &H2
>
>
>
> Private Declare Function SHFileOperation Lib "Shell32.dll" _
> Alias "SHFileOperationA" (lpFileOp As SHFILEOPSTRUCT) As Long
>
>
>
> Private Sub cmdInstall_Click()
>
> Dim sOrigin As String
> Dim sTarget As String
>
>
> Dim lFileOp As Long
> Dim lresult As Long
> Dim lFlags As Long
> Dim lpil As Long
>
> Dim SHFileOp As SHFILEOPSTRUCT
>
> lFileOp = FO_COPY
> sOrigin = App.Path
> sTarget = "C:\progra~1\Install"
>
> With SHFileOp
> .wFunc = lFileOp
> .pFrom = sOrigin
> .pTo = sTarget
> .fFlags = lFlags
> End With
> lresult = SHFileOperation(SHFileOp)
>
> End Sub

You have to explicitly terminate the strings assigned to pFrom and pTo with
double null characters. When passing a string parameter to an API function,
VB terminates with a null character automatically. But since these are
members of a structure, you must do it yourself. The reason you have to use
2 null characters is because you can specify multiple paths or filenames for
either member and these are separated with 1 null character. Then, there
has to be a final null character. This is documented in the Platform SDK:

-----
pFrom
Address of a buffer to specify one or more source file names. These names
must be fully qualified paths. Standard DOS wild cards, such as "*", are
permitted in the filename position. Although this member is declared as a
null-terminated string, it is used as a buffer to hold multiple file names.
Each file name must be terminated by a single NULL character. An additional
NULL character must be appended to the end of the final name to indicate the
end of pFrom.
pTo
Address of a buffer to contain the name of the destination file or
directory. This parameter must be set to NULL if it is not used. Like pFrom,
the pTo member is also a double-NULL terminated string and is handled in
much the same way. However, pTo must meet the following specifications:
-------

Win9x is more forgiving if you don't null-terminate the strings, but
NT-based versions of Windows will choke (it might not perform the operation
at all, or it might use a wrong folder name or filename, or any of a number
of other things can go wrong) if you don't do it.

Since you're assigning the strings to variables first, what'd I'd do is
include a single null character in that assigment and then when you assign
the variables to the structure members, include the final (2nd) null
character. This way, if you specify multiple filenames, each filename has
the single null character already.

    lFileOp = FO_COPY
    sOrigin = App.Path & vbNullChar
    sTarget = "C:\progra~1\Install" & vbNullChar

    With SHFileOp
        .wFunc = lFileOp
        .pFrom = sOrigin & vbNullChar
        .pTo = sTarget & vbNullChar
        .fFlags = lFlags
    End With
    lresult = SHFileOperation(SHFileOp)

Finally, it's a REAL bad idea to hard-code paths. Your code would "fail"
regardless on my PC because "progra~1", which I assume to be "Program
Files", is NOT on my C: drive. Now it wouldn't fail as in not copying the
files. What would happen is that the function would create that directory
on my C: drive, but this would not be good either. What you should do is
use the SHGetSpecialFolderPath API function to get whatever the user's
Program Files folder is.

-- 
Mike
Microsoft MVP Visual Basic


Relevant Pages


Loading