Get Universal Name

From NSIS Wiki
Jump to navigationJump to search
Author: HotButteredSoul (talk, contrib)


NSIS forum thread

Description

This is a function that, given any path, coverts it to a UNC path if necessary. This is especially useful when dealing with mapped network drives.

Function

I have not written a macro for this function.

Usage

Use the following code in your NSIS installer convert a mapped drive to a unc path:

Push "H:\path\file"
Call get_universal_name
Pop $0 ; = "\\servername\sharename\path\file"

Note: this function works fine with non-network paths. Thus, if you pass it "C:\somepath" it will return "C:\somepath". You don't have to check the type of drive before you call this function.

Code

#
# GetUniversalName.nsh - by HotButteredSoul
#
# Function for getting the Universal name of a filepath.
#
# History:
# *Unicode and 64bit support - Anders / 20131129
# *Initial version - HotButteredSoul / 20070216
 
!ifndef _GetUniversalName_nsh
!define _GetUniversalName_nsh
 
#
# get_universal_name - gets universal name of a filepath
#
# Example:
#
# Push "H:\path\file"
# Call get_universal_name
# Pop $0 ; = "\\servername\sharename\path\file"
#
# Uses mpr.lib WNetGetUniversalNameA/W
#
# DWORD WNetGetUniversalName(
#   LPCTSTR lpLocalPath,  // pointer to drive-based path for a network
#                         // resource
#   DWORD dwInfoLevel,    // specifies form of universal name to be
#                         // obtained
#   LPVOID lpBuffer,      // pointer to buffer that receives universal
#                         // name data structure
#   LPDWORD lpBufferSize  // pointer to variable that specifies size
#                         // of buffer
# );
#
# Parameters
# lpLocalPath
# Points to a null-terminated string that is a drive-based path for a network resource.
# For example, if drive H has been mapped to a network drive share, and the network
# resource of interest is a file named SAMPLE.DOC in the directory \WIN32\EXAMPLES on
# that share, the drive-based path is H:\WIN32\EXAMPLES\SAMPLE.DOC.
#
# dwInfoLevel
# Specifies the type of data structure that the function will store in the buffer pointed
#  to by lpBuffer. This parameter can be one of the following values: Value Meaning
#  UNIVERSAL_NAME_INFO_LEVEL The function will store a UNIVERSAL_NAME_INFO data
#       structure in the buffer. (defined in WINNETWK.H as 1)
#  REMOTE_NAME_INFO_LEVEL The function will store a REMOTE_NAME_INFO data structure in
#       the buffer. (defined in WINNETWK.H as 2)
#
# The UNIVERSAL_NAME_INFO data structure points to a Universal Naming Convention (UNC)
# name string.
#
# lpBuffer
# Points to a buffer that receives the type of data structure specified by the
# dwInfoLevel parameter.
#
# lpBufferSize
# Points to a variable that specifies the size in bytes of the buffer pointed to by lpBuffer.
# If the function succeeds, it sets the variable pointed to by lpBufferSize to the size
# in bytes of the data structure stored in the buffer. If the function fails because the
# buffer is too small, indicated by the ERROR_MORE_DATA error code, it sets the variable
# pointed to by lpBufferSize to the required buffer size.
#
# Return Values
# If the function succeeds, the return value is NO_ERROR (0).
#
# If the function fails, the return value is an error code. To get extended error
# information, callGetLastError. GetLastError may return one of the following error codes:
#
# Value Meaning
# ERROR_BAD_DEVICE The string pointed to by lpLocalPath is invalid (1200).
# ERROR_CONNECTION_UNAVAIL There is no current connection to the remote device, but there
#   is a remembered (persistent) connection to it (1201).
# ERROR_EXTENDED_ERROR A network-specific error occurred. Use the WNetGetLastError
#   function to obtain a description of the error (1208).
# ERROR_MORE_DATA The buffer pointed to by lpBuffer is too small. The function sets the
#   variable pointed to by lpBufferSize to the required buffer size. More entries are
#   available with subsequent calls (234).
# ERROR_NOT_SUPPORTED The dwInfoLevel parameter was set to UNIVERSAL_NAME_INFO_LEVEL, but
#   the network provider does not support UNC names. This function is not supported by
#   any of the network providers (282).
# ERROR_NO_NET_OR_BAD_PATH None of the providers recognized this local name as having a
#   connection. However, the network is not available for at least one provider to whom
#   the connection may belong (1203).
# ERROR_NO_NETWORK There is no network present (1222).
# ERROR_NOT_CONNECTED The device specified by lpLocalPath is not redirected (2250).
#
Function get_universal_name
 
    Exch $0 ; local path (IN)
    Push $1 ; WNet error code
    Push $2 ; lpBuffer
 
    ; Allocate UNIVERSAL_NAME_INFO buffer (pointer and TCHAR array)
    !ifdef NSIS_PTR_SIZE & NSIS_CHAR_SIZE
        System::Call '*(p,&t${NSIS_MAX_STRLEN} "")p.r2'
        !define /math get_universal_name_UNISTRSIZE ${NSIS_CHAR_SIZE} * ${NSIS_MAX_STRLEN}
        !define /math get_universal_name_UNISIZE ${get_universal_name_UNISTRSIZE} + ${NSIS_PTR_SIZE}
        !undef get_universal_name_UNISTRSIZE
        System::Call 'mpr::WNetGetUniversalName(tr0,i1,p$2,*i${get_universal_name_UNISIZE})i.r1'
    !else
        System::Call '*(i,&t${NSIS_MAX_STRLEN} "")i.r2'
        !define /math get_universal_name_UNISIZE 4 + ${NSIS_MAX_STRLEN}
        System::Call 'mpr::WNetGetUniversalNameA(tr0,i1,i$2,*i${get_universal_name_UNISIZE})i.r1'
    !endif
    !undef get_universal_name_UNISIZE
    IntCmpU 0 $1 0 retlocal retlocal ; Local path is already in $0 and will be returned if the call failed
        System::Call "*$2(t.r0)" ; Extract universal string
    retlocal:
    System::Free $2
 
    Pop $2
    Pop $1
    Exch $0
 
FunctionEnd
!endif ; _GetUniversalName_nsh

Resources and Links

API Functions used: