Recent

Author Topic: Passing unicode filenames to external program  (Read 21826 times)

LeeJiEun

  • New Member
  • *
  • Posts: 17
Passing unicode filenames to external program
« on: October 21, 2013, 12:42:59 am »
Hi,
I'm trying to use a lazarus project to call ffmpeg using ShellExecuteExW and pass it a widestring with the parameters, including several filenames.

The problem I'm having is that sometimes the filenames might contain unicode characters, and those get all mangled up.
I also send the same string to ShowMessage() and the unicode characters display correctly, likewise if I set the Text of an edit control with it, it not only displays correctly but I can also copy it and invoke ffmpeg from a command prompt by pasting the copied text and it works. It only seems to mangle the characters when I use it in the ShellExecuteExW call.

Here's the procedure I'm using for the call.
Thanks.

procedure TForm1.Button4Click(Sender: TObject);
begin
  params := '-report -i "' + VideoFilename + '" -i "' + AudioFilename + '" -c copy "' + OutputFilename + '"';

  ExecuteFile:='c:\ffmpeg\bin\ffmpeg.exe';

    FillChar(SEInfo, SizeOf(SEInfo), 0) ;
    SEInfo.cbSize := SizeOf(TShellExecuteInfo) ;
    with SEInfo do begin
      fMask := SEE_MASK_NOCLOSEPROCESS;
      Wnd := Handle;
      lpFile := PWideChar(ExecuteFile) ;
      lpParameters := PWideChar(params) ;
      nShow := 1;
    end;
    if ShellExecuteExW(@SEInfo) then begin
      ShowMessage(params) ;
    end
    else ShowMessage('Error starting ffmpeg!') ;
end;

vrull

  • Full Member
  • ***
  • Posts: 118
Re: Passing unicode filenames to external program
« Reply #1 on: October 21, 2013, 12:54:51 am »
ShellExecute is not a Lazarus way. You could try TProcess instead.

Code: [Select]
var
  prProcess : TProcess;  // or it may be your form property, just drop TProcess on he form
...

begin
  prProcess.CommandLine := exePath + ' ' + commLine;
  prProcess.Execute;  // if you want to wait till process ends
//  ExecuteProcess(UTF8ToSys(exePath), commLine, []); // simplest modal way
  while prProcess.Running do
    begin
      sleep(30);
      Application.ProcessMessages; // keep main program alive
    end;

LeeJiEun

  • New Member
  • *
  • Posts: 17
Re: Passing unicode filenames to external program
« Reply #2 on: October 21, 2013, 01:06:24 am »
Okay, I'll give that a try and see what happens. Thanks.

LeeJiEun

  • New Member
  • *
  • Posts: 17
Re: Passing unicode filenames to external program
« Reply #3 on: October 21, 2013, 01:43:16 am »
Okay, that code threw an exception and the program hung (I think because TProcess.Create() wasn't called?).

I redid it based on some TProcess code I found on the freepascal wiki like this:

  prProcess := TProcess.Create(nil);
  prProcess.Executable:= 'c:\ffmpeg\bin\ffmpeg.exe';
  prProcess.Parameters.Add(params);
  prProcess.Options := prProcess.Options + [poWaitOnExit];
  prProcess.Execute;
  prProcess.Free; 

With this I get the same problem I had with ShellExecute.

vrull

  • Full Member
  • ***
  • Posts: 118
Re: Passing unicode filenames to external program
« Reply #4 on: October 21, 2013, 02:42:37 am »
Sorry about .Create. My code was a mix of two approaches - component is dropped to the form, and a variable; and both were incomplete.

I think the function UTF8ToSys(Path) could do the trick.

LeeJiEun

  • New Member
  • *
  • Posts: 17
Re: Passing unicode filenames to external program
« Reply #5 on: October 21, 2013, 04:00:20 am »
That's not working either.
I'm thinking there is no way to do this, it was supposed to be a quick and dirty utility to save me some time, now it's turning out to do the opposite.

Thanks for the assistance.

Deepaak

  • Sr. Member
  • ****
  • Posts: 454
Re: Passing unicode filenames to external program
« Reply #6 on: October 21, 2013, 06:34:23 am »
Try using

Code: [Select]
uses UTF8Process;
 
prProcess: TProcessUTF8;   


and do the reset of the above code of tprocess.

Quote
if prProcess.Parameters.Add(params); creates a problem then use prProcess.Parameters.Add(SysToUTF8(params));

i am not on my system so, otherwise i had checked the code before giving. have a try
« Last Edit: October 21, 2013, 06:41:58 am by deepaak99 »
Holiday season is online now. :-)

marcov

  • Administrator
  • Hero Member
  • *
  • Posts: 12896
  • FPC developer.
Re: Passing unicode filenames to external program
« Reply #7 on: October 21, 2013, 10:28:48 am »
FPC's TProcess uses CreateProcessA not CreateProcessW.

IIRC Lazarus has some UTF8 TProcess.

LeeJiEun

  • New Member
  • *
  • Posts: 17
Re: Passing unicode filenames to external program
« Reply #8 on: October 21, 2013, 03:24:02 pm »
I tried changing it from TProcess to TProcessUTF8, still no-go.
The file names I'm trying it with have a mix of English and Korean Hangul characters in them, if I rename the files to remove the Korean parts it runs fine. I'm using Windows 7 64 bit and the app is compiled as 64 bit.

I'm using a file open dialog to pick the files, then I used the file names to build a command line argument for ffmpeg, basically to save me from having to do it manually at a command prompt.

I've made it so it builds the command line and puts it into an edit control, from there I can copy and paste the whole thing into the command prompt and it works well enough for my purposes. When I past it the Korean parts show up as '???' but for some reason it still works, which is also weird.
I'll keep playing around with it as an academic exercise, since I am just learning Lazarus. I might also try it in C++ and see if I get the same problem.
Thanks for the  responses.

Bart

  • Hero Member
  • *****
  • Posts: 5727
    • Bart en Mariska's Webstek
Re: Passing unicode filenames to external program
« Reply #9 on: October 21, 2013, 06:57:34 pm »
procedure TForm1.Button4Click(Sender: TObject);
begin
  params := '-report -i "' + VideoFilename + '" -i "' + AudioFilename + '" -c copy "' + OutputFilename + '"';


Params is defined as WideString?
Same for VideoFileName etc.?
How are the vakues for those variables set?

Bart

LeeJiEun

  • New Member
  • *
  • Posts: 17
Re: Passing unicode filenames to external program
« Reply #10 on: October 21, 2013, 07:32:29 pm »

Params is defined as WideString?
Same for VideoFileName etc.?
How are the vakues for those variables set?

Yes, all widestring. I set them with an OpenDialog as shown here:

http://wiki.freepascal.org/Howto_Use_TOpenDialog

Like I said, it all seems to work right up to the point where it calls the other program.

Okay, I just found something..... apparently there's already a project written in Lazarus called WinFF that's similar to what I'm trying to do, so I'm going to take a look and see how they did it.  %)

Bart

  • Hero Member
  • *****
  • Posts: 5727
    • Bart en Mariska's Webstek
Re: Passing unicode filenames to external program
« Reply #11 on: October 21, 2013, 10:54:32 pm »
Yes, all widestring. I set them with an OpenDialog as shown here:

TOpenDialog.FileName is in UTF8 encoding.
Simply assigning it to a widestring probably won't do.
You need to do
Code: [Select]
uses
  LazUtf8, ...
var
  VideoFileName: WideString;
...
begin
  ...
  VideoFileName := Utf8ToUtf16(OpenDialog1.FileName);
  ...

Bart

LeeJiEun

  • New Member
  • *
  • Posts: 17
Re: Passing unicode filenames to external program
« Reply #12 on: October 22, 2013, 01:22:16 pm »
And.......... no.

I have discovered the secret to how they made this work in WinFF though.....

They didn't.

From their docs:

Quote
Use CHCP for international characters set the code page for the command prompt with the
system setting. The CHCP command arbitrarily crashes on later versions of XP and Vista. If this is
the case you can turn it off by unchecking the box for it. If it is unchecked though you will need to
remove non ANSI characters from file names of the videos to be converted.

There's a checkbox for CHCP. Tried it both ways.
Didn't work. So I'm moving on.

avra

  • Hero Member
  • *****
  • Posts: 2590
    • Additional info
Re: Passing unicode filenames to external program
« Reply #13 on: October 22, 2013, 03:57:51 pm »
I'm using a file open dialog to pick the files, then I used the file names to build a command line argument for ffmpeg
Maybe you are loosing UTF8 somewhere in between. Have you tried to skip file dialog and to do the job by hard coding your korean string path in IDE and test it like that?
ct2laz - Conversion between Lazarus and CodeTyphon
bithelpers - Bit manipulation for standard types
pasettimino - Siemens S7 PLC lib

BigChimp

  • Hero Member
  • *****
  • Posts: 5740
  • Add to the wiki - it's free ;)
    • FPCUp, PaperTiger scanning and other open source projects
Re: Passing unicode filenames to external program
« Reply #14 on: October 22, 2013, 04:04:38 pm »
@avra, I think Bart is completely correct:
TOpenDialog.FileName is in UTF8 encoding.
Simply assigning it to a widestring probably won't do.
You need to do
Code: [Select]
uses
  LazUtf8, ...
var
  VideoFileName: WideString;
...
begin
  ...
  VideoFileName := Utf8ToUtf16(OpenDialog1.FileName);
  ...

Bart
Want quicker answers to your questions? Read http://wiki.lazarus.freepascal.org/Lazarus_Faq#What_is_the_correct_way_to_ask_questions_in_the_forum.3F

Open source including papertiger OCR/PDF scanning:
https://bitbucket.org/reiniero

Lazarus trunk+FPC trunk x86, Windows x64 unless otherwise specified

 

TinyPortal © 2005-2018