We have an unmanaged memory C++ dll that generates video data. The user interface is in UWP VB. I need to write the video data to the disk. The user gives the location to write from a file picker and this path and file name is passed to the dll. Using CreateFile and WriteFile the data will be written to disk.
This is the VB code
<DllImport("mycplus.dll", CallingConvention:=CallingConvention.StdCall)>
Public Function MainFrozen(ByVal EvF() As UInteger) As UInteger
End Function
Private Async Sub btnSaveAs_Click(sender As Object, e As RoutedEventArgs) Handles btnSaveAs.Click
Dim savePicker = New Windows.Storage.Pickers.FileSavePicker()
savePicker.SuggestedStartLocation = Windows.Storage.Pickers.PickerLocationId.DocumentsLibrary
savePicker.FileTypeChoices.Add("Video Files", New List(Of String)() From {".bin"})
savePicker.SuggestedFileName = gVideoFileName
Dim file As Windows.Storage.StorageFile = Await savePicker.PickSaveFileAsync()
If file IsNot Nothing Then
Dim fileName As String = file.Path
Dim d(0 To 15) As UInt32
d(0) = VIDEO_FILE_WRITE
d(1) = System.Runtime.InteropServices.Marshal.StringToHGlobalAnsi(fileName)
d(2) = System.Runtime.InteropServices.Marshal.StringToHGlobalAnsi(gAuthorName)
d(3) = gReserved
d(8) = MainFrozen(d)
Else
'txtDeubg.Text = "Operation cancelled."
End If
End Sub
And the following is the C++ code
extern "C" __declspec (dllexport) ULONG __stdcall MainFrozen(PULONG ptrEv)
{
ULONG eve = ptrEv[0];
switch (eve)
{
case VIDEO_FILE_WRITE:
SaveScanVideosToFile((LPCSTR)ptrEv[1], (LPCSTR)ptrEv[2], ptrEv[3]);
break;
}
return 0;
}
ULONG SaveScanVideosToFile(LPCSTR lpFileName,
LPCSTR lpAuthorName,
ULONG reserved)
{
HANDLE hFile;
ULONG bytesWritten;
ULONG n;
hFile = CreateFile(lpFileName, GENERIC_WRITE, 0, NULL,
CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
for (n=0; n<gScanVideoCnt; n++)
{
WriteFile(hFile, ScanVideos[n].pImg->Bcine.pCineMem, SCAN_VIDEO_MEM_SIZ, &bytesWritten, NULL);
WriteFile(hFile, ScanVideos[n].pImg, sizeof(IMG_TYPE), &bytesWritten, NULL);
}
CloseHandle(hFile);
return 0;
}
The problem is I am unable to write to any location other than: Windows.Storage.ApplicationData.Current.LocalFolder I.e C:\Users\ravi\AppData\Local\Packages\2d6e339b-614b-4161-8c7d-3570f07fc01f_2ygbv2t9jdb9y\LocalState\
At other locations, CreateFile fails with access denied. However using the .net file functions I am able to write other test files to almost all locations in my PC in the latest creators edition of win10, which is most welcome and heartening.
The question is: what security attributes should be set so that CreateFile will succeed and write to all location like the native .net file functions do?
There could be workarounds like marshal the entire data to managed memory or writing the file to the ApplicationData.Current.LocalFolder and then moving it using vb.net calls. But nothing like making CreateFile succeed.
PS: Our app is a side loaded one for enterprise use only and we do not mind if it fails windows stores test. (our customers are trusting us from “windows NT” days :-)
Help from Microsoft forum got this working.click here for the full thread
Basically Cast the file object to IStorageItemHandleAccess and call Create to obtain a file HANDLE. Then use WriteFile and Close in unmanaged code.
Here is the code:
<ComImport>
<Guid("5CA296B2-2C25-4D22-B785-B885C8201E6A")>
<InterfaceType(ComInterfaceType.InterfaceIsIUnknown)>
Friend Interface IStorageItemHandleAccess
Function Create(ao As Int32, so As Int32, o As Int32, oploc As Int32,
ByRef ptrHandle As IntPtr) As IntPtr
End Interface
' just 2 lines of extra code in your function to get the HANDLE which works magic!
Dim storageHandleIface = DirectCast(file, IStorageItemHandleAccess)
Dim myfileHandle As IntPtr
Dim res = storageHandleIface.Create(&H120116, 2, 0, 0, myfileHandle) ' WindowsStorageCom.h