Rename files with special char in filename

I need to rename a lot of files automatically, that have been copied over the network from a volume with macintosh namespace.
Some of them had a '/' in their filename which displays as a black box in the explorer.
When you read the list of filenames, this character display as '?'
The following methods did not work:
- Windows.RenameFile/MoveFile
- SHFileOperation(..FO_Rename..) (returns Error 114).

These methods do work:
- the shell's ren command
- rename these files with the
Windows NT Explorer.

How do I rename files in code like the Windows explorer (probably something with IShellXXXX interface).


Thanks,
EmmDieh

LVL 1
EmmDiehAsked:
Who is Participating?
I wear a lot of hats...

"The solutions and answers provided on Experts Exchange have been extremely helpful to me over the last few years. I wear a lot of hats - Developer, Database Administrator, Help Desk, etc., so I know a lot of things but not a lot about one thing. Experts Exchange gives me answers from people who do know a lot about one thing, in a easy to use platform." -Todd S.

hubdogCommented:
Because I do not have  mac files to test,the code below may not work.

procedure TForm1.Button1Click(Sender: TObject);
var
  P: PWideChar;
  NewPIDL,RenPIDL,PathPIDL: PItemIDList;
  Flags,
  NumChars: LongWord;
  NewShellFolder: IShellFolder;
  Value,PathValue:String;
begin
  SHGetDesktopFolder(FIDesktopFolder);
  Value:='hubdog.txt';//change c:\hubdog.txt to c:\newhubdog.txt
  PathValue:='C:\';
  NumChars := Length(PathValue);
  Flags := 0;
  P := StringToOleStr(PathValue);

  OLECheck(
    FIDesktopFolder.ParseDisplayName(
      Application.Handle,
      nil,
      P,
      NumChars,
      PathPIDL,
      Flags)
   );

  OLECheck(
    FIDesktopFolder.BindToObject(
            PathPIDL,
            nil,
            IID_IShellFolder,
            Pointer(NewShellFolder))
   );

  NumChars := Length(Value);
  Flags := 0;
  P := StringToOleStr(Value);

  OLECheck(
    NewShellFolder.ParseDisplayName(
      Application.Handle,
      nil,
      P,
      NumChars,
      NewPIDL,
      Flags)
   );

  if NewShellFolder.SetNameOf(
            Application.Handle,
            NewPIDL,
            StringToOleStr('newhubdog.txt'),
            128,
            RenPIDL
            )=noerror then
    showmessage('ok');
end;

good luck

hubdog
0
hubdogCommented:
I do not test the code on mac files so it may not work.

procedure TForm1.Button1Click(Sender: TObject);
var
  P: PWideChar;
  NewPIDL,RenPIDL,PathPIDL: PItemIDList;
  Flags,
  NumChars: LongWord;
  //Index: Integer;
  NewShellFolder: IShellFolder;
  Value,PathValue:String;
begin
  SHGetDesktopFolder(FIDesktopFolder);
  Value:='hubdog.txt';//change c:\hubdog.txt to c:\newhubdog.txt
  PathValue:='C:\';
  NumChars := Length(PathValue);
  Flags := 0;
  P := StringToOleStr(PathValue);

  OLECheck(
    FIDesktopFolder.ParseDisplayName(
      Application.Handle,
      nil,
      P,
      NumChars,
      PathPIDL,
      Flags)
   );

  OLECheck(
    FIDesktopFolder.BindToObject(
            PathPIDL,
            nil,
            IID_IShellFolder,
            Pointer(NewShellFolder))
   );

  NumChars := Length(Value);
  Flags := 0;
  P := StringToOleStr(Value);

  OLECheck(
    NewShellFolder.ParseDisplayName(
      Application.Handle,
      nil,
      P,
      NumChars,
      NewPIDL,
      Flags)
   );

  if NewShellFolder.SetNameOf(
            Application.Handle,
            NewPIDL,
            StringToOleStr('newhubdog.txt'),
            128,
            RenPIDL
            )=noerror then
    showmessage('ok');
  //SHChangeNotify(SHCNE_RENAMEITEM,SHCNF_FLUSH,NewPIDL,nil);
end;

good luck

hubdog
0

Experts Exchange Solution brought to you by

Your issues matter to us.

Facing a tech roadblock? Get the help and guidance you need from experienced professionals who care. Ask your question anytime, anywhere, with no hassle.

Start your 7-day free trial
MadshiCommented:
Well, the question is: How is the filename stored in the FAT? Have you tried enumerating the files that were copied with FindFirstFile? I guess the APIs like RenameFile, MoveFile and CopyFile will work if you give in the right string. You "simply" need to find the right string... Well, at least that is what I guess. I don't have such files here, so I can't test it...

Regards, Madshi.
0
Cloud Class® Course: CompTIA Cloud+

The CompTIA Cloud+ Basic training course will teach you about cloud concepts and models, data storage, networking, and network infrastructure.

EmmDiehAuthor Commented:
Hello Madshi,

I know how the file is stored in the fat, because when I right-click it, I have an additional tab "Mac Properties".

That is either because of NT or because of the driver from MacOpener 4.1.
Funny thing is, whe I deactivate the driver I can still see the Mac Properties tab sheet.

On this tab sheet it says for example:
BKK14017?S_88_4 (on NTFS)
Macintosh-Name: BKK14017/S_88_4
Datapath: xxx Byte
Resourcepath: yyy Byte
Type/Creator:   AAAA / BBBB
Attributes:..... and so on

But neither the NTFS Filename nor the Mac-Filename did work with the standard API Funktions.

Thanks,
Michael
0
EmmDiehAuthor Commented:

The System Control Pack on
http://www.delphifreestuff.com/delphi/
contains a tdfsSystemListView that
is able to rename the special files I mentioned:

li := dfsSystemListView.Items[i];
if li.Caption = 'BKK14014?S_88_3' then
  dfsSystemListView.RenameItem(dfsSystemListView.Items[i], 'BKK14014_S_88_3');

Unfortunately this is A LOT more than I need.


0
EmmDiehAuthor Commented:
Hello Hubdog,

I took your second post and tried it.

VERY GOOD, I will grant you the points, if you comment your piece of code.
(don't forget to declare the variable FIDesktopFolder).

You can test it with arbitrary file names like I also did, before I tried it on live data.

What memory/handles etc. do you need to release ?
I suppose you need to free the memory that was reserved by StringToOleStr ?

Here is how I read your code:
First you retrieve a pointer to the desktop shell folder.
From there you retrieve a new shell folder that points to the specified directory.
Last you change the name of the file in this shell folder.

For manipulation of files/folders etc. you always need Item Identifier Lists.


Thanks,
Michael

0
hubdogCommented:
Hi Michael
sorry for I forgot to declare the variable FIDeskTopFolder

var
  FIDeskTopFolder:IShellFolder;

I think what you understand is right.
And the item identifier List must be free like this
procedure FreeIDL(IDL:PItemIdList);
var
  ShellMalloc: IMalloc;
begin
  if IDL=nil then exit;
  SHGetMalloc(ShellMalloc);
  ShellMalloc.Free(IDL);
end;

And no need to free StringToOleStr
you can grep the source of Delphi Units
all them not free the StringToOleStr

good luck

hubdog

0
hubdogCommented:
>>First you retrieve a pointer to the desktop shell folder.
>>From there you retrieve a new shell >>folder that points to the specified directory.
>>Last you change the name of the file in this shell folder.

>>For manipulation of files/folders etc. you always need Item Identifier Lists.

That is what my code means

remember free the pitemidlist after you have used it.

0
EmmDiehAuthor Commented:
Hello hubdog,

Looking at the VCL-Source for StringToOleStr, I can see that this function uses the Win-API function SysAllocStringLen to reserve the memory.
The Win-SDK says you'll have to use SysFreeString to later free this string.

That is what I inserted into your code after each usage:
SysFreeString(P);
And Windows did not complain so far.....

Thanks,
Michael
0
hubdogCommented:
Hi,Michael

You may be right.I didn't pay much attention to the memory leak.So my programs always have lots of bugs
:(

thanks

hubdog
0
It's more than this solution.Get answers and train to solve all your tech problems - anytime, anywhere.Try it for free Edge Out The Competitionfor your dream job with proven skills and certifications.Get started today Stand Outas the employee with proven skills.Start learning today for free Move Your Career Forwardwith certification training in the latest technologies.Start your trial today
Delphi

From novice to tech pro — start learning today.