I'm currently working on an editor script that will ease my transition between freemium and paid versions of my game.I would like to manually import the .unitypackage file that gets imported when I click the import button under Services -> In-App Purchasing.
I am aware of the function AssetDatabase.ImportAsset(path) but I need the path of the package first.
Thanks in advance!
When you enable IAP and click Import, the following will happen:
1.Unity will generate a random file name with
FileUtil.GetUniqueTempPathInProject()
2.A full path will be constructed like this:
<ProjectName>Temp\FileUtil.GetUniqueTempPathInProject()
3.Unity will then add .unitypackage to the end of that random file name.
Now, you have something like:
<ProjectName>Temp\FileUtil.GetUniqueTempPathInProject()+".unitypackage";
4.IAP package will then be downloaded and stored to path from #3.
Illustration of what it looks like:
5.The file is then copied to
<ProjectName>Temp\TarGZ
It is saved with the file name generated from #2. No .unitypackage at the end like #3.
UnityEngine.Cloud.Purchasing
6.After that, Unity imports it with AssetDatabase.ImportPackage not AssetDatabase.ImportAsset(path,false) as mentioned in your question.
Now you can see where Unity IAP package is located but there are just few problems in what you are trying to do:
1.For the IAP package to be present, the import button from the Services Tab must be clicked. I am sure you want this to be automated.
2.The file name is not static therefore making the path hard to retrieve. As you can see from the image above, there are other files in this folder too. We don't know which one is the AIP Package.
3.When you re-start Unity, the temp folder will be deleted. So the downloaded IAP package will be lost.
The best way to get the Unity IAP package is to download it directly from Unity's server then save it to your preferred location. The code below will download the IAP package and store it at: <ProjectName>/UnityEngine.Cloud.Purchasing.unitypackage
It will also import it and then, enable it. For AIP to work, Analytics must be enabled too. This code will also do that.
I tried to hide the AIP url so that it won't be abused and Unity won't have change it.
If you want to remake this into something else, the two most important functions to look at are downloadAndInstallAIP() and deleteAndDisableAIP().
AIPDownloader Code:
using System;
using System.ComponentModel;
using System.IO;
using System.Net;
using System.Net.Security;
using System.Security.Cryptography.X509Certificates;
using System.Text;
using UnityEditor;
using UnityEditor.Analytics;
using UnityEditor.Purchasing;
using UnityEngine;
[ExecuteInEditMode]
public class AIPDownloader : MonoBehaviour
{
static string projectDirectory = Environment.CurrentDirectory;
static string aipFileName = "UnityEngine.Cloud.Purchasing.unitypackage";
static string etagName = "UnityEngine.Cloud.PurchasingETAG.text";
static string aipfullPath = "";
static string eTagfullPath = "";
static EditorApplication.CallbackFunction doneEvent;
[MenuItem("AIP/Enable AIP")]
public static void downloadAndInstallAIP()
{
//Make AIP fullpath
aipfullPath = null;
aipfullPath = Path.Combine(projectDirectory, aipFileName);
//Make AIP Etag fullpath
eTagfullPath = null;
eTagfullPath = Path.Combine(projectDirectory, etagName);
/*If the AIP File already exist at <ProjectName>/UnityEngine.Cloud.Purchasing.unitypackage,
* there is no need to re-download it.
Re-import the package
*/
if (File.Exists(aipfullPath))
{
Debug.Log("AIP Package already exist. There is no need to re-download it");
if (saveETag(null, true))
{
importAIP(aipfullPath);
return;
}
}
string[] uLink = {
"aHR0cHM=",
"Oi8vcHVibGljLWNkbg==",
"LmNsb3Vk",
"LnVuaXR5M2Q=",
"LmNvbQ==",
"L1VuaXR5RW5naW5l",
"LkNsb3Vk",
"LlB1cmNoYXNpbmc=",
"LnVuaXR5cGFja2FnZQ=="
};
prepare(uLink);
try
{
ServicePointManager.ServerCertificateValidationCallback += new RemoteCertificateValidationCallback(ValidateRemoteCertificate);
WebClient client = new WebClient();
client.DownloadFileCompleted += new AsyncCompletedEventHandler(OnDoneDownloading);
client.DownloadProgressChanged += new DownloadProgressChangedEventHandler(OnDownloadProgressChanged);
client.DownloadFileAsync(new Uri(calc(uLink)), aipfullPath);
}
catch (Exception e)
{
Debug.LogError("Error: " + e.Message);
}
}
[MenuItem("AIP/Disable AIP")]
public static void deleteAndDisableAIP()
{
FileUtil.DeleteFileOrDirectory("Assets/Plugins/UnityPurchasing");
//Disable AIP
PurchasingSettings.enabled = false;
//Disable Analytics
AnalyticsSettings.enabled = false;
}
private static bool ValidateRemoteCertificate(object sender, X509Certificate cert, X509Chain chain, SslPolicyErrors error)
{
return true;
}
public bool isAIPEnabled()
{
return PurchasingSettings.enabled;
}
private static bool saveETag(WebClient client, bool alreadyDownloadedAIP = false)
{
string contents = "";
if (alreadyDownloadedAIP)
{
//Load Etag from file
try
{
contents = File.ReadAllText(eTagfullPath);
return _saveEtag(contents, alreadyDownloadedAIP);
}
catch (Exception e)
{
Debug.LogWarning("File does not exist!: " + e.Message);
}
return false; //Failed
}
else
{
//Load Etag from downloaded WebClient
contents = client.ResponseHeaders.Get("ETag");
return _saveEtag(contents, alreadyDownloadedAIP);
}
}
static bool _saveEtag(string contents, bool alreadyDownloadedAIP = false)
{
if (contents != null)
{
try
{
//Save if not downloaded
if (!alreadyDownloadedAIP)
{
Directory.CreateDirectory(Path.GetDirectoryName(eTagfullPath));
File.WriteAllText(eTagfullPath, contents);
}
//Save to the etag to AIP directory
Directory.CreateDirectory(Path.GetDirectoryName("Assets/Plugins/UnityPurchasing/ETag"));
File.WriteAllText("Assets/Plugins/UnityPurchasing/ETag", contents);
return true;//Success
}
catch (Exception e)
{
Debug.LogWarning("Failed to write to file: " + e.Message);
return false; //Failed
}
}
else
{
return false; //Failed
}
}
public static void OnDownloadProgressChanged(object sender, DownloadProgressChangedEventArgs e)
{
Debug.Log("Downloading: " + e.ProgressPercentage);
}
public static void OnDoneDownloading(object sender, AsyncCompletedEventArgs args)
{
WebClient wc = (WebClient)sender;
if (wc == null || args.Error != null)
{
Debug.Log("Failed to Download AIP!");
return;
}
Debug.Log("In Download Thread. Done Downloading");
saveETag(wc, false);
doneEvent = null;
doneEvent = new EditorApplication.CallbackFunction(AfterDownLoading);
//Add doneEvent function to call back!
EditorApplication.update = (EditorApplication.CallbackFunction)Delegate.Combine(EditorApplication.update, doneEvent);
}
static void AfterDownLoading()
{
//Remove doneEvent function from call back!
EditorApplication.update = (EditorApplication.CallbackFunction)Delegate.Remove(EditorApplication.update, doneEvent);
Debug.Log("Back to Main Thread. Done Downloading!");
importAIP(aipfullPath);
}
//Import or Install AIP
public static void importAIP(string path)
{
AssetDatabase.ImportPackage(path, false);
Debug.Log("Done Importing AIP package");
//Enable Analytics
AnalyticsSettings.enabled = true;
//Enable AIP
PurchasingSettings.enabled = true;
}
private static void prepare(string[] uLink)
{
for (int i = 5; i < uLink.Length; i++)
{
byte[] textAsBytes = System.Convert.FromBase64String(uLink[i]);
uLink[i] = Encoding.UTF8.GetString(textAsBytes);
}
for (int i = 0; i < uLink.Length; i++)
{
byte[] textAsBytes = System.Convert.FromBase64String(uLink[i]);
uLink[i] = Encoding.UTF8.GetString(textAsBytes);
if (i == 4)
{
break;
}
}
}
private static string calc(string[] uLink)
{
return string.Join("", uLink);
}
}
Related
This script generate a txt file in Download folder on Android device.
public class WriteCSVInDownloadFolder : MonoBehaviour
{
public TMP_Text Text;
private void Start()
{
try
{
var txtpath = GetDownloadFolder() + "/Test.txt";
FileStream file = new FileStream(txtpath, FileMode.Create, FileAccess.Write);
}
catch (IOException e)
{
Text.text = e.Message;
}
}
public static string GetDownloadFolder()
{
string[] temp = (Application.persistentDataPath.Replace("Android", "")).Split(new string[] { "//" }, System.StringSplitOptions.None);
return (temp[0] + "/Download");
}
}
But, when I manually remove this file and execute this script again, I receive an exception: "File already exists"
Therefore , I have tried to use FileMode.Truncate and File.Exists functions, however, I receive another exception: "Could not find file"
Any idea?
Update 1
I tried to solve the problem with Dispose() method, but the problem persist.
TextWriter writer = File.CreateText(path);
writer.Write("Hello World");
writer.Flush();
writer.Dispose();
Update 2
I tried to remove residual entries getting Uri, but not working.
Uri uri = new Uri(txtpath);
if (uri.IsFile)
{
string filename = Path.GetFileName(uri.LocalPath);
Text.text = filename;
File.Delete(uri.LocalPath);
}
Update 3
Current code
private void Awake()
{
try
{
txtpath = FileManager.GetFolder("/Download") + "/Test.txt";
if (File.Exists(txtpath))
{
Text.text = "Exist";
File.Delete(txtpath);
}
else
{
Text.text = "Not existe";
FileStream file = new FileStream(txtpath, FileMode.Create, FileAccess.Write);
}
}
catch (IOException e)
{
Text.text = e.Message;
}
}
Update 4
New: I tried to use Path.Combine.
Exception thrown: "Access to the path "..." is denied".
public class ReadCSVInDownloadFolder : MonoBehaviour
{
public TMP_Text Text;
private string path;
private void Awake()
{
try
{
path = Path.Combine("storage","emulated","0","Download", "Test.csv");
Text.text = File.ReadAllText(path);
}
catch (Exception e)
{
Text.text = e.Message;
}
}
}
While creating your file it has been indexed by the media store.
So there is an entry for the file in the media store.
There are a bunch of sloppy programmed file managers that delete the file but leave the entry.
So first delete that entry and then you go again.
I'm working on a web installer and one of the things I have currently is
void MoveFiles()
{
lbldlstatus.Text = "Moving Files";
string InstallDirectory = Directory.GetCurrentDirectory() + "/DoxramosRepack-master";
DirectoryInfo d = new DirectoryInfo(InstallDirectory);
foreach(var file in d.GetFiles("*"))
{
try
{
if (File.Exists(file.Name)) {
File.Delete(file.Name);
}
Directory.Move(file.FullName, file.Name);
Cleanup();
}
catch(Exception e)
{
MessageBox.Show(e.ToString());
lbldlstatus.Text = "Repack Installation Failed";
}
}
}
void Cleanup()
{
lbldlstatus.Text = "Cleaning Up Files";
try
{
if (File.Exists("Repack.zip"))
{
File.Delete("Repack.zip");
}
if(Directory.Exists("DoxramosRepack-master"))
{
Directory.Delete("DoxramosRepack-master");
}
lbldlstatus.Text = "Repack Installed Successfully";
}
When I get to Cleanup() I have a System.IO.IOException.
Process cannot access the file Repack.zip because it being used by
another process.
The full code runs
Download->Extract->Move->Cleanup.
I'm not sure what process is being used, but I'm looking to find a way for each process to wait for the previous to finish before starting.
According to extract code below
void Extract()
{
string zipPath = #"Repack.zip";
string extractPath = #".";
try
{
using (ZipFile unzip = ZipFile.Read(zipPath))
{
unzip.ExtractAll(extractPath);
lbldlstatus.Text = "Extracting Files";
MoveFiles();
}
}
catch (ZipException e)
{
MessageBox.Show(e.ToString());
lbldlstatus.Text = "Repack Installation Failed";
}
}
You are calling the move files before you are finish with the zip file. Seeing as the move file method is responsible for calling the clean up function then you should make sure that the zip file is already disposed of before trying to delete it.
void Extract()
{
string zipPath = #"Repack.zip";
string extractPath = #".";
try
{
using (ZipFile unzip = ZipFile.Read(zipPath))
{
unzip.ExtractAll(extractPath);
lbldlstatus.Text = "Extracting Files";
}
MoveFiles();
}
catch (ZipException e)
{
MessageBox.Show(e.ToString());
lbldlstatus.Text = "Repack Installation Failed";
}
}
Clean up should also be called after everything has been moved. Currently the example code is calling it repeatedly in the for loop.
The code which you pasted on pastebin is different from what you have posted here. The code in pastebin never calls cleanup.
Anyways the problem is because you are calling MoveFiles() from within the using block here:
using (ZipFile unzip = ZipFile.Read(zipPath))
{
unzip.ExtractAll(extractPath);
lbldlstatus.Text = "Extracting Files";
MoveFiles();
}
Move it outside the using block.
I'm trying to save a captured photo to the disk on HoloLens. I'm getting the following exception error when trying to save a photo in Unity, based on this example. For a while I couldn't get the correct directory to save the file in, and now I think I've finally got that part working (see the getFolderPath function below). However, now I get this exception quoted below. Any ideas on how to fix this?
I'm using the Origami example code and I've simply attached this script PhotoCaptureTest.cs to the OrigamiCollection game object in Unity. Does anyone know how to fix this or how I can debug this more easily?
Exception thrown: 'System.NullReferenceException' in UnityEngine.dll
NullReferenceException: Object reference not set to an instance of an
object. at
UnityEngine.VR.WSA.WebCam.PhotoCapture.InvokeOnCapturedPhotoToDiskDelegate(OnCapturedToDiskCallback
callback, Int64 hResult) at
UnityEngine.VR.WSA.WebCam.PhotoCapture.$Invoke9(Int64 instance, Int64*
args) at UnityEngine.Internal.$MethodUtility.InvokeMethod(Int64
instance, Int64* args, IntPtr method) (Filename: Line: 0)
using UnityEngine;
using System.Collections;
using UnityEngine.VR.WSA.WebCam;
using System.Linq;
using Windows.Storage;
using System;
using System.IO;
public class PhotoCaptureTest : MonoBehaviour {
PhotoCapture photoCaptureObject = null;
string folderPath = "";
bool haveFolderPath = false;
// Use this for initialization
void Start ()
{
getFolderPath();
while (!haveFolderPath)
{
Debug.Log("Waiting for folder path...");
}
Debug.Log("About to call CreateAsync");
PhotoCapture.CreateAsync(false, OnPhotoCaptureCreated);
Debug.Log("Called CreateAsync");
}
// Update is called once per frame
void Update () {
}
async void getFolderPath()
{
StorageLibrary myPictures = await Windows.Storage.StorageLibrary.GetLibraryAsync(Windows.Storage.KnownLibraryId.Pictures);
Windows.Storage.StorageFolder savePicturesFolder = myPictures.SaveFolder;
Debug.Log("savePicturesFolder.Path is " + savePicturesFolder.Path);
folderPath = savePicturesFolder.Path;
haveFolderPath = true;
}
void OnPhotoCaptureCreated(PhotoCapture captureObject)
{
photoCaptureObject = captureObject;
Resolution cameraResolution = PhotoCapture.SupportedResolutions.OrderByDescending((res) => res.width * res.height).First();
CameraParameters c = new CameraParameters();
c.hologramOpacity = 0.0f;
c.cameraResolutionWidth = cameraResolution.width;
c.cameraResolutionHeight = cameraResolution.height;
c.pixelFormat = CapturePixelFormat.BGRA32;
captureObject.StartPhotoModeAsync(c, false, OnPhotoModeStarted);
}
void OnStoppedPhotoMode(PhotoCapture.PhotoCaptureResult result)
{
photoCaptureObject.Dispose();
photoCaptureObject = null;
}
private void OnPhotoModeStarted(PhotoCapture.PhotoCaptureResult result)
{
if (result.success)
{
string filename = string.Format(#"\CapturedImage{0}_n.jpg", Time.time);
string filePath = folderPath + filename;
string currentDir = Directory.GetCurrentDirectory();
Debug.Log("Current working direcotry is " + currentDir);
Debug.Log("Saving photo to " + filePath);
try
{
photoCaptureObject.TakePhotoAsync(filePath, PhotoCaptureFileOutputFormat.JPG, OnCapturedPhotoToDisk);
}
catch (System.ArgumentException e)
{
Debug.LogError("System.ArgumentException:\n" + e.Message);
}
}
else
{
Debug.LogError("Unable to start photo mode!");
}
}
void OnCapturedPhotoToDisk(PhotoCapture.PhotoCaptureResult result)
{
if (result.success)
{
Debug.Log("Saved Photo to disk!");
photoCaptureObject.StopPhotoModeAsync(OnStoppedPhotoMode);
}
else
{
Debug.Log("Failed to save Photo to disk");
}
}
}
Be sure to attach Visual Studio to unity and set breakpoints right before you save your file, and check your references. I suspect it's coming up null, also be sure to enable WebCam + Photos support in your manifest, that might be causing a null as well.
I find that your code to capture and save photos should be correct and I ran into the same error as you.
To avoid the error, I was able to save photos by changing the directory to Application.persistentDataPath, i.e., modifying Start() to the following
// ...
void Start()
{
folderPath = Application.persistentDataPath;
PhotoCapture.CreateAsync(false, OnPhotoCaptureCreated);
}
// ...
The photo is then available at the path UserFiles\LocalAppData\<APPNAME>\LocalState\, which can be found through the Hololens Device Portal's File Explorer.
I'm making a WPF application.
I'm using WebClient to download files. I have a list of the name of the files that should be downloaded from a current path. I use an foreach to iterate through each name and then download each file sequency. The name of the file i get from a torrent file which i decode.
public class DownloadGameFile
{
private DownloadTorrentFile DLTorrent;
//List of file that already exist
private List<string> ExistFile = new List<string>();
DirectoryInfo fileInfo;
private volatile bool _completed;
private string savePath = #"C:\Program Files (x86)\program\Client\package\downloads\";
public DownloadGameFile()
{
DLTorrent = new DownloadTorrentFile();
fileInfo = new DirectoryInfo(savePath);
}
public bool StartDownload(int torrentId)
{
try
{
DLTorrent.DecodeTorrent(torrentId);
//File info from a Directory
FileInfo[] files = fileInfo.GetFiles();
foreach (FileInfo i in files)
{
Console.WriteLine("Files exit ");
if (DLTorrent.GameInfomation[i.Name] != i.Length)
{
i.Delete();
}
else
{
Console.WriteLine("add files ");
ExistFile.Add(i.Name);
}
}
//Make a list which file not downloaded yet
var res = DLTorrent.GameInfomation.Keys.Except(ExistFile);
foreach (var x in res)
{
Console.WriteLine(x);
}
foreach (var x in res)
{
DownloadProtocol("http://cdn.path.com/rental/" + torrentId + "/" + x, savePath + x);
}
return true;
}
catch
{
return false;
}
}
public void DownloadProtocol(string address, string location)
{
WebClient client = new WebClient();
Uri Uri = new Uri(address);
client.DownloadFileCompleted += new AsyncCompletedEventHandler(Completed);
client.DownloadProgressChanged += new DownloadProgressChangedEventHandler(DownloadProgress);
client.DownloadFileAsync(Uri, location);
}
private void DownloadProgress(object sender, DownloadProgressChangedEventArgs e)
{
// Displays the operation identifier, and the transfer progress.
Console.WriteLine("{0} downloaded {1} of {2} bytes. {3} % complete...",
(string)e.UserState,
e.BytesReceived,
e.TotalBytesToReceive,
e.ProgressPercentage);
}
private void Completed(object sender, AsyncCompletedEventArgs e)
{
if (e.Cancelled == true)
{
Console.WriteLine("Download has been canceled.");
}
else
{
Console.WriteLine("Download completed!");
}
}
This code work fine in an Console app with a current thread blocker. But when I use the same code in an WPF app It doesn't. I'm using a button to execute the StartDownload() function, but when I do that it start downloading all the files at the same time. Example the first file get 3% done and then it switch to another file and so on. I really don't know why this isn't working.
Have you considered not using .DownloadFileAsync? You can try .DownloadFile and start DownloadProtocol() with a single background thread. Although I think you'll have to rethink your DownloadProgress output.
I do something very similar within a winform.
I have A C# Visual Studio 2012 Solution that relies on a native dll that I use PInvoke to access. When I deploy the app I will have to ensure that this Dll is in the app folder.
Is there anyway I can merge this Dll into the executable?
perhaps as a resource?
I have heard of ILMerge but I am told it cant cope with native code.
Any help would be appreciated.
You can create a Setup package project with Visual Studio that deploys all your files to the correct location or use other third party packaging software (like full InstallShield or alternatives)
However, your question reminds me on the Open Hardware Monitor project where they include drivers as embedded resource and extract them when the user starts the application. It works like this: they've added WinRing0.sys and WinRing0x64.sys to the project and set their Build Action to Embedded Resource, then they have a method that extracts the driver from the resource:
private static bool ExtractDriver(string fileName) {
string resourceName = "OpenHardwareMonitor.Hardware." +
(OperatingSystem.Is64BitOperatingSystem() ? "WinRing0x64.sys" :
"WinRing0.sys");
string[] names =
Assembly.GetExecutingAssembly().GetManifestResourceNames();
byte[] buffer = null;
for (int i = 0; i < names.Length; i++) {
if (names[i].Replace('\\', '.') == resourceName) {
using (Stream stream = Assembly.GetExecutingAssembly().
GetManifestResourceStream(names[i]))
{
buffer = new byte[stream.Length];
stream.Read(buffer, 0, buffer.Length);
}
}
}
if (buffer == null)
return false;
try {
using (FileStream target = new FileStream(fileName, FileMode.Create)) {
target.Write(buffer, 0, buffer.Length);
target.Flush();
}
} catch (IOException) {
// for example there is not enough space on the disk
return false;
}
// make sure the file is actually writen to the file system
for (int i = 0; i < 20; i++) {
try {
if (File.Exists(fileName) &&
new FileInfo(fileName).Length == buffer.Length)
{
return true;
}
Thread.Sleep(100);
} catch (IOException) {
Thread.Sleep(10);
}
}
// file still has not the right size, something is wrong
return false;
}
They're reading the resource into a buffer, write that buffer to disk and wait until the file has been flushed to disk.
My solution is conceptually similar to the one presented by Wouter.
It's what we use in our own app, and we can use native/mixed-mode and c# dlls all embedded in the same .exe.
It extracts the dlls into a temp dir everytime the application is run. Obviously you might not want to do this in the production version, where the dlls will be stable; you might choose a different directory there (probably somewhere in %AppData%). It will use an existing dll with the same version number, though (e.g. it's only done the first time when opening the app multiple times between booting the computer).
Since we're doing
AppDomain.CurrentDomain.AssemblyResolve += (sender, args)
this function is getting called wherever the system tries to resolve a dll. And since it's initalised in the static Program class, it all works automagically.
Program.cs:
namespace MyApp
{
internal class Program
{
static Program()
{
LoadAssemblyResource.Initialize("MyApp");
}
//....
}
}
LoadAssemblyResource.cs
namespace MyAppStartup
{
public static class LoadAssemblyResource
{
private readonly static String _version_string =
Assembly.GetExecutingAssembly().GetName().Version.ToString();
private readonly static String _dll_path = Path.GetTempPath()
+ "\\MyApp\\" + _version_string;
static public String last_error_msg = null;
public static bool WriteBytesToFile(string filename, byte[] bytes)
{
try
{
var fs = new FileStream(filename, FileMode.Create, FileAccess.Write);
fs.Write(bytes, 0, bytes.Length);
fs.Close();
return true;
}
catch (Exception e)
{
Console.WriteLine("Writing file failed. Exception: {0}", e.ToString());
}
return false;
}
public static Assembly LoadUnsafe(String assembly_name, Byte[] assembly)
{
if (!Directory.Exists(_dll_path))
{
Directory.CreateDirectory(_dll_path);
Console.WriteLine("Created tmp path '" + _dll_path + "'.");
}
String fullpath = _dll_path + "\\" + assembly_name;
if (!File.Exists(fullpath))
{
Console.WriteLine("Assembly location: " + fullpath + ".");
if (!WriteBytesToFile(fullpath, assembly))
return null;
}
return Assembly.UnsafeLoadFrom(fullpath);
}
public static void Initialize(String exe_name)
{
AppDomain.CurrentDomain.AssemblyResolve += (sender, args) =>
{
String assembly_name = new AssemblyName(args.Name).Name + ".dll";
String resource_name = exe_name + "." + assembly_name;
using (var stream =
Assembly.GetExecutingAssembly().GetManifestResourceStream(resource_name))
{
if (stream == null)
return null;
Byte[] assembly_data = new Byte[stream.Length];
stream.Read(assembly_data, 0, assembly_data.Length);
try
{
Assembly il_assembly = Assembly.Load(assembly_data);
return il_assembly;
}
catch (System.IO.FileLoadException ex)
{
// might have failed because it's an mixed-mode dll.
last_error_msg = ex.Message;
}
Assembly mixed_mode_assembly = LoadUnsafe(assembly_name, assembly_data);
return mixed_mode_assembly;
}
};
}
}
}