Save file on Desktop

This is the forum for miscellaneous technical/programming questions.

Moderator: 2ffat

Save file on Desktop

Postby Lena » Mon Nov 13, 2017 2:39 am

Hi.
My program VCL in OnClose event should take these steps:
1. If the Desktop is not created then create a folder named MyFiles.
2. Load a file to the TMemoryStream.
3. Save this file to Desktop in the MyFiles folder with the encoding UTF-8. If the file exists, then overwrite it. The file has an extension .ini
I can not find С++ examples with Desktop anywhere. I only know the second step:
Code: Select all
String path = (ExtractFilePath(ParamStr(0)));
path = path + L"setup.ini";
  if(FileExists(path))
    { 
          std::unique_ptr<TMemoryStream> SFile(new TMemoryStream());
          SFile->LoadFromFile(path);
         SFile->Position = 0;
//***

Please help.
Lena
BCBJ Master
BCBJ Master
 
Posts: 520
Joined: Sun Feb 06, 2011 1:28 pm

Re: Save file on Desktop

Postby rlebeau » Mon Nov 13, 2017 3:27 pm

Lena wrote:1. If the Desktop is not created then create a folder named MyFiles.


What "desktop" are you referring to exactly? The Windows desktop? You need to be more specific.

Lena wrote:The file has an extension .ini


Then why are you using TMemoryStream instead of T(Mem)IniFile?
Remy Lebeau (TeamB)
Lebeau Software
User avatar
rlebeau
BCBJ Author
BCBJ Author
 
Posts: 1450
Joined: Wed Jun 01, 2005 3:21 am
Location: California, USA

Re: Save file on Desktop

Postby Lena » Tue Nov 14, 2017 3:21 am

Yes Windows desktop. Is it different computer, path to windows desktop may be different?

Thank you for T(Mem)IniFile. My female brain forgot that there is this useful class. :)
Lena
BCBJ Master
BCBJ Master
 
Posts: 520
Joined: Sun Feb 06, 2011 1:28 pm

Re: Save file on Desktop

Postby rlebeau » Tue Nov 14, 2017 12:21 pm

Lena wrote:Yes Windows desktop. Is it different computer, path to windows desktop may be different?


Use the Win32 API SHGetFolderPath() or SHGetKnowFolderPath() function to query Windows for the user's actual Desktop folder path.

Use the RTL's ForceDirectories() function to ensure your sub folder exists.

Then save the file to your sub folder as needed.

For example:

Code: Select all
String __fastcall GetSpecialFolderPath(int Folder)
{
    String result;
    TCHAR path[MAX_PATH] = {};
    if (SUCCEEDED(SHGetFolderPath(NULL, Folder, NULL, SHGFP_TYPE_CURRENT, path)))
         result = IncludeTrailingPathDelimiter(path);
    return result;
);

/* or:
String __fastcall GetKnownFolderPath(KNOWNFOLDERID Folder)
{
    String result;
    PWSTR path;
    if (SUCCEEDED(SHGetKnownFolderPath(Folder, 0, NULL, &path)))
    {
        result = IncludeTrailingPathDelimiter(path);
        CoTaskMemFree(path);
    }
    return result;
}
*/


Code: Select all
String DesktopFolder = GetSpecialFolderPath(CSIDL_DESKTOPDIRECTORY);
// or:
// String DesktopFolder = GetKnownFolderPath(FOLDERID_Desktop);
if (!DesktopFolder.IsEmpty())
{
    String MyFilesPath = DesktopFolder + _D("MyFiles") + PathDelim;
    if (ForceDirectories(MyFilesPath))
    {
        String DefSetupPath = ExtractFilePath(ParamStr(0)) + _D("setup.ini");
        if (FileExists(DefSetupPath))
        {
            String NewSetupPath = MyFilesPath + _D("setup.ini");
            ::CopyFile(DefSetupPath.c_str(), NewSetupPath.c_str(), TRUE);
        }
    }
}
Remy Lebeau (TeamB)
Lebeau Software
User avatar
rlebeau
BCBJ Author
BCBJ Author
 
Posts: 1450
Joined: Wed Jun 01, 2005 3:21 am
Location: California, USA

Re: Save file on Desktop

Postby Lena » Thu Nov 16, 2017 2:28 am

Thank you very much!
I have two questions:
1. Do I need to delete the file from the folder MyFiles before I copy it there? Is it best way? I need to overwrite the file.
2. I use the received file in the Android project. How to get it after copying encoded UTF-8?
Lena
BCBJ Master
BCBJ Master
 
Posts: 520
Joined: Sun Feb 06, 2011 1:28 pm

Re: Save file on Desktop

Postby rlebeau » Thu Nov 16, 2017 1:15 pm

Lena wrote:1. Do I need to delete the file from the folder MyFiles before I copy it there?


No. Read the CopyFile() documentation about the bFailIfExist parameter:

If this parameter is TRUE and the new file specified by lpNewFileName already exists, the function fails. If this parameter is FALSE and the new file already exists, the function overwrites the existing file and succeeds.


Lena wrote:I need to overwrite the file.


Then set the bFailIfExist parameter of CopyFile() to FALSE.

Lena wrote:I use the received file in the Android project. How to get it after copying encoded UTF-8?


I don't understand what you are asking.
Remy Lebeau (TeamB)
Lebeau Software
User avatar
rlebeau
BCBJ Author
BCBJ Author
 
Posts: 1450
Joined: Wed Jun 01, 2005 3:21 am
Location: California, USA

Re: Save file on Desktop

Postby Lena » Fri Nov 17, 2017 1:23 am

I don't understand what you are asking.


My program has two versions. One for Windows is the second for Android. In Windows versions I work with a file ini encoded ANSI. After closing my Windows program, I want to get a duplicate of this file but in the encoding UTF-8. I need two files ini (ANSI and UTF-8).
ANSI version ini I use in my Windows program.
UTF-8 version ini user use in my Android program. User manual copied this ini UTF-8 file in Android device.

Then set the bFailIfExist parameter of CopyFile() to FALSE.


Many thanks for the tip!
Lena
BCBJ Master
BCBJ Master
 
Posts: 520
Joined: Sun Feb 06, 2011 1:28 pm

Re: Save file on Desktop

Postby rlebeau » Fri Nov 17, 2017 10:47 am

Lena wrote:In Windows versions I work with a file ini encoded ANSI. After closing my Windows program, I want to get a duplicate of this file but in the encoding UTF-8. I need two files ini (ANSI and UTF-8).


Then you need to open the first file, read it using ANSI and convert it to Unicode, and then save the Unicode to the second file using UTF-8. You can do that easily with TMemIniFile, eg:

Code: Select all
TMemIniFile *ini = new TMemIniFile(L"c:\\path to\\ansi.ini", TEncoding::ANSI);
ini->Rename(L"c:\\path to\\utf8.ini", false);
ini->Encoding = TEncoding::UTF8;
ini->UpdateFile();
delete ini;


But why are you bothering with ANSI at all? You can (and should) use UTF-8 ini files exclusively, even on Windows.
Remy Lebeau (TeamB)
Lebeau Software
User avatar
rlebeau
BCBJ Author
BCBJ Author
 
Posts: 1450
Joined: Wed Jun 01, 2005 3:21 am
Location: California, USA

Re: Save file on Desktop

Postby Lena » Sat Nov 18, 2017 6:20 am

But why are you bothering with ANSI at all? You can (and should) use UTF-8 ini files exclusively, even on Windows.


Hi.
See my picture.
Attachments
432.jpg
432.jpg (160.4 KiB) Viewed 149 times
Lena
BCBJ Master
BCBJ Master
 
Posts: 520
Joined: Sun Feb 06, 2011 1:28 pm

Re: Save file on Desktop

Postby Lena » Sat Nov 18, 2017 6:55 am

I use now your code:
Code: Select all
void __fastcall TForm1::FormClose(TObject *Sender, TCloseAction &Action)
{
 int i = 0;
 String path = (ExtractFilePath(ParamStr(0)));
 path = path + L"dibocca.ini";
 if(FileExists(path))
    {
     //save to DESKTOP
      String DesktopFolder = GetSpecialFolderPath(CSIDL_DESKTOPDIRECTORY);
      if (!DesktopFolder.IsEmpty())
      {
         String MyFilesPath = DesktopFolder + _D("Menu") + PathDelim;
         if (ForceDirectories(MyFilesPath))
         {
            String DefSetupPath = ExtractFilePath(ParamStr(0)) + _D("dibocca.ini");
            if (FileExists(DefSetupPath))
            {
               String NewSetupPath = MyFilesPath + _D("dibocca.ini");
               ::CopyFile(DefSetupPath.c_str(), NewSetupPath.c_str(), false);
               i++;

                    std::unique_ptr<TMemIniFile> utf8(new TMemIniFile(NewSetupPath, TEncoding::ANSI));
               utf8->Rename(NewSetupPath, false);
               utf8->Encoding = TEncoding::UTF8;
               utf8->UpdateFile();
               //delete ini;
            }
         }
      }

    }
   else
      {
       ShowMessage(L"No found file dibocca.ini");
      }
//***
//chek i
if(i > 0)
//***
Lena
BCBJ Master
BCBJ Master
 
Posts: 520
Joined: Sun Feb 06, 2011 1:28 pm

Re: Save file on Desktop

Postby rlebeau » Mon Nov 20, 2017 11:42 am

Lena wrote:See my picture.


That doesn't answer my question. If you are using a Unicode UI (which you should be), then you should be using an UTF-8 file, not an ANSI file. Unless you are dealing with legacy data (which you should convert to Unicode), there is no good reason to use ANSI anymore.
Remy Lebeau (TeamB)
Lebeau Software
User avatar
rlebeau
BCBJ Author
BCBJ Author
 
Posts: 1450
Joined: Wed Jun 01, 2005 3:21 am
Location: California, USA

Re: Save file on Desktop

Postby rlebeau » Mon Nov 20, 2017 11:52 am

Lena wrote:I use now your code


<sigh> You are mixing codes I gave you for different purposes.

If you insist on using ANSI for your source file, and want to convert it to UTF-8 when saving it, then do something more like this instead:

Code: Select all
void __fastcall TForm1::FormClose(TObject *Sender, TCloseAction &Action)
{
    String DefSetupPath = ExtractFilePath(ParamStr(0)) + _D("dibocca.ini");
    if (!FileExists(DefSetupPath))
    {
        ShowMessage(L"dibocca.ini not found");
        return;
    }

    String DesktopFolder = GetSpecialFolderPath(CSIDL_DESKTOPDIRECTORY);
    if (DesktopFolder.IsEmpty())
    {
        ShowMessage(L"Desktop folder not found");
        return;
    }

    String MyFilesPath = DesktopFolder + _D("Menu") + PathDelim;
    if (!ForceDirectories(MyFilesPath))
    {
        ShowMessage(L"Cannot create Menu folder on Desktop");
        return;
    }

    String NewSetupPath = MyFilesPath + _D("dibocca.ini");

    std::unique_ptr<TMemIniFile> ini(new TMemIniFile(DefSetupPath, TEncoding::ANSI));
    ini->Rename(NewSetupPath, false);
    ini->Encoding = TEncoding::UTF8;
    ini->UpdateFile();
}


But, if you switch your source file to UTF-8 (which you should), then you don't need to use the TMemIniFile anymore, just copy the file as-is:

Code: Select all
void __fastcall TForm1::FormClose(TObject *Sender, TCloseAction &Action)
{
    String DefSetupPath = ExtractFilePath(ParamStr(0)) + _D("dibocca.ini");
    if (!FileExists(DefSetupPath))
    {
        ShowMessage(L"dibocca.ini not found");
        return;
    }

    String DesktopFolder = GetSpecialFolderPath(CSIDL_DESKTOPDIRECTORY);
    if (DesktopFolder.IsEmpty())
    {
        ShowMessage(L"Desktop folder not found");
        return;
    }

    String MyFilesPath = DesktopFolder + _D("Menu") + PathDelim;
    if (!ForceDirectories(MyFilesPath))
    {
        ShowMessage(L"Cannot create Menu folder on Desktop");
        return;
    }

    String NewSetupPath = MyFilesPath + _D("dibocca.ini");

    if (!::CopyFile(DefSetupPath.c_str(), NewSetupPath.c_str(), FALSE))
    {
        ShowMessage(L"Cannot save dibocca.ini to Menu folder");
    }
}
Remy Lebeau (TeamB)
Lebeau Software
User avatar
rlebeau
BCBJ Author
BCBJ Author
 
Posts: 1450
Joined: Wed Jun 01, 2005 3:21 am
Location: California, USA

Re: Save file on Desktop

Postby Lena » Wed Nov 22, 2017 3:32 am

That doesn't answer my question. If you are using a Unicode UI (which you should be), then you should be using an UTF-8 file, not an ANSI file. Unless you are dealing with legacy data (which you should convert to Unicode), there is no good reason to use ANSI anymore.


Sorry, I do not fully understand.
I create VCL project in C++ Builder Berlin.
I create ini files in notepad and save in notepad UTF-8.
INI:
Code: Select all
[1]
name=Паста "Di Bocca"
price=210
text=
weight=400 г.
footer=(спагетти с креветками)
category=Пасты и ризотто
image=1.jpg
print=1
otdel=0

//***


Code: Select all
//This is the code snippet

     std::unique_ptr<TIniFile> FileINI(new TIniFile(path));
     std::unique_ptr<TStringList> AlliniSection(new TStringList());
     FileINI->ReadSections(AlliniSection.get());
String name;
     for (int i = 0; i < AlliniSection->Count; i++)
     {
//***
 name = FileINI->ReadString(AlliniSection->Strings[i], L"name", "");
      if(name != "")
      {
             String pos = AlliniSection->Strings[i];
       int i = StrToInt(pos);
       ListBox1->Items->AddObject(name, (TObject*)i);
//***


After that I do not see the Russian letters in ListBox1. Where is my mistake?
Lena
BCBJ Master
BCBJ Master
 
Posts: 520
Joined: Sun Feb 06, 2011 1:28 pm

Re: Save file on Desktop

Postby rlebeau » Wed Nov 22, 2017 2:10 pm

Lena wrote:Sorry, I do not fully understand.
I create VCL project in C++ Builder Berlin.


Then you are using a Unicode-based RTL and GUI. So you should be using Unicode files to avoid any possible data loss during ANSI<->Unicode conversions.

Lena wrote:I create ini files in notepad and save in notepad UTF-8.


Then you need to load it as UTF-8, especially since it contains non-ASCII characters in it. In particular, this line:

Code: Select all
std::unique_ptr<TIniFile> FileINI(new TIniFile(path));


Needs to be changed to this:

Code: Select all
std::unique_ptr<TMemIniFile> FileINI(new TMemIniFile(path, TEncoding::UTF8));


Lena wrote:After that I do not see the Russian letters in ListBox1.


On Windows, TIniFile wraps the Win32 PrivateProfile API. On most Windows versions (at least up to Windows 7 - I didn't test Windows 8+), the Unicode version of the PrivateProfile functions do not support UTF-8 files, only UTF-16 files. So ReadSections() returns an empty TStringList, and ReadString() returns the specified default string. If you save your INI file as UTF-16 instead of UTF-8, then TIniFile works correctly.

TMemIniFile does not have that limitation. It can load and save UTF-8 files just fine, as long as you use TEncoding::UTF8. And TIniFile is an alias for TMemIniFile on non-Windows platforms.
Remy Lebeau (TeamB)
Lebeau Software
User avatar
rlebeau
BCBJ Author
BCBJ Author
 
Posts: 1450
Joined: Wed Jun 01, 2005 3:21 am
Location: California, USA


Return to Technical

Who is online

Users browsing this forum: Bing [Bot], Google [Bot] and 6 guests

cron