File and folder handling with %APPDATA%

Posted By: Turrican

File and folder handling with %APPDATA% - 10/13/17 17:26

Hey guys,

for a number of reasons I want to put my game's savegame data into the user-specific %APPDATA% folder. I would like to use file_open_... commands for my savegames, rather than using game_save. Now I have several problems with that:

1. Unicode User Names
As Emre kindly explained here, it is possible to retrieve the complete %APPDATA% path using a shell32-function. However, as this example uses "SHGetFolderPathA", it only works as long as the Windows username does not contain any unicode characters. Using non-unicode usernames is rather common for territories like east-asia, russia and so on. There is a function "SHGetFolderPathW", which is supposed to return a unicode string, but I never managed to retrieve more than a single letter "C" from it.

Have a look at that here:
Code:
HRESULT WINAPI SHGetFolderPath(HWND hwndOwner, int nFolder,HANDLE hToken,DWORD dwFlags,char* pszPath);
#define PRAGMA_API SHGetFolderPath;Shell32.dll!SHGetFolderPathW
char temp_getfolder[260];
STRING* str_sv_dir="";

const int APPDATA = 0x001A;

function get_appdata_folder_startup()
{
	SHGetFolderPath(NULL,APPDATA,0,NULL,temp_getfolder);
	str_sv_dir=str_createw(temp_getfolder);
	error(str_sv_dir); // opens a dialog box containing the letter "C"
}



BTW, I also tried using "SHGetSpecialFolderPath" from windows.h with similar results.
My question is: How can I retrieve the correct appdata path as a unicode string? And once I have this - do Lite-C's "file_open..." commands actually work with such a string?

2. Creating a possibly non-existing folder
Now, at every start of my game, I want to make sure that the actual savegame folder and file exist to prevent Invalid Pointer errors. Therefore I refer to the manual, which states:

  • file_open_append (STRING* name);
    Opens a file for appending additional content at the end. If the file does not exist, it is created.
    The functions return a file handle - that is a unique number to identify the opened file. The file handle is used by other functions to access that file.

I expected that calling this function on a non-existent file in an also non-existent folder path would simply create both the file and the folder. But instead, the engine can't find the given file, throws
an "Invalid Pointer" error message, and the script execution stops.

I then tried "game_save". This command actually creates the required folder, which is good - except that I don't want to use Acknex' .SAV files at all, so this is no option for me.

I also tried using "CreateDirectory(char* lpPathName,long lpSecurityAttributes);" from windows.h with the String I got from "SHGetFolderPath" (see above), combined with "mygametitle". It did not work at all.

Is there any other method to create a folder from inside the engine?
Posted By: Superku

Re: File and folder handling with %APPDATA% - 10/13/17 18:38

I only had a quick look at it but you usually want to use "short" arrays for Unicode, not "chars" ( in view of "temp_getfolder").
Posted By: Turrican

Re: File and folder handling with %APPDATA% - 10/14/17 09:14

Originally Posted By: Superku
I only had a quick look at it but you usually want to use "short" arrays for Unicode, not "chars" ( in view of "temp_getfolder").


Thanks, that makes sense. I gave it a shot, still got only "C" as result. I guess this is because of the string type that SHGetFolderPathW expects ("LPWSTR"). Either that, or I made some other mistake on the way.

Anyway - sadly, it's pointless to test this any further, because I just checked if the engine's "file_open_..." commands accept unicode strings as file paths. And of course, the result is: No, they don't. So working on this stuff in lite-c makes no sense at all - or am I missing something?

I really can't understand why Windows Special Folders were not implemented into the engine in a hard-coded way at all. It's a standard since Vista - that was 10 years ago.

Maybe someone still has an idea how to get this working...? This really is an important part for my project.
Posted By: txesmi

Re: File and folder handling with %APPDATA% - 10/14/17 10:55

Hi,
unicode strings are half-implemented in the engine. There are many functions that don't work with unicode strings. error funtion is one of those, I guess. I remember str_len, str_clip and str_trunc failing too. There might be more...

TEXT and PANEL digits shows unicode strings correctly.
Click to reveal..

Code:
#include <acknex.h>
#include <windows.h>

HRESULT WINAPI SHGetFolderPath(HWND hwndOwner, int nFolder,HANDLE hToken,DWORD dwFlags,char* pszPath);
#define PRAGMA_API SHGetFolderPath;Shell32.dll!SHGetFolderPathW

const int APPDATA = 0x001A;

FONT *fnt = "Arial#24";
TEXT *txtW =
{
	font = fnt;
	pos_x = 10;
	pos_y = 10;
	strings = 1;
	flags = SHOW;
}

function get_appdata_folder_startup()
{
	short temp_getfolder[260];
	SHGetFolderPath ( NULL, APPDATA, 0, NULL, temp_getfolder );
	*txtW->pstring = str_createw ( temp_getfolder );
}

void main ( )
{
	while ( !key_esc )
		wait ( 1 );
	
	sys_exit ( NULL );
}


Posted By: Kartoffel

Re: File and folder handling with %APPDATA% - 10/14/17 14:13

The string you retrieved is correct, however if you use it with a function that expects non-unicode strings like error() they don't work correctly. In this case the first character ('C') of your string is not one byte large as the engine expects because it's unicode (still, it happens to have the same ascii value in the first byte). When the engine continues to read the string it expects the second byte to be the next character. However, this byte is still part of the first unicode character and since it has the value 0x00 in this case, the engine interperts it as the end of string character and cuts off the rest.

Like txesmi said, TEXT and PANEL can display the string correctly. draw_text() works aswell (I believe it works the same as TEXT/PANEL drawing)

Regarding the CreateDirectory() function: when using the windows API you have to be pretty careful with unicode/non-unicode strings. If SHGetFolderPath returns a wstring (which it seems it does) you'd have to use CreateDirectoryW.
Posted By: Turrican

Re: File and folder handling with %APPDATA% - 10/17/17 11:58

Originally Posted By: txesmi
unicode strings are half-implemented in the engine. There are many functions that don't work with unicode strings. error funtion is one of those, I guess. I remember str_len, str_clip and str_trunc failing too. There might be more...


Yes, I found out about that some time ago, but there were always methods to work around these problems. Anyway, as a matter of fact, it seems that file_open_write or _read belong to those commands that don't support Unicode, and there seems to be no workaround for that.

Originally Posted By: Kartoffel
The string you retrieved is correct, however if you use it with a function that expects non-unicode strings like error() they don't work correctly. In this case the first character ('C') of your string is not one byte large as the engine expects because it's unicode (still, it happens to have the same ascii value in the first byte). (...)

Like txesmi said, TEXT and PANEL can display the string correctly. draw_text() works aswell (I believe it works the same as TEXT/PANEL drawing)


Sorry, yes, you were right. The retrieved string was indeed correct, and it's also displayed correctly when using draw_text. However, when I now use this string to create and write into a file, guess what happens.

Code:
HRESULT WINAPI SHGetFolderPath(HWND hwndOwner, int nFolder,HANDLE hToken,DWORD dwFlags,char* pszPath);
#define PRAGMA_API SHGetFolderPath;Shell32.dll!SHGetFolderPathW
char temp_getfolder[260];
STRING* str_sv_dir="";

const int APPDATA = 0x001A;

function get_appdata_folder_startup()
{
	SHGetFolderPath(NULL,APPDATA,0,NULL,temp_getfolder);
	STRING* wstr = str_createw(temp_getfolder);

	str_cat(wstr,"\\MyGame\\test.txt");
	var filehandle = file_open_write(wstr);
	file_str_write(filehandle,"Look guys, we're writing into the file!");
	file_close(filehandle);
	// --> ...and now look for a file named 'C' in your project directory. :(

	while(1)
	{
		draw_text(wstr,800,560,vector(100,100,255));	// yes, that's actually the correct path
		
		wait(1);
	}
}



I guess that's the proof that file_open_write does not know Unicode. What shall I do now? Is it really the only feasible option to create a DLL-plugin that works around this problem, with custom file and folder handling? It sure looks that way. Please tell me there's an easier way.
Posted By: Turrican

Re: File and folder handling with %APPDATA% - 10/26/17 15:52

Just a short update, in case anyone is interested: I wrote myself a plugin to handle saving to/reading from %APPDATA%, which has been far more complicated than expected. But at least it works. Case closed, I guess.
Posted By: jumpman

Re: File and folder handling with %APPDATA% - 10/26/17 19:23

congrats my dude, sorry you couldnt really find a workaround within lite-c. Cant wait till your game is finished!
Posted By: Turrican

Re: File and folder handling with %APPDATA% - 10/27/17 10:17

Thanks! laugh
I'll keep you all updated.
© 2024 lite-C Forums