Twitter iPhone pliant OnePlus 11 PS5 Disney+ Orange Livebox Windows 11

Convertir UNC en chemin sur lettre de lecteur

3 réponses
Avatar
Gloops
Bonjour tout le monde,

J'ai besoin de transformer un chemin UNC en chemin bas=E9 sur une lettre =

de lecteur (=E0 charge pour l'utilisateur de l'avoir d=E9fini avant).

Je pars de l'exemple All drives de=20
http://allapi.mentalis.org/apilist/GetLogicalDriveStrings.shtml, dans un =

module standard, et j'ajoute ce qui suit (quelques fonctions ne sont=20
plus utilis=E9es).

Dites-moi voir si on peut faire mieux.

=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D

Public Function UNCenLettre(strUNC As String) As String
Dim strTmp As String
Dim strChemins() As String
Dim strAllDrives As String
Dim N As Integer, Nb As Integer
strAllDrives =3D fGetDrives
Do
ReDim Preserve strChemins(1, N)
strTmp =3D Mid$(strAllDrives, 1, InStr(strAllDrives,=20
vbNullChar) - 1)
strChemins(0, N) =3D strTmp
If GetDriveType(Left$(strTmp, 2)) =3D DRIVE_REMOTE Then
strChemins(1, N) =3D JusqueZero(fGetUNCPath(Left$(strTmp=
,=20
2)))
End If
strAllDrives =3D Mid$(strAllDrives, InStr(strAllDrives,=20
vbNullChar) + 1)
N =3D N + 1
Loop While Not strAllDrives =3D ""
Nb =3D UBound(strChemins, 2)
For N =3D 0 To Nb - 1
'Debug.Print strChemins(0, N) + " | " + strChemins(1, N)
If Left$(strUNC, Len(strChemins(1, N))) =3D strChemins(1, N) And=20
Len(strChemins(1, N)) > 0 Then
UNCenLettre =3D strChemins(0, N) + Right$(strUNC, Len(strUNC) - =

Len(strChemins(1, N)))
End If
Next
If Len(UNCenLettre) =3D 2 Then UNCenLettre =3D UNCenLettre + "\"
End Function

'________

Public Function JusqueZero(strIn As String) As String
Dim I As Integer
I =3D InStr(strIn, Chr$(0))
JusqueZero =3D Left$(strIn, I - 1)
End Function

3 réponses

Avatar
Jean-marc
Gloops wrote:
Bonjour tout le monde,

J'ai besoin de transformer un chemin UNC en chemin basé sur une lettre
de lecteur (à charge pour l'utilisateur de l'avoir défini avant).

Je pars de l'exemple All drives de
http://allapi.mentalis.org/apilist/GetLogicalDriveStrings.shtml, dans
un module standard, et j'ajoute ce qui suit (quelques fonctions ne
sont plus utilisées).

Dites-moi voir si on peut faire mieux.

====================================================== >
Public Function UNCenLettre(strUNC As String) As String
Dim strTmp As String
Dim strChemins() As String
Dim strAllDrives As String
Dim N As Integer, Nb As Integer
strAllDrives = fGetDrives
Do
ReDim Preserve strChemins(1, N)
strTmp = Mid$(strAllDrives, 1, InStr(strAllDrives,
vbNullChar) - 1)
strChemins(0, N) = strTmp
If GetDriveType(Left$(strTmp, 2)) = DRIVE_REMOTE Then
strChemins(1, N) > JusqueZero(fGetUNCPath(Left$(strTmp, 2)))
End If
strAllDrives = Mid$(strAllDrives, InStr(strAllDrives,
vbNullChar) + 1)
N = N + 1
Loop While Not strAllDrives = ""
Nb = UBound(strChemins, 2)
For N = 0 To Nb - 1
'Debug.Print strChemins(0, N) + " | " + strChemins(1, N)
If Left$(strUNC, Len(strChemins(1, N))) = strChemins(1, N) And
Len(strChemins(1, N)) > 0 Then
UNCenLettre = strChemins(0, N) + Right$(strUNC, Len(strUNC) -
Len(strChemins(1, N)))
End If
Next
If Len(UNCenLettre) = 2 Then UNCenLettre = UNCenLettre + ""
End Function

'________

Public Function JusqueZero(strIn As String) As String
Dim I As Integer
I = InStr(strIn, Chr$(0))
JusqueZero = Left$(strIn, I - 1)
End Function



Hello,

je ne sais pas si on peut faire "mieux", car il faudrait au préalabale
donner une définition consensuelle de la notion de "mieux", ce qui n'est
pas gagné d'avance et pourrait sans nul doute occuper ce forum pendant
des semaines :-)


Ceci étant posé, on peut quand même faire des remarques sur le code
que tu proposes, remarques qui ne sont pas des jugements de valeur
mais plutot des généralités.

1) Byval vs Byref
Si l'argument de la fonction ne doit pas être modifié (cas des arguments
de tes 2 fonctions), il est d'usage de le mentionner clairement quand le
langage le permet. C'est le cas ici, il vaut mieux mettre un Byval devant:
- C'est plus sur (ca évite une destruction accidentelle de la variable)
- C'est mieux d'un point de vue sémantique (tu marques clairement ton
intention au lecteur)


2) Commentaires
Des commentaires ne seraient pas inutiles, c'est la pratique en
programmation
de commenter non pas la synatxe MAIS la sémantique (quelles sont mes
intentions?).


3) Convention de Nommage des variables
- Il n'est pas d'usage d'employer une majuscule comme nom de variable.
N est ici mal choisi.
- Pour les variables de boucles, l'usage est d'utiliser i, j, k, etc.
Ainsi un lecteur qui voit i, j, k sait immédiatement que c'est une variable
de boucle.
- la lettre "i" ne s'emploie jamais pour autre chose que comme compteur de
boucle.


3bis) Une variable pour chaque usage
Tu utilises N pour compter, donc comme une sorte d'index, puis comme
variable
de boucle. En dehors du fait que le nom était mal choisi, le fait d'utiliser
la même variable pour 2 usages complètement différent rend le code très
confus, difficile à suivre et à débugger. On préfèrera toujours créer une
nouvelle variable.


4) Ne jamais répéter de code
Dans la boucle, on calcule 3 fois la même expression: Len(strChemins(1, i))
Il est de bon ton de la calculer une seule fois, de l'assigner à une
variable
et de s'en tenir ensuite à l'utilisation de la variable.


5) Concaténation en VB
En VB, l'opérateur de concaténation de chaines de caractère est le signe
ampersande (&). Certes ça marche avec le '+' mais c'est peu efficace et
surtout très mauvais d'un point de vue sémantique.


6) Pas de hard codage : Les constantes explicites.
Tu emploies Chr$(0) dans la fonction JusqueZero; Il vaut mieux
toujours employer la constante nommée : vbNullChar (comme tu le fais
d'ailleurs dans la fonction précédente).


7) Présentation et indentation
// Si c'est ton logiciel de messagerie qui a déformé ton code, oublie ceci.
Il est d'usage d'indenter son code en utilisant le caractère Tabulation, et
JAMAIS des espaces fantaisistes.


8) Casser ou rendre non ambigue les expressions complexes

Le If suivant est illisble et source d'énormes erreurs:

If Left$(strUNC, Len(strChemins(1, N))) = strChemins(1, N) And
Len(strChemins(1, N)) > 0 Then

Dans ce cas, il vaut meiux parenthéser et/ou passer explicitement
à la ligne, comme ceci:

If ((Left$(strUNC, lenChem) = strChemins(1, i)) And _
(lenChem > 0) _
) Then

Mais le mieux dans ce genre de cas est encore de faire ceci:

Dim Cond1 As Boolean, Cond2 As Boolean

' Calcul des conditions
Cond1 = Left$(strUNC, lenChem) = strChemins(1, i)
Cond2 = lenChem > 0

' test
If Cond1 And Cond2 Then

C'est plus propre, plus joli, moins source d'erreurs et plus reposant!


9) Nommage des fonctions
Dans une optique européenne, il est de plus en plus d'usage quand
on a une connaissance suffisante de l'anglais de nommer les fonctions
en anglais.

Par exmeple : UNCPathToDriveLetterpath (pas génial mais c'est l'idée)
TrimToNull (pas extraordinaire non plus, mais bon)

Je sais que ce point est sujet à polémique, je n'insisterais donc pas :-)


Voila, je pense avoir fait le tour.
Je te propose donc le code modifié, mettant en pratique les
différentes remarques (à l'exception des commentaires):




Public Function UNCenLettre(ByVal strUNC As String) As String
Dim strTmp As String
Dim strChemins() As String
Dim strAllDrives As String
Dim N As Integer, Nb As Integer
Dim i As Integer
Dim Cond1 As Boolean, Cond2 As Boolean

strAllDrives = fGetDrives
Do
ReDim Preserve strChemins(1, Idx)
strTmp = Mid$(strAllDrives, 1, InStr(strAllDrives, vbNullChar) - 1)
strChemins(0, Idx) = strTmp
If GetDriveType(Left$(strTmp, 2)) = DRIVE_REMOTE Then
strChemins(1, Idx) = JusqueZero(fGetUNCPath(Left$(strTmp, 2)))
End If
strAllDrives = Mid$(strAllDrives, InStr(strAllDrives, vbNullChar) +
1)
Idx = Idx + 1
Loop While Not strAllDrives = ""

Nb = UBound(strChemins, 2)
For i = 0 To Nb - 1
lenChem = Len(strChemins(1, i))

Cond1 = Left$(strUNC, lenChem) = strChemins(1, i)
Cond2 = lenChem > 0

If Cond1 And Cond2 Then
UNCenLettre = strChemins(0, i) & Right$(strUNC, Len(strUNC) -
lenChem)
End If

Next i
If Len(UNCenLettre) = 2 Then
UNCenLettre = UNCenLettre & ""
End If
End Function



Public Function JusqueZero(ByVal strIn As String) As String
Dim p As Long

p = InStr(strIn, vbNullChar)
JusqueZero = Left$(strIn, p - 1)
End Function



Bonne soirée !



--
Jean-marc Noury (jean_marc_n2)
Microsoft MVP - Visual Basic
mailto: remove '_no_spam_' ;
FAQ VB: http://faq.vb.free.fr/
Avatar
Gloops
Jean-marc a écrit, le 17/07/2007 22:11 :
Hello,

je ne sais pas si on peut faire "mieux", car il faudrait au préalabal e
donner une définition consensuelle de la notion de "mieux", ce qui n' est
pas gagné d'avance et pourrait sans nul doute occuper ce forum pendan t
des semaines :-)




Que voilà pourtant des conseils précieux.
Le N était une réminiscence du GWbasic, comme quoi, quand on est
dynosaure, de nos jours, il faut s'adapter ...

Peut-être dans la même lignée, l'économie de moyens : une fois qu 'une
variable n'était plus utilisée, on s'en servait pour autre chose, plu tôt
qu'en déclarer une autre. C'est que l'octet, à l'époque, c'était une
donnée rare (tu aurais vu la tête des stagiaires ce midi, quand je le ur
ai dit qu'après avoir fait un stage je n'ai même pas été payé d e quoi
acheter une machine à écrire pour taper le rapport : hein ? une machi ne
à écrire ? C'est quoi ?)

Le coup du ByVal, il m'est arrivé la semaine dernière d'être obligé de
le mettre, sinon ça plantait juste à cause de ça. Sinon, c'est vrai que
j'ai un peu une fâcheuse tendance à négliger ça.

Je mets toujours vbCrLf plutôt que chr$(13) + chr$(10), mais le
vbNullChar je ne l'avais pas en tête. Je devrais me mettre à jour
là-dessus aussi. A ce que j'ai entendu c'est un motif de se faire
rétamer par la moulinette de conversion automatique de VB6 vers VB.Net
(donc on pourrait dire que c'est bon pour l'emploi, mais pas de pot,
c'est dans un secteur où on n'en manque pas).

Ah, oui, le coup de stocker un calcul intermédiaire dans une variable
avant de s'en servir plusieurs fois, quelqu'un (peut-être toi) m'en
avait parlé il y a un an ou deux. ça va bien finir par entrer.
J'entendais bien une idée qui me rôdait dans la tête, aussi, quand j'ai
tapé ça :)

Ah, oui, l'indentation, jamais moyen de savoir à l'avance comment elle
sera faite ici. J'aurais bien guetté la parution pour voir comment ça
sortait, et puis je l'ai découverte en même temps que ta réponse. E n
plus, hier soir il fallait que je fasse "fissah" (qui a dit défense de
la culture française ?)

C'est vrai que mettre une condition dans une variable booléenne ça
allège la syntaxe, mais alors il faut veiller à l'initialiser au bon
endroit. Souvent, une fois avant la boucle, et une fois à la fin
(surtout pour un While).

Il n'y a pas longtemps j'ai fait un truc du genre

If PatateDouceAntiConstitutionnelleEtTuttiQuanti _
And BricolesAnnexesEtAutres _
And AutresChosesEncore
Then
'si oui
Else
'si non
End If

Il m'a semblé que le Then aidait à bien visualiser où se termine
l'énoncé des conditions (c'est vrai que pour un While, l'équivalent
n'existe pas).

C'est vrai que les commentaires c'est un truc auquel on pense parfois un
peu tard. Ce matin, j'ai réalisé que je n'ai même pas écrit dans mon
module pourquoi je l'ai mis là (indépendamment du fait que c'est moi qui
l'ai mis et avec quelle version du fichier). En plus, comme j'ai vu ça
dans une copie, j'ai oublié après et je n'ai pas encore mis les
commentaires appropriés. Je vais m'atteler à ça en arrivant demain.

Si la personne qui a développé ce sur quoi je travaille avait appliqu é
ça, je serais passé au fichier suivant depuis un moment (pourtant, de s
commentaires, il y en a, mais le code est toujours plus clair pour celui
qui l'a écrit :) ).

Ah oui, un nom en Anglais : c'est vrai que parfois, on trouve des trucs
intéressants dans des newsgroups en Russe, si il n'y a pas une sauce en
Anglais avec on est mal (à moins de parler Russe).

Sur les applications de traduction, j'ai tendance à avoir un peu de
flottement : soit je mets les noms en Anglais pour être bien compris de
tous ceux qui passent derrière, soit, si c'est une application que je
suis censé mener seul à terme pour une boîte française, je les me ts en
Français pour défendre la culture. Moyennant quoi, il m'est même ar rivé
de faire un panachage des deux dans une même application, ce qui je
crois est bien la seule solution non défendable.

A propos de traduction, l'application avait été développée avec u ne
interface source en Anglais pour être comprise partout, à charge pour
une personne dans chaque pays de traduire. Pas de pot, le client suivant
a fait son application en Français quand il a décidé que dans les p ays
où on parle Anglais la main d'œuvre est moins chère. ça fait que j'ai
des textes en français dans un champ que j'ai appelé English, et la
traduction en Anglais sera dans le champ Local. ça ne se voit pas à
l'écran, mais comme clarté du code, c'est vrai que je peux repasser.

Ah oui il reste le + : quand j'ai débarqué sur une application Access ,
j'aimais bien utiliser le &, c'était commode, et puis on m'a expliqué
que c'était une application qu'il allait falloir convertir sur plusieur s
versions d'Access, donc on la développait avec la version la plus
ancienne (II dans un cas, 95 dans un autre), et elle allait ensuite
tourner sur les autres versions. Dans ce cas de figure, si on a un & qui
se balade quelque part dans le code, on se fait jeter au moment de la
conversion.

On doit alors le remplacer par un +, ce qui implique qu'on doit rendre
explicites toutes les conversions de données. Par exemple
"Il existe " & i & " enregistrements dans la table"

devient la syntaxe légère au possible suivante :

"Il existe " + VBA.Str$(i) + " enregistrements dans la table"

Je te concède que lorsqu'on apprend ça, on a besoin d'un peu de temps
pour s'habituer à l'idée. Je me suis donc demandé si lorsqu'on alla it
avoir éclusé les autres points, je n'allais pas proposer une version
sous cette forme pour ce contexte (bases Access multi-versions
impliquant la version 95), et une autre avec "&" comme opérateur de
concaténation pour les autres utilisations. Je vais voir si j'ai encore
un peu de temps à passer là-dessus.

HS : A propos de bases Access 95, si quelqu'un est concerné, il faut
aussi préfixer Recordset, Database et ce qui tourne autour en DAO. Si o n
ne le fait pas on n'est pas ennuyé en convertissant en Access 2000, mai s
le problème apparaît lorsqu'on veut réutiliser un des modules dans une
base qui a été développée sous Access 2000 (donc par défaut ave c des
objets ADO).

En tout cas, merci beaucoup pour ces remarques. On devrait faire ça plu s
souvent, on verrait moins d'horreurs quand on passe faire de la
maintenance de code.

(oh, mais je réalise que ça rend bavard ...)
Avatar
Jean-marc
Gloops wrote:
Jean-marc a écrit, le 17/07/2007 22:11 :
Hello,





Que voilà pourtant des conseils précieux.
Le N était une réminiscence du GWbasic, comme quoi, quand on est
dynosaure, de nos jours, il faut s'adapter ...




J'ai connu aussi :-)

Le coup du ByVal, il m'est arrivé la semaine dernière d'être obligé de
le mettre, sinon ça plantait juste à cause de ça. Sinon, c'est vrai
que j'ai un peu une fâcheuse tendance à négliger ça.




Ca peut effectivement planter lors des appels aux API Windows.


Je mets toujours vbCrLf plutôt que chr$(13) + chr$(10), mais le
vbNullChar je ne l'avais pas en tête. Je devrais me mettre à jour
là-dessus aussi. A ce que j'ai entendu c'est un motif de se faire
rétamer par la moulinette de conversion automatique de VB6 vers VB.Net




Oui et d'une façon générale c'est plus agréable pour celui qui lit.


Ah, oui, le coup de stocker un calcul intermédiaire dans une variable
avant de s'en servir plusieurs fois, quelqu'un (peut-être toi) m'en
avait parlé il y a un an ou deux. ça va bien finir par entrer.
J'entendais bien une idée qui me rôdait dans la tête, aussi, quand
j'ai tapé ça :)




Plus lisible, plus performant, diminue le risque d'erreurs : Que du
bonheur !


Ah, oui, l'indentation, jamais moyen de savoir à l'avance comment elle
sera faite ici. J'aurais bien guetté la parution pour voir comment ça
sortait, et puis je l'ai découverte en même temps que ta réponse.




Oui avec les lecteurs de news on ne sait pas toujours à l'avance!



C'est vrai que mettre une condition dans une variable booléenne ça
allège la syntaxe, mais alors il faut veiller à l'initialiser au bon
endroit. Souvent, une fois avant la boucle, et une fois à la fin
(surtout pour un While).




Oui, c'est sur. Mais franchement, ça vaut le coup parce que ça évite
des tas d'erreurs. Mieux, ça permet parfois de mettre en évidence une
erreur de conception.

Dans ton code, une fois converti, on arrive à ça:

For i = 0 To Nb - 1
lenChem = Len(strChemins(1, i))

Cond1 = Left$(strUNC, lenChem) = strChemins(1, i)
Cond2 = lenChem > 0

If Cond1 And Cond2 Then
...
End If
Next i

Et bien en lisant ceci, on voit qu'il serait plus correct d'écrire:


For i = 0 To Nb - 1
lenChem = Len(strChemins(1, i))
If lenChem > 0 Then
If Left$(strUNC, lenChem) = strChemins(1, i) Then
...
End If
End If
Next i


C'est vrai que les commentaires c'est un truc auquel on pense parfois
un peu tard. Ce matin, j'ai réalisé que je n'ai même pas écrit dans
mon module pourquoi je l'ai mis là (indépendamment du fait que c'est
moi qui l'ai mis et avec quelle version du fichier). En plus, comme
j'ai vu ça dans une copie, j'ai oublié après et je n'ai pas encore
mis les commentaires appropriés. Je vais m'atteler à ça en arrivant
demain.





Une fois pris l'habitude ça devient automatique. Conseil: ne jamais
commenter la syntaxe, car on suppose que le lecteur connait la
syntaxe de VB. Au contraire, on commentera la sémantique, c'est à
dire qu'on explique ses intentions. Ca permet au relecteur de voir
si l'implémentation (le code) est conforme au commentaires (les
spécifications).


Sur les applications de traduction, j'ai tendance à avoir un peu de
flottement : soit je mets les noms en Anglais pour être bien compris
de tous ceux qui passent derrière, soit, si c'est une application que
je suis censé mener seul à terme pour une boîte française, je les
mets en Français pour défendre la culture. Moyennant quoi, il m'est
même arrivé de faire un panachage des deux dans une même application,
ce qui je crois est bien la seule solution non défendable.




Oui, un panaché n'est pas terrible, effectivement.

> Ah oui il reste le + : quand j'ai débarqué sur une application Access,
j'aimais bien utiliser le &, c'était commode, et puis on m'a expliqué
que c'était une application qu'il allait falloir convertir sur
plusieurs versions d'Access, donc on la développait avec la version
la plus ancienne (II dans un cas, 95 dans un autre), et elle allait
ensuite tourner sur les autres versions. Dans ce cas de figure, si on
a un & qui se balade quelque part dans le code, on se fait jeter au
moment de la conversion.



Ok, c'est un cas particulier. Dans ce cas, de fait, je ne vois pas mieux
que de faire avec '+'. Mais alors on peut mettre un petit commentaire du
genre :

' -------------------------------------------------------------
' Compatibility issue :
' use '+' to concatenate as '&' does not work with Access :-(
' -------------------------------------------------------------

ou en français:

' ---------------------------------------------------------------------
' Problème de compatibilité avec VBA
' '&' est interdit en VBA, on utilise donc '+' pour concaténer :-(
' ---------------------------------------------------------------------


En tout cas, merci beaucoup pour ces remarques. On devrait faire ça
plus souvent, on verrait moins d'horreurs quand on passe faire de la
maintenance de code.



Avec plaisir, c'est un exercice que j'affectionne :-)


--
Jean-marc Noury (jean_marc_n2)
Microsoft MVP - Visual Basic
mailto: remove '_no_spam_' ;
FAQ VB: http://faq.vb.free.fr/