VB.NET GetShortFileName Equivalent

  • Thread starter Thread starter Allen
  • Start date Start date
A

Allen

Greetings,
I need to pass a file path to an application. This file path contains long
directory and file names. The target application, pdftotext.exe, only
accepts short directory and file names. Is there an equivalent VB.NET
function to the GetShortFileName and similar functions available in VB6.
Then I can pass the correct file path to pdftotext.exe.

Thanks in advance
Allen

Private Function funConvertPDF(ByVal fFile$) As String

'Create a new process

Dim myProcess As New Process

'This will break if cmd$ contains long file name. for example if fFile$ =
"d:\Library\TravelSystem\TravelRequest.pdf

Dim cmd$ = fFile & " " & Path.GetDirectoryName(fFile) & "\Temp.txt"

Try

myProcess.EnableRaisingEvents = True

myProcess = Process.Start("D:\pdftotext.exe", cmd$)

'do not procede until the converion is complete.

myProcess.WaitForExit()

'Close the process

myProcess.Close()

funConvertPDF = Path.GetDirectoryName(fFile) & "\Temp.txt"

Catch a As Exception

Console.WriteLine(a.Message)

Finally

End Try

End Function
 
Allen said:
Greetings,
I need to pass a file path to an application. This file path contains long
directory and file names. The target application, pdftotext.exe, only
accepts short directory and file names. Is there an equivalent VB.NET
function to the GetShortFileName and similar functions available in VB6.
Then I can pass the correct file path to pdftotext.exe.

Thanks in advance
Allen

Private Function funConvertPDF(ByVal fFile$) As String

'Create a new process

Dim myProcess As New Process

'This will break if cmd$ contains long file name. for example if fFile$ =
"d:\Library\TravelSystem\TravelRequest.pdf

Dim cmd$ = fFile & " " & Path.GetDirectoryName(fFile) & "\Temp.txt"

Try

myProcess.EnableRaisingEvents = True

myProcess = Process.Start("D:\pdftotext.exe", cmd$)

'do not procede until the converion is complete.

myProcess.WaitForExit()

'Close the process

myProcess.Close()

funConvertPDF = Path.GetDirectoryName(fFile) & "\Temp.txt"

Catch a As Exception

Console.WriteLine(a.Message)

Finally

End Try

End Function

I don't know of a .NET equivalent, but you can continue to call
GetShortPathName from VB.NET through P/Invoke, something like the
following air code:

Private Const MAX_PATH As Integer = 260

Private Declare Auto Function GetShortPathName Lib "kernel32" ( _
ByVal lpszLongPath As String, _
ByVal lpszShortPath As System.Text.StringBuilder, _
ByVal cchBuffer As Integer) As Integer


Public Function GetShortFileName(ByVal LongPath As String) As String
Dim ShortPath As New System.Text.StringBuilder(MAX_PATH)

Dim BufferSize As Integer = GetShortPathName( _
LongPath,
ShortPath,
ShortPath.Capacity)

' You might want to check the return value here
' If BufferSize is greater then ShortPath.Capacity then
' you need to reallocate the stringbuilder to BufferSize + 1
' and call GetShortPathName again. If the return value is 0
' then you will want to generate an error.

Return ShortPath.ToString()
End Function

HTH,
Tom Shelton
 
Hi,

Use the get filename api.

API Declare

Declare Function GetShortPathName Lib "kernel32" Alias "GetShortPathNameA" _

(ByVal lpszLongPath As String, ByVal lpszShortPath As String, _

ByVal cchBuffer As Integer) As Integer

Example

Dim strPath As String = Application.StartupPath

Dim strShortPath As String = Space(100)

GetShortPathName(strPath, strShortPath, 100)

TextBox1.Text = strShortPath

Ken
 
Hello,

Ken Tucker said:
Use the get filename api.

\\\
Private Declare Auto Function GetShortPathName Lib "kernel32.dll" ( _
ByVal lpszLongPath As String, _
ByVal lpszShortPath As String, _
ByVal cchBuffer As Int32 _
) As Int32
..
..
..
Dim strPath As String = Application.StartupPath
Dim strShortPath As String = Space(100)
Dim n As Int32 = GetShortPathName(strPath, strShortPath, 100)
MsgBox(Strings.Left(strShortPath, n))
///
 
Herfried said:
Hello,




\\\
Private Declare Auto Function GetShortPathName Lib "kernel32.dll" ( _
ByVal lpszLongPath As String, _
ByVal lpszShortPath As String, _
ByVal cchBuffer As Int32 _
) As Int32
.

Sorry, Herfried - but you should use a StringBuilder for the
lpszShortPath parameter:

Private Declare Auto Function GetShortPathName Lib "kernel32" ( _
ByVal lpszLongPath As String, _
ByVal lpszShortPath As System.Text.StringBuilder, _
ByVal cchBuffer As Int32) As Int32


Dim strPath As String = Application.StartupPath
Dim strShortPath As New System.Text.StringBuilder(260) ' MaxPath
Dim n As Int32 = GetShortPathName(strPath, strShortPath,
stShortPath.Capacity)
MsgBox(strShortPath.ToString())

Using strings for buffers is bad for performance considering the
immutable nature of strings...

Tom Shelton
 
Hello,

Tom Shelton said:
Sorry, Herfried - but you should use a StringBuilder for the
lpszShortPath parameter:

Private Declare Auto Function GetShortPathName Lib "kernel32" ( _
ByVal lpszLongPath As String, _
ByVal lpszShortPath As System.Text.StringBuilder, _
ByVal cchBuffer As Int32) As Int32


Dim strPath As String = Application.StartupPath
Dim strShortPath As New System.Text.StringBuilder(260) ' MaxPath
Dim n As Int32 = GetShortPathName(strPath, strShortPath,
stShortPath.Capacity)
MsgBox(strShortPath.ToString())

Using strings for buffers is bad for performance considering the
immutable nature of strings...

Are you really sure the 'StringBuilder' will have a better performance when
the function is called once?

;-)
 
Herfried,
Just because you said that in the other message about a string handling to
me.
But I tested it, when you want to have the test, I do it in the next reply.
I don't know and if it affects this question.
But I thought before testing, it would be nothing but concatenating a string
traditional way can be more than 100 times slower than stringbuilder.
I did not even look good if this question was concatentating a string (I
thought in a flash to see it).
(That has always been a problem with memory allocation).

When it in this routine just for one occurence, you know what I always say
about that.
"Do it in the way you like the most".
Cor
 
Herfried said:
Hello,




Are you really sure the 'StringBuilder' will have a better performance when
the function is called once?

;-)

No... It won't make a difference when the function is only called once -
or if it is called infrequently. But, I suppose I pickup on it because
I think it is a bad habbit to use the String type for return buffers.
Basically, because there are situations where the extra work - and
memory (since it can cause several temporary string objects to be
created) - can be detrimental. IMHO, it is always preferable to use a
StringBuilder when passing string buffers to unmanaged code...

You might say it is one of my P/Invoke pet peve's...
1. Using Alias for A/W functions - what's up with that?
2. Using As String for string buffers....
....

Tom Shelton
 
Hello,

Cor said:
Just because you said that in the other message about a
string handling to me.

In this case I think that the datatypes will me marshalled automatically and
the performance won't be that bad. In case of your sample you are
concatenating strings for example > 100 times. This can be very time
costly.
 
Herfried said:
Hello,




In this case I think that the datatypes will me marshalled automatically and
the performance won't be that bad. In case of your sample you are
concatenating strings for example > 100 times. This can be very time
costly.

Maybe not AS bad - but still, it is a bad habbit. The marshaller has to
work much harder marshaling String then it does with StringBuilder. It
isn't as though it is harder to use StringBuilder - in fact it is often
easier. Personally, if a buffer is going to be modified - using a
stringbuilder is the best way.

Tom Shelton
 
You might say it is one of my P/Invoke pet peve's...
1. Using Alias for A/W functions - what's up with that?

Why? I mean, why is it a problem for you in C#?
2. Using As String for string buffers....

Why? Strings are immutable -- so it is not surprising that you are not
allowed to use them in contexts that would mute them....
 
Why? I mean, why is it a problem for you in C#?

Of course it isn't a problem in C#. You do things different there. It
just doesn't make sense to me to alias to a specific version of these
functions when the runtime is capable of determining the best version on
it's own.
Why? Strings are immutable -- so it is not surprising that you are not
allowed to use them in contexts that would mute them....

Exactly why this bothers me. I don't like seeing people pass an
immutable object - such as string - to a function that is going to be
using it as a buffer. My point is that you should use
System.Text.StringBuilder in these scenarios.

See, my problem isn't with the way .NET works - just with the way people
are using it. I can understand it - since they are just doing what has
been done in VB.CLASSIC for so long. But, things work different in .NET
so I just think it should be pointed out when the opertunity arises.

Tom Shelton
 
Tom Shelton said:
Of course it isn't a problem in C#. You do things different there. It
just doesn't make sense to me to alias to a specific version of these
functions when the runtime is capable of determining the best version on
it's own.

Ok, I'll rephrase -- why is it a problem in any language?

There are at times many good reasons to not like the default behavior.
Exactly why this bothers me. I don't like seeing people pass an
immutable object - such as string - to a function that is going to be
using it as a buffer. My point is that you should use
System.Text.StringBuilder in these scenarios.

Yes, and if you pass a plain old string then it won't work!
See, my problem isn't with the way .NET works - just with the way people
are using it. I can understand it - since they are just doing what has
been done in VB.CLASSIC for so long. But, things work different in .NET
so I just think it should be pointed out when the opertunity arises.

Ah, this I agree with.
 
Ok, I'll rephrase -- why is it a problem in any language?

There are at times many good reasons to not like the default behavior.

I'm not trying to be argumentative - but when would you want to call a A
version of a function on a NT box? I was under the impression that on
NT, that the A versions simply converted to wide strings and then called
the W version, and then coverted the results back to Ansi.... Seems
like simply adding Auto and avoiding the Alias can save a lot of
unnecesary string conversions...
Yes, and if you pass a plain old string then it won't work!

You know, I have never tried it in C# - but I'm pretty sure that it does
in fact work in VB.NET. There is a fairly significant amount of
overhead since the marshaler has to create temporary copies that
actually get passed, but in the end it does actually work.
Ah, this I agree with.

Wow! We agree on something :)

Tom Shelton
 
Tom Shelton said:
You know, I have never tried it in C# - but I'm pretty sure that it does
in fact work in VB.NET. There is a fairly significant amount of
overhead since the marshaler has to create temporary copies that
actually get passed, but in the end it does actually work.

It will work in VB.NET.
 
Tom Shelton said:
I'm not trying to be argumentative - but when would you want to call a A
version of a function on a NT box? I was under the impression that on
NT, that the A versions simply converted to wide strings and then called
the W version, and then coverted the results back to Ansi.... Seems
like simply adding Auto and avoiding the Alias can save a lot of
unnecesary string conversions...

I was not necessarily talking about the desire to call the "A" version of
functions on an NT box, I was actually referring to Win9x behavior that I
learned while writing the MS Layer for Unicode, and the aliasing rules in
general. But all of the following "exceptions" to the general rules (and
keep in mind that there are a lot more than these examples!). And note that
some apply to NT as well!

1) Some "A" functions have to convert a Unicode data source do not use the
default system code page for conversions of data -- if you let .NET convert
in one code page and then the API uses another then you recieve cottage
cheese on the other end -- GetLocaleInfoA is a good example of this.

2) Some APIs have no A/W versions and need specific work done to properly
convert -- such as the conversion functions themselves,
WideCharToMultiByte/MultiByteToWideChar. Note that there is functionality in
the APIs that is not yet available in .NET so they are reasonable to call
via pinvoke. The default behavior will take the time to try aliasing. This
is true on NT as well!

3) Some new APIs are Unicode only, NT only (e.g. IsNLSDefinedString) and
have no suffix -- but again on NT the alias behavior forces the perf hit
because it has to check for a "W" version before trying the un-aliased
version. This is similar to #3, though #3 must suport a Unicode and a
non-Unicode string whereas this is a Unicode-only API.

4) Some APIs exist in the "W" version on Win9x (e.g. ExtTextOutW).
 
I was not necessarily talking about the desire to call the "A" version of
functions on an NT box, I was actually referring to Win9x behavior that I
learned while writing the MS Layer for Unicode, and the aliasing rules in
general. But all of the following "exceptions" to the general rules (and
keep in mind that there are a lot more than these examples!). And note that
some apply to NT as well!

1) Some "A" functions have to convert a Unicode data source do not use the
default system code page for conversions of data -- if you let .NET convert
in one code page and then the API uses another then you recieve cottage
cheese on the other end -- GetLocaleInfoA is a good example of this.

2) Some APIs have no A/W versions and need specific work done to properly
convert -- such as the conversion functions themselves,
WideCharToMultiByte/MultiByteToWideChar. Note that there is functionality in
the APIs that is not yet available in .NET so they are reasonable to call
via pinvoke. The default behavior will take the time to try aliasing. This
is true on NT as well!

3) Some new APIs are Unicode only, NT only (e.g. IsNLSDefinedString) and
have no suffix -- but again on NT the alias behavior forces the perf hit
because it has to check for a "W" version before trying the un-aliased
version. This is similar to #3, though #3 must suport a Unicode and a
non-Unicode string whereas this is a Unicode-only API.

4) Some APIs exist in the "W" version on Win9x (e.g. ExtTextOutW).

Ok, you do have some valid points here. But, I don't think it applies
to the majority of functions. I think in at least 95% of the cases the
alias is going to do more harm then good. I am certainly not saying
that Alias should never be used - but that it is way overused.

Tom Shelton
 
Tom Shelton said:
Ok, you do have some valid points here. But, I don't think it applies
to the majority of functions. I think in at least 95% of the cases the
alias is going to do more harm then good. I am certainly not saying
that Alias should never be used - but that it is way overused.

I am not sure I understand what you are saying you prefer here -- you would
like people to call the "A" or "W" versions directly, with no aliasing? Or
something else?

It would be easier to understand what you meant if you posted an example
declare you believe to be "good" and then the version that you believe to be
"bad".
 
Back
Top