First of all, I would like to thank you guys for doing such an amazing job with win32 builds! I am currently trying to develop an app specifically for a newer windows device - the surface 3 pro… which is basically a tablet with full blown windows 8.1 on it. That being said, it has a built in camera like most tablets and I need to access it and even the file system to possibly upload a photo. Will that be possible soon or am I doing something wrong with the media library?
This is not something we currently support on Windows.
And to be honest, it’s at the bottom of our priority list.
If you’re willing, you could attempt to implement it yourself in C/C++ by creating your own Windows plugin. I’ve provided instruction on how to create a Windows plugin in the link below. Just note that this assumes you have experience developing in C++ and Visual Studio.
https://forums.coronalabs.com/topic/57623-support-for-nativenewtextfield/?p=298499
Ok, my first programming experience was C++ many years ago… and I’ve used Visual Studio to write apps with VB.net. So I will give it a try. Thanks!
Great! And starting off, I recommend that you try implementing a photo/image file selection API first before attempting camera support, which would be more challenging. For example, if you want the end-user to select a photo/image file, then the simplest solution is to display a standard “File Open” dialog via Microsoft’s GetOpenFileName() Win32 function. That’s a pretty easy function to work with and it allows you to get your feet wet with how to use Lua’s C APIs.
https://msdn.microsoft.com/en-us/library/windows/desktop/ms646927(v=vs.85).aspx
OK, I managed to get the file dialog box to open. Then I have a messageBox tell me what the file path is just fine. I need to get that value back to my app. I tried to lua_pushstring but only receive the first character from the path “C” and that is it. Any suggestions, help?
Here is my code:
static int fop\_getFile(lua\_State \*L) { OPENFILENAME ofn; // common dialog box structure char szFile[260]; // buffer for file name HANDLE hf; // file handle // Initialize OPENFILENAME // Display the Open dialog box. // open a file name ZeroMemory(&ofn, sizeof(ofn)); ofn.lStructSize = sizeof(ofn); ofn.hwndOwner = NULL; ofn.lpstrFile = szFile; ofn.lpstrFile[0] = '\0'; ofn.nMaxFile = sizeof(szFile); ofn.lpstrFilter = L"JPG\0\*.jpg\0PNG\0\*.png\0"; ofn.nFilterIndex = 1; ofn.lpstrFileTitle = NULL; ofn.nMaxFileTitle = 0; ofn.lpstrInitialDir = NULL; ofn.Flags = OFN\_PATHMUSTEXIST | OFN\_FILEMUSTEXIST; GetOpenFileName(&ofn); lua\_pushstring(L, ofn.lpstrFile); return 1; //MessageBox(NULL, ofn.lpstrFile, L"File Name", MB\_OK); }
I think its a UTF-16 Unicode issue. By default, your VC++ library project should be set up for Unicode. This means that your “ofn.lpstrFile” is a 2 byte “wchar_t” UTF-16 characters string. But the lua_pushstring() function only accepts single byte “char” UTF-8 strings. So, the solution is to convert the string from UTF-16 to UTF-8. The below functions will do this.
static wchar\_t\* CreateUtf16StringFrom(const char\* utf8String) { wchar\_t \*utf16String = NULL; int conversionLength; if (utf8String) { conversionLength = MultiByteToWideChar(CP\_UTF8, 0, utf8String, -1, NULL, 0); if (conversionLength \> 0) { utf16String = (wchar\_t\*)malloc((size\_t)conversionLength \* sizeof(wchar\_t)); MultiByteToWideChar(CP\_UTF8, 0, utf8String, -1, utf16String, conversionLength); } } return utf16String; } static void DestroyUtf16String(wchar\_t \*utf16String) { if (utf16String) { free(utf16String); } } static char\* CreateUtf8StringFrom(const wchar\_t\* utf16String) { char \*utf8String = NULL; int conversionLength; if (utf16String) { conversionLength = WideCharToMultiByte(CP\_UTF8, 0, utf16String, -1, NULL, 0, NULL, NULL); if (conversionLength \> 0) { utf8String = (char\*)malloc((size\_t)conversionLength \* sizeof(char)); WideCharToMultiByte(CP\_UTF8, 0, utf16String, -1, utf8String, conversionLength, NULL, NULL); } } return utf8String; } static void DestroyUtf8String(char \*utf8String) { if (utf8String) { free(utf8String); } }
And then you can use it in your function like this…
GetOpenFileName(&ofn); auto utf8String = CreateUtf8StringFrom(ofn.lpstrFile); if (utf8String) { lua\_pushstring(L, utf8String); DestroyUtf8String(utf8String); } else { lua\_pushnil(L); } return 1;
I hope this helps!
That did it! I knew I was a bit rusty on c, Thanks a bunch!
Great! Happy to help!
And I’ve spotted one more problem in your code. You are giving the “ofn.lpstrFile” field a char array when it should be a wchar_t array (ie: a 2 byte wide character array for UTF-16 strings). So the follow should change from this…
char szFile[260];
…to this…
wchar_t szFile[260];
And the following line of code needs to change from this…
ofs.nMaxFile = sizeof(szFile);
…to this…
ofs.nMaxFile = sizeof(szFile) / sizeof(wchar_t);
…because you are suppose to provide the number of characters in the string array and not the number of bytes.
The rest looks good.
ah yeah that makes sense! Good looking out! One more question and I think this issue will be done… How do I access this file path from my corona app now? lol Or could I send a base64 encoded string instead of the file path… What do you think?
Good question. Yeah, our display.newImage() API does not support loading files outside of Corona’s sandboxed directories such as Resources, Documents, Caches, or Temporary. As in display.newImage() won’t accept absolute paths. Only relative paths which are relative to one of these sandboxed directories. So, the only option at the moment is to copy the file to one of these sandboxed directories.
This can be done in Lua by using the file io APIs. Or in C by using the Win32 CopyFileW() function…
https://msdn.microsoft.com/en-us/library/windows/desktop/aa363851(v=vs.85).aspx
If you need to create a subdirectory, then you can do so in Lua via the lfs.mkdir() function…
https://docs.coronalabs.com/api/library/lfs/index.html
Or in C, you can use the Win32 SHCreateDirectoryExW(NULL, L"<MyDirectoryPath>", NULL) function…
https://msdn.microsoft.com/en-us/library/windows/desktop/bb762131(v=vs.85).aspx
Ok so I managed to get the path to the TemporaryFiles dir for the app. I think. Which is located in the AppData/Local/company name/app name/TemporaryFiles folder. But the copyfile funciton is not putting it there. Here is my poorly written c code
if (GetOpenFileName(&ofn) == TRUE) { TCHAR szPath[MAX\_PATH]; if (SUCCEEDED(SHGetFolderPath(NULL, CSIDL\_LOCAL\_APPDATA, NULL, 0, szPath))) { auto utf8String = CreateUtf8StringFrom(szPath); auto sourceFile = CreateUtf8StringFrom(ofn.lpstrFile); char\* appPath = strcat(utf8String, "\\Tartar Sauce Media, LLC\\TabletDemo2\\TemporaryFiles\\somefile.png"); CopyFile(sourceFile, appPath, FALSE); } }
I don’t receive any errors and no file is copied. Any ideas?
I decided to go with Lua’s io Api. It works and was easier to figure out! Yet, I still would like to know why C’s copyfile function would not work.
First, the strcat() function call you are doing is dangerous. It’s writing past the bounds of the utf8String array and will trash memory. This is because the CreateUtf8StringFrom() function creates a char array just long enough to hold all of the characters it needs, leaving no room for string concatenation. I’ll bet it’s turning your appPath into an invalid path because it’s not null terminated where you expect it to be.
It might be easier to return the absolute path to Lua and do the file copy from there. This is because you don’t have easy access to Corona’s sandboxed directory paths at the moment on the C/C++ side. Lua’s standard file io APIs can work with paths outside of Corona’s sandboxed directories. We provide example code on how to copy a file here…
https://docs.coronalabs.com/guide/data/readWriteFiles/index.html#copying-files-to-subfolders
And if you need to create a subdirectory, then you can use Lua’s lfs.mkdir() function as shown here…
https://docs.coronalabs.com/api/library/lfs/index.html#working-with-directories
Now, if you don’t want to do the above in Lua and handle it on the C/C++ side, then it’s going to be a bit more work, but it’s definitely possible. Your Lua code would have to pass in either a destination directory path to your C function or the base directory constant (ie: system.DocumentsDirectory, system.CachesDirectory, etc.). The following link shows you how our “pasteboard” plugin does it by passing in a Corona base directory constant. This is how we normally do it for “official” plugins that we would make publically available. The trick is that your C/C++ code will have to call the Lua system.pathForFile() function, which is what the link below will show you. Or you could keep it simple and do it on the Lua side like I mentioned above. It’s up to you.
Thanks for the info! I’m keeping it simple and going with lua io API!
This is not something we currently support on Windows.
And to be honest, it’s at the bottom of our priority list.
If you’re willing, you could attempt to implement it yourself in C/C++ by creating your own Windows plugin. I’ve provided instruction on how to create a Windows plugin in the link below. Just note that this assumes you have experience developing in C++ and Visual Studio.
https://forums.coronalabs.com/topic/57623-support-for-nativenewtextfield/?p=298499
Ok, my first programming experience was C++ many years ago… and I’ve used Visual Studio to write apps with VB.net. So I will give it a try. Thanks!
Great! And starting off, I recommend that you try implementing a photo/image file selection API first before attempting camera support, which would be more challenging. For example, if you want the end-user to select a photo/image file, then the simplest solution is to display a standard “File Open” dialog via Microsoft’s GetOpenFileName() Win32 function. That’s a pretty easy function to work with and it allows you to get your feet wet with how to use Lua’s C APIs.
https://msdn.microsoft.com/en-us/library/windows/desktop/ms646927(v=vs.85).aspx
OK, I managed to get the file dialog box to open. Then I have a messageBox tell me what the file path is just fine. I need to get that value back to my app. I tried to lua_pushstring but only receive the first character from the path “C” and that is it. Any suggestions, help?
Here is my code:
static int fop\_getFile(lua\_State \*L) { OPENFILENAME ofn; // common dialog box structure char szFile[260]; // buffer for file name HANDLE hf; // file handle // Initialize OPENFILENAME // Display the Open dialog box. // open a file name ZeroMemory(&ofn, sizeof(ofn)); ofn.lStructSize = sizeof(ofn); ofn.hwndOwner = NULL; ofn.lpstrFile = szFile; ofn.lpstrFile[0] = '\0'; ofn.nMaxFile = sizeof(szFile); ofn.lpstrFilter = L"JPG\0\*.jpg\0PNG\0\*.png\0"; ofn.nFilterIndex = 1; ofn.lpstrFileTitle = NULL; ofn.nMaxFileTitle = 0; ofn.lpstrInitialDir = NULL; ofn.Flags = OFN\_PATHMUSTEXIST | OFN\_FILEMUSTEXIST; GetOpenFileName(&ofn); lua\_pushstring(L, ofn.lpstrFile); return 1; //MessageBox(NULL, ofn.lpstrFile, L"File Name", MB\_OK); }
I think its a UTF-16 Unicode issue. By default, your VC++ library project should be set up for Unicode. This means that your “ofn.lpstrFile” is a 2 byte “wchar_t” UTF-16 characters string. But the lua_pushstring() function only accepts single byte “char” UTF-8 strings. So, the solution is to convert the string from UTF-16 to UTF-8. The below functions will do this.
static wchar\_t\* CreateUtf16StringFrom(const char\* utf8String) { wchar\_t \*utf16String = NULL; int conversionLength; if (utf8String) { conversionLength = MultiByteToWideChar(CP\_UTF8, 0, utf8String, -1, NULL, 0); if (conversionLength \> 0) { utf16String = (wchar\_t\*)malloc((size\_t)conversionLength \* sizeof(wchar\_t)); MultiByteToWideChar(CP\_UTF8, 0, utf8String, -1, utf16String, conversionLength); } } return utf16String; } static void DestroyUtf16String(wchar\_t \*utf16String) { if (utf16String) { free(utf16String); } } static char\* CreateUtf8StringFrom(const wchar\_t\* utf16String) { char \*utf8String = NULL; int conversionLength; if (utf16String) { conversionLength = WideCharToMultiByte(CP\_UTF8, 0, utf16String, -1, NULL, 0, NULL, NULL); if (conversionLength \> 0) { utf8String = (char\*)malloc((size\_t)conversionLength \* sizeof(char)); WideCharToMultiByte(CP\_UTF8, 0, utf16String, -1, utf8String, conversionLength, NULL, NULL); } } return utf8String; } static void DestroyUtf8String(char \*utf8String) { if (utf8String) { free(utf8String); } }
And then you can use it in your function like this…
GetOpenFileName(&ofn); auto utf8String = CreateUtf8StringFrom(ofn.lpstrFile); if (utf8String) { lua\_pushstring(L, utf8String); DestroyUtf8String(utf8String); } else { lua\_pushnil(L); } return 1;
I hope this helps!
That did it! I knew I was a bit rusty on c, Thanks a bunch!