2

UPDATED: after Cody Gray's reply

I want to find a way to save a file to a desktop. Since every user has different user name, I found following code will help me find the path to someone else’s desktop. But how can I save the following to desktop?

#include <iostream>
#include <windows.h>
#include <fstream>
#include <direct.h>
#include <shlobj.h>
using namespace std;
int main ()
{
    ofstream file;  

    TCHAR appData[MAX_PATH];
    if (SUCCEEDED(SHGetFolderPath(NULL,
                                  CSIDL_DESKTOPDIRECTORY | CSIDL_FLAG_CREATE,
                                  NULL,
                                  SHGFP_TYPE_CURRENT,
                                  appData)))

    wcout << appData << endl; //This will printout the desktop path correctly, but
    file.open(appData +"/.txt"); //how can I open the desktop path here??
    file<<"hello\n";
    file.close();
    return 0;
}

Microsoft Visual Studio 2010, Windows 7, C++ console

Justin k
  • 1,104
  • 5
  • 22
  • 33
  • 2
    please do not update your questions like that, the answers will become irrelevant to the question.Kindly frame a new question for what u are seeking for. – Shirish11 Feb 16 '12 at 09:07

2 Answers2

6

The problem is that you're compiling the application with UNICODE defined (as you well should be), meaning that C-style strings are not stored in char arrays (as they would be for ANSI strings), but rather wchar_t arrays.

That's why you can't convert from char* to LPWSTR (which is typedefed in the Windows headers as wchar_t*).

The solution is to change the type of your string buffer. You can either use wchar_t explicitly:

wchar_t appData[MAX_PATH];

or take advantage of the TCHAR macro that will automatically #define to the appropriate type, depending on whether you compile with UNICODE defined:

TCHAR appData[MAX_PATH];

That's not the only problem though. A couple of other things to note:

  1. You should strongly consider using the TRUE and FALSE symbols instead of the literals 0 and 1 when writing Win32 code. When the function's documentation indicates that it accepts values of type BOOL, take advantage of the symbols that are already defined for that type. It makes your code much clearer and easier to read, even if you can reasonably assume that these symbols will never change their definitions in the headers.

  2. CSIDL_LOCAL_APPDATA is not the correct constant to use if you want the desktop folder. That will return a folder that is associated with the current user and intended to be used by applications for storing data that should not roam with the user (it should be stored and available on the local machine only). All things considered, this is probably a better choice than the desktop anyway, as apps should really have a darn good reason before spilling junk out on a user's desktop.

    If you need the data to roam with the application, you should use CSIDL_APPDATA instead. I provide a brief run-down of what all these different folders are, what they mean, and when you should use them in my answer here.

    Do note, however, that the SHGetSpecialFolderPath function limits you to a particular subset of the special folders. Which brings me to...

  3. As of Windows 2000 (and I honestly don't think there's anyone out there still writing apps targeting versions of Windows prior to 2000), the SHGetSpecialFolderPath function is obsolete.

    The preferred replacement for those targeting Windows 2000 and XP is SHGetFolderPath, which you would use in a similar fashion:

    TCHAR appData[MAX_PATH];
    
    if (SUCCEEDED(SHGetFolderPath(NULL, 
                                  CSIDL_LOCAL_APPDATA | CSIDL_FLAG_CREATE, 
                                  NULL, 
                                  SHGFP_TYPE_CURRENT, 
                                  appData))) 
    {
        wcout << appData << endl;
    }
    

    And the newest member of the family is SHGetKnownFolderPath for new applications targeting only Windows Vista and later.

Community
  • 1
  • 1
Cody Gray - on strike
  • 239,200
  • 50
  • 490
  • 574
  • @Justin: Ah, the issue is probably that you need to use `wcout` to print the value, rather than `cout`, since you're working with wide strings... – Cody Gray - on strike Feb 16 '12 at 07:28
  • 1
    @Justink try with `CSIDL_DESKTOPDIRECTORY` to retrieve users desktop directory – Shirish11 Feb 16 '12 at 07:36
  • 1
    @Shirish11: That value is not supported with the `SHGetSpecialFolderPath` function. You will have to change to one of the other functions that I described. – Cody Gray - on strike Feb 16 '12 at 07:38
  • @Justin: Yes, you're printing the location of the pointer. It will be a number. I didn't realize what you were saying. You need to display the contents of the string array. You should have no problem doing this with `std::wcout << appData << L'\n';` – Cody Gray - on strike Feb 16 '12 at 07:40
  • @Justin: No, that won't work. You can't concatenate character arrays using the `+` operator. Are you new to C++ programming? I highly recommend that you pick up [a book that will help you](http://stackoverflow.com/questions/388242/the-definitive-c-book-guide-and-list). It can be very confusing to come in from the world of Java or C# or some other language. C++ *does* provide a string type (`std::string`), so you might want to consider using that, instead. The Windows API functions will still require raw C-style character arrays, but the `std::string` function lets you interoperate with those. – Cody Gray - on strike Feb 16 '12 at 18:34
  • I also don't know where you got the `file.open` method. In Win32, you can launch a file using the [`ShellExecute` function](http://msdn.microsoft.com/en-us/library/windows/desktop/bb762153.aspx) with the `open` action. You'll still need to make sure that the path is correct, though. And rather than raw string concatenation, even with the C++ string class, I would recommend that you use the [`PathAppend` function](http://msdn.microsoft.com/en-us/library/windows/desktop/bb773565.aspx) to make sure that everything is properly formatted. The linked MSDN documentation should have sample code. – Cody Gray - on strike Feb 16 '12 at 18:36
0
    Böyle Olması Gerekiyor

    TCHAR path[_MAX_PATH] = _T("");
    if (SUCCEEDED(SHGetFolderPath(NULL, 
                                  CSIDL_DESKTOP 
                                  0, 
                                  NULL, 
                                  path))) 
    strcat(path,"\\Test.txt");
    ofstream out;
    out.open(path);
  • Your answer could be improved with additional supporting information. Please [edit] to add further details, such as citations or documentation, so that others can confirm that your answer is correct. You can find more information on how to write good answers [in the help center](/help/how-to-ask). – Community Sep 20 '21 at 21:39