Old 16th February 2007, 17:49   #1
HotButteredSoul
Junior Member
 
HotButteredSoul's Avatar
 
Join Date: Feb 2007
Location: Santa Monica, California (USA)
Posts: 6
Converting a mapped drive to a UNC path

Hello!

I've been running into clients with network setups who have been trying to install onto mapped network drives. This can cause issues, mainly because mapped drives are associated with User logons and can be different depending upon who is logged into a machine. Moreover, services do not obtain mapped drive information, even when given rights to "Log on as:" a particular user.

UNC paths, however, do not exhibit this problem. Thus, I wrote a little function to take any windows full path and, if the path uses a mapped drive, convert it to a UNC path.

Enjoy!!

code:

#
# GetUniversalName.nsh - by HotButteredSoul
#
# Function for getting the Universal name of a filepath.
#

!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
#
# 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 ; Universal Path (OUT)
Push $2 ; lpBuffer
Push $3 ; lpBufferSize
Push $4 ; GetUniversalName return value

;allocate buffer for following structure:
; typedef struct _UNIVERSAL_NAME_INFO { /* uni */
; LPTSTR lpUniversalName;
; } UNIVERSAL_NAME_INFO;
System::Call "*(&t${NSIS_MAX_STRLEN} '') i .r2"

; make call
System::Call 'mpr::WNetGetUniversalNameA(t r0, i 1,i $2, *i ${NSIS_MAX_STRLEN} r3)i .r4'
IntCmp 0 $4 success
StrCpy $1 $0 ; failed, so just use local path
GoTo clean_up

success:
System::Call "*$2(t .r1)" ; Extract universal string

clean_up:
System::Free $2
Pop $4
Pop $3
Pop $2
Exch
Pop $0
Exch $1

FunctionEnd
!endif ; _GetUniversalName_nsh

HotButteredSoul is offline   Reply With Quote
Old 16th February 2007, 17:57   #2
kichik
M.I.A.
[NSIS Dev, Mod]
 
kichik's Avatar
 
Join Date: Oct 2001
Location: Israel
Posts: 11,343
The UNIVERSAL_NAME_INFO structure contains only a pointer to a string. There is no need to allocate 1024 bytes for it, only 4. Call "*(i)" should be good enough. You can use 't' without the ampersand to make it clear the allocation is for a string pointer.

You should create a Wiki page for useful scripts so they won't get lost in the forums.

NSIS FAQ | NSIS Home Page | Donate $
"I hear and I forget. I see and I remember. I do and I understand." -- Confucius
kichik is offline   Reply With Quote
Old 16th February 2007, 19:49   #3
HotButteredSoul
Junior Member
 
HotButteredSoul's Avatar
 
Join Date: Feb 2007
Location: Santa Monica, California (USA)
Posts: 6
You would think so!

However, what Microsoft doesn't tell you (though they imply it in their example) is that lpBuffer not only contains the UNIVERSAL_NAME_INFO structure, it ALSO contains the string that the structure points to!!

Thus, for a 14 byte path like "\\loki\loki_c" you need 18 bytes in your lpBuffer.

Hence, my usage of NSIS_MAX_STRLEN. Note, my code is a little misleading... because of the 4 byte size of the structure the maximum length UNC path my function will return is NSIS_MAX_STRLEN-4 = 1020.

A sidenote: if you don't give WNetGetUniversalNameA a big enough buffer, it returns the buffer size it does need in lpBufferSize. However, even this non-unicode version asks for a unicode size buffer!! Thus, for "\\loki\loki_c\pub" it would ask for 32 (14*2 + 4) bytes, even though it works with 18 (but set it to 17 and it asks for 32!! lol).

Don't you just love Micro$oft??
HotButteredSoul is offline   Reply With Quote
Old 16th February 2007, 19:58   #4
kichik
M.I.A.
[NSIS Dev, Mod]
 
kichik's Avatar
 
Join Date: Oct 2001
Location: Israel
Posts: 11,343
So they expect everyone to always query for the required size and make no note of it in the documentation? That's one of the weirdest APIs I've ever seen. Why not LPSTR lpUniversalName[1] as always?

NSIS FAQ | NSIS Home Page | Donate $
"I hear and I forget. I see and I remember. I do and I understand." -- Confucius
kichik is offline   Reply With Quote
Old 16th February 2007, 20:06   #5
HotButteredSoul
Junior Member
 
HotButteredSoul's Avatar
 
Join Date: Feb 2007
Location: Santa Monica, California (USA)
Posts: 6
Yes, it's wacky. They actually expect you to guess a size and use it, then only do something if it fails... which, btw, I'm not doing in my script.
HotButteredSoul is offline   Reply With Quote
Old 16th February 2007, 20:39   #6
HotButteredSoul
Junior Member
 
HotButteredSoul's Avatar
 
Join Date: Feb 2007
Location: Santa Monica, California (USA)
Posts: 6
Wiki'd

Http://nsis.sourceforge.net/Get_Universal_Name
HotButteredSoul is offline   Reply With Quote
Old 17th February 2007, 01:02   #7
Anders
Moderator
 
Anders's Avatar
 
Join Date: Jun 2002
Location: ${NSISDIR}
Posts: 5,358
http://nsis.sourceforge.net/Get_Universal_Name

IntOp $PostCount $PostCount + 1
Anders is offline   Reply With Quote
Old 12th August 2013, 08:25   #8
Calicebus
Junior Member
 
Join Date: Aug 2013
Posts: 1
Hallo,
how can i download the GetUniversalName_nsh?
Calicebus is offline   Reply With Quote
Old 12th August 2013, 14:01   #9
Anders
Moderator
 
Anders's Avatar
 
Join Date: Jun 2002
Location: ${NSISDIR}
Posts: 5,358
Quote:
Originally Posted by Calicebus View Post
Hallo,
how can i download the GetUniversalName_nsh?
The code is right there on the wiki page...

IntOp $PostCount $PostCount + 1
Anders is offline   Reply With Quote
Old 2nd December 2013, 06:37   #10
kleinstein
Junior Member
 
Join Date: Aug 2013
Posts: 15
Sorry, But this( http://nsis.sourceforge.net/Get_Universal_Name ) does not work on my windows 7.

i have tried with

WNetGetUniversalNameA
WNetGetUniversalName
WNetGetUniversalNameW

(.. as suggested from hier: http://forums.winamp.com/showthread.php?t=373932 )

these 3 makes no changes.. i get no unc path from any of them..
the return value is always the same path as input path(mapped drive path.)

* it is tested with NSIS Unicode Version(2.46.5 from http://www.scratchpaper.com/ )
kleinstein is offline   Reply With Quote
Reply
Go Back   Winamp & Shoutcast Forums > Developer Center > NSIS Discussion

Thread Tools Search this Thread
Search this Thread:

Advanced Search
Display Modes

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off

Forum Jump