Saturday, April 8, 2017

How to copy ROM zip file to the freshly wiped device

How to copy ROM zip file to the freshly wiped device


Consider the following code:

using System;
using System.Runtime.InteropServices;
using System.Collections.Generic;
using System.Text;

namespace SmartDeviceProject5
{
class Program
{
static void Main(string[] args)
{
Foo foo = new Foo();
try
{
SomeMethod(foo); // KABOOM! NotSupportedException
}
catch (Exception e)
{
}
try
{
AnotherMethod("hello"); // KABOOM! NotSupportedException
}
catch (Exception e)
{
}
}

[DllImport("SomeDLL")]
extern static void SomeMethod(Foo foo);

[DllImport("SomeDLL")]
extern static void AnotherMethod([MarshalAs(UnmanagedType.LPStr)] string someString);
}

public struct Foo
{
public string Bar;
public string Borked;
}

}

When attempting to run this program, it will throw an exception upon calling the SomeMethod PInvoke. Attempting to call the "AnotherMethod" function will fail just as well.
This happens because C# automatically marshals all strings in structures as LPTStr (which for some reason is LPStr in Windows Mobile). However, in methods, strings are marshalled as LPWStr. I dont get it. Anyways, .Net Compact Framework does not support marshalling as LPStr in structures or method calls for whatever reason, even though the code to make it happen is all there (as I will show you).
Changing the code by adding the MarshalAs attribute to explicitly Marshal them as LPWStr would make it work:



 [DllImport("SomeDLL")]
extern static void AnotherMethod([MarshalAs(UnmanagedType.LPWStr)] string someString);
}

public struct Foo
{
[MarshalAs(UnmanagedType.LPWStr)]
public string Bar;
[MarshalAs(UnmanagedType.LPWStr)]
public string Borked;
}


Although LPWStr (Unicode) is more or less the standard now, but if you really really want/need to Marshal it as a LPStr, tough cookies, you get a NotSupportedException.
Generally, if you need to marshal a structure with strings, its highly unlikely that you are going to need to mix LPWStr and LPStr in the same structure. To that end, I wrote a custom MarshalAnsi class that marshals a structure and all its contents; any strings found are marshalled as LPStr:


using System; using System.Collections.Generic; using System.Text; using System.Runtime.InteropServices; using System.Reflection; namespace System.Runtime.InteropServices { /// <summary> /// .NET Compact framework does not support marshalling strings to ascii. /// Need to do it manually. /// </summary> static class MarshalAnsi { /// <summary> /// This Dictionary maintains all the strings allocated by an IntPtr that a structure /// was Marshalled to. /// </summary> static Dictionary<IntPtr, List<IntPtr>> myStringsForObject = new Dictionary<IntPtr,List<IntPtr>>(); public static IntPtr StructureToPtr(object structure) { Type type = structure.GetType(); var fieldInfos = type.GetFields(BindingFlags.Instance | BindingFlags.GetField | BindingFlags.Public | BindingFlags.NonPublic); // determine the total size of the structure. Need to special case strings and bools int totalSize = 0; foreach (FieldInfo field in fieldInfos) { totalSize += field.FieldType == typeof(string) ? Marshal.SizeOf(typeof(IntPtr)) : field.FieldType == typeof(bool) ? Marshal.SizeOf(typeof(int)) : Marshal.SizeOf(field.FieldType); } // allocate the pointer, and create its list of allocated strings IntPtr ret = Marshal.AllocHGlobal(totalSize); List<IntPtr> strings = new List<IntPtr>(); myStringsForObject.Add(ret, strings); // structure pointer offset, which is incremented as we write to the structure int ofs = 0; foreach (FieldInfo field in fieldInfos) { object toWrite = null; if (field.FieldType == typeof(string)) { // allocate memory for the string if need be, and add it to the // pointers string allocation list string str = field.GetValue(structure) as string; IntPtr strPtr; if (str == null) strPtr = IntPtr.Zero; else { byte[] bytes = Encoding.ASCII.GetBytes(str); strPtr = Marshal.AllocHGlobal(bytes.Length + 2); strings.Add(strPtr); Marshal.Copy(bytes, 0, strPtr, bytes.Length); Marshal.WriteInt16(strPtr, bytes.Length, 0); } toWrite = strPtr; } else if (field.FieldType == typeof(bool)) { // need to write this as an int, not a bool. // BOOL in C/C++ is really an int, which is of size 4. toWrite = (bool)field.GetValue(structure) ? 1 : 0; } else { // just do the default behavior toWrite = field.GetValue(structure); } Marshal.StructureToPtr(toWrite, (IntPtr)((int)ret + ofs), false); // increment the structure pointer offset ofs += Marshal.SizeOf(toWrite); } return ret; } /// <summary> /// Destroy the memory allocated by a structure, and all strings as well. /// </summary> /// <param name="ptr"></param> public static void DestroyStructure(IntPtr ptr) { List<IntPtr> strings = myStringsForObject[ptr]; myStringsForObject.Remove(ptr); foreach (IntPtr strPtr in strings) { Marshal.FreeHGlobal(strPtr); } Marshal.FreeHGlobal(ptr); } } } 

Usage:
Simply pass a structure into this class and it will return a pointer with the marshalled data. All strings are marshalled as Ansi strings.
Remember to call MarshalAnsi.DestroyStructure with the pointer returned from MarshalAnsi.StructureToPtr when it is no longer in use.


Go to link for download