locked
Run Resource in VB.NET RRS feed

  • Question

  • Howdy,

    My VB.NET app uses a component that needs Visual C++ 2010 x64 to run, I embed the component with my application executable file using some tool to have a stand alone application which does not need installer. But for Visual C++ 2010 x64 requirement, I just check if it's not installed, show a message to user to install it first. Since it's only ~5MB, I have imported Visual C++ 2010 x64 in my VB.NT application as a resource, just need to run it in case it's not installed, how to run the embedded resource via code? Is there any code snippet on MSDN?

    I found some threads with some code snippets, but none of them worked for me.

    Thanks.



    • Edited by OSVBNET Sunday, January 6, 2019 4:47 PM
    Sunday, January 6, 2019 4:34 PM

Answers

  • Hello,

    You need to extract the embedded file before it can be executed e.g. extract a file stored under My.Settings/

    Public Class Form1
        Private FileName As String = IO.Path.Combine(Application.StartupPath, "MyFile.pdf")
        Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
            If IO.File.Exists(FileName) Then
                If My.Dialogs.Question("Replace existing file with file from resources?") Then
                    My.Computer.FileSystem.WriteAllBytes(FileName, My.Resources.MainDocument, False)
                End If
                Process.Start(FileName)
            Else
                My.Computer.FileSystem.WriteAllBytes(FileName, My.Resources.MainDocument, False)
                Process.Start(FileName)
            End If
        End Sub
    End Class
    

    From resource

    Imports System.IO
    
    Public Class Form1
        Private FileName As String = IO.Path.Combine(
            Application.StartupPath, "JsonCSharpClassGenerator.exe")
        Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
            If Not File.Exists(FileName) Then
                My.Computer.FileSystem.WriteAllBytes(FileName, My.Resources.JsonCSharpClassGenerator, False)
            End If
            Process.Start(FileName)
        End Sub
        Private Sub Form1_FormClosing(sender As Object, e As FormClosingEventArgs) Handles Me.FormClosing
            If File.Exists(FileName) Then
                Try
                    File.Delete(FileName)
                Catch ex As Exception
                    MessageBox.Show(ex.Message)
                    e.Cancel = True
                End Try
            End If
        End Sub
    End Class
    

    IMPORTANT

    The two code samples are rather basic in that they don't account for removal of the file on closing which may or may not be a issue for you.


    Please remember to mark the replies as answers if they help and unmark them if they provide no help, this will help others who are looking for solutions to the same or similar problem. Contact via my Twitter (Karen Payne) or Facebook (Karen Payne) via my MSDN profile but will not answer coding question on either.
    VB Forums - moderator
    profile for Karen Payne on Stack Exchange, a network of free, community-driven Q&A sites

    • Marked as answer by OSVBNET Sunday, January 6, 2019 10:30 PM
    Sunday, January 6, 2019 4:56 PM

All replies

  • Hello,

    You need to extract the embedded file before it can be executed e.g. extract a file stored under My.Settings/

    Public Class Form1
        Private FileName As String = IO.Path.Combine(Application.StartupPath, "MyFile.pdf")
        Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
            If IO.File.Exists(FileName) Then
                If My.Dialogs.Question("Replace existing file with file from resources?") Then
                    My.Computer.FileSystem.WriteAllBytes(FileName, My.Resources.MainDocument, False)
                End If
                Process.Start(FileName)
            Else
                My.Computer.FileSystem.WriteAllBytes(FileName, My.Resources.MainDocument, False)
                Process.Start(FileName)
            End If
        End Sub
    End Class
    

    From resource

    Imports System.IO
    
    Public Class Form1
        Private FileName As String = IO.Path.Combine(
            Application.StartupPath, "JsonCSharpClassGenerator.exe")
        Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
            If Not File.Exists(FileName) Then
                My.Computer.FileSystem.WriteAllBytes(FileName, My.Resources.JsonCSharpClassGenerator, False)
            End If
            Process.Start(FileName)
        End Sub
        Private Sub Form1_FormClosing(sender As Object, e As FormClosingEventArgs) Handles Me.FormClosing
            If File.Exists(FileName) Then
                Try
                    File.Delete(FileName)
                Catch ex As Exception
                    MessageBox.Show(ex.Message)
                    e.Cancel = True
                End Try
            End If
        End Sub
    End Class
    

    IMPORTANT

    The two code samples are rather basic in that they don't account for removal of the file on closing which may or may not be a issue for you.


    Please remember to mark the replies as answers if they help and unmark them if they provide no help, this will help others who are looking for solutions to the same or similar problem. Contact via my Twitter (Karen Payne) or Facebook (Karen Payne) via my MSDN profile but will not answer coding question on either.
    VB Forums - moderator
    profile for Karen Payne on Stack Exchange, a network of free, community-driven Q&A sites

    • Marked as answer by OSVBNET Sunday, January 6, 2019 10:30 PM
    Sunday, January 6, 2019 4:56 PM
  • WoW, thanks indeed, it was a great easy way of doing the job :)

    Just wanna know if it's possible not to save it on disc and load it to memory and run from there? Because if save it on disc, I prefer to remove the setup after execution, not on form closing, and I don't know how to achieve that?

    Sunday, January 6, 2019 5:22 PM
  • WoW, thanks indeed, it was a great easy way of doing the job :)

    Just wanna know if it's possible not to save it on disc and load it to memory and run from there? Because if save it on disc, I prefer to remove the setup after execution, not on form closing, and I don't know how to achieve that?

    Well, this could be done with native C++ (been to long for me to give you code to go from VB.NET to C#) as shown here but really you best option is to use what I've shown.

    /* 
     * Title: CMemoryExecute.cs
     * Description: Runs an EXE in memory using native WinAPI. Very optimized and tiny.
     * 
     * Developed by: affixiate 
     * Release date: December 10, 2010
     * Released on: http://opensc.ws
     * Credits:
     *          MSDN (http://msdn.microsoft.com)
     *          NtInternals (http://undocumented.ntinternals.net)
     *          Pinvoke (http://pinvoke.net)
     *          
     * Comments: If you use this code, I require you to give me credits. Don't be a ripper! ;]
     */
    
    // ReSharper disable InconsistentNaming
    public static unsafe class CMemoryExecute
    {
        public struct STARTUPINFO
        {
            public uint cb;
            public string lpReserved;
            public string lpDesktop;
            public string lpTitle;
            public uint dwX;
            public uint dwY;
            public uint dwXSize;
            public uint dwYSize;
            public uint dwXCountChars;
            public uint dwYCountChars;
            public uint dwFillAttribute;
            public uint dwFlags;
            public short wShowWindow;
            public short cbReserved2;
            public IntPtr lpReserved2;
            public IntPtr hStdInput;
            public IntPtr hStdOutput;
            public IntPtr hStdError;
        }
    
        /// <summary>
        /// Runs an EXE (which is loaded in a byte array) in memory.
        /// </summary>
        /// <param name="exeBuffer">The EXE buffer.</param>
        /// <param name="hostProcess">Full path of the host process to run the buffer in.</param>
        /// <param name="optionalArguments">Optional command line arguments.</param>
        /// <returns></returns>
        public static bool Run(byte[] exeBuffer, string hostProcess, string optionalArguments = "")
        {
            // STARTUPINFO
            STARTUPINFO StartupInfo = new STARTUPINFO();
            StartupInfo.dwFlags = STARTF_USESTDHANDLES|STARTF_USESHOWWINDOW;
            StartupInfo.wShowWindow = SW_HIDE;
    
            var IMAGE_SECTION_HEADER = new byte[0x28]; // pish
            var IMAGE_NT_HEADERS = new byte[0xf8]; // pinh
            var IMAGE_DOS_HEADER = new byte[0x40]; // pidh
            var PROCESS_INFO = new int[0x4]; // pi
            var CONTEXT = new byte[0x2cc]; // ctx
    
            byte* pish;
            fixed (byte* p = &IMAGE_SECTION_HEADER[0])
                pish = p;
    
            byte* pinh;
            fixed (byte* p = &IMAGE_NT_HEADERS[0])
                pinh = p;
    
            byte* pidh;
            fixed (byte* p = &IMAGE_DOS_HEADER[0])
                pidh = p;
    
            byte* ctx;
            fixed (byte* p = &CONTEXT[0])
                ctx = p;
    
            // Set the flag.
            *(uint*)(ctx + 0x0 /* ContextFlags */) = CONTEXT_FULL;
    
            // Get the DOS header of the EXE.
            Buffer.BlockCopy(exeBuffer, 0, IMAGE_DOS_HEADER, 0, IMAGE_DOS_HEADER.Length);
    
            /* Sanity check:  See if we have MZ header. */
            if (*(ushort*)(pidh + 0x0 /* e_magic */) != IMAGE_DOS_SIGNATURE)
                return false;
    
            var e_lfanew = *(int*)(pidh + 0x3c);
    
            // Get the NT header of the EXE.
            Buffer.BlockCopy(exeBuffer, e_lfanew, IMAGE_NT_HEADERS, 0, IMAGE_NT_HEADERS.Length);
    
            /* Sanity check: See if we have PE00 header. */
            if (*(uint*)(pinh + 0x0 /* Signature */) != IMAGE_NT_SIGNATURE)
                return false;
    
            // Run with parameters if necessary.
            if (!string.IsNullOrEmpty(optionalArguments))
                hostProcess += " " + optionalArguments;
    
            if (!CreateProcess(null, hostProcess, IntPtr.Zero, IntPtr.Zero, false, CREATE_SUSPENDED, IntPtr.Zero, null, ref StartupInfo, PROCESS_INFO))
                return false;
    
            var ImageBase = new IntPtr(*(int*)(pinh + 0x34));
            NtUnmapViewOfSection((IntPtr)PROCESS_INFO[0] /* pi.hProcess */, ImageBase);
            if (VirtualAllocEx((IntPtr)PROCESS_INFO[0] /* pi.hProcess */, ImageBase, *(uint*)(pinh + 0x50 /* SizeOfImage */), MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE) == IntPtr.Zero)
                Run(exeBuffer, hostProcess, optionalArguments); // Memory allocation failed; try again (this can happen in low memory situations)
    
            fixed (byte* p = &exeBuffer[0])
                NtWriteVirtualMemory((IntPtr)PROCESS_INFO[0] /* pi.hProcess */, ImageBase, (IntPtr)p, *(uint*)(pinh + 84 /* SizeOfHeaders */), IntPtr.Zero);
    
            for (ushort i = 0; i < *(ushort*)(pinh + 0x6 /* NumberOfSections */); i++)
            {
                Buffer.BlockCopy(exeBuffer, e_lfanew + IMAGE_NT_HEADERS.Length + (IMAGE_SECTION_HEADER.Length * i), IMAGE_SECTION_HEADER, 0, IMAGE_SECTION_HEADER.Length);
                fixed (byte* p = &exeBuffer[*(uint*)(pish + 0x14 /* PointerToRawData */)])
                    NtWriteVirtualMemory((IntPtr)PROCESS_INFO[0] /* pi.hProcess */, (IntPtr)((int)ImageBase + *(uint*)(pish + 0xc /* VirtualAddress */)), (IntPtr)p, *(uint*)(pish + 0x10 /* SizeOfRawData */), IntPtr.Zero);
            }
    
            NtGetContextThread((IntPtr)PROCESS_INFO[1] /* pi.hThread */, (IntPtr)ctx);
            NtWriteVirtualMemory((IntPtr)PROCESS_INFO[0] /* pi.hProcess */, (IntPtr)(*(uint*)(ctx + 0xAC /* ecx */)), ImageBase, 0x4, IntPtr.Zero);
            *(uint*)(ctx + 0xB0 /* eax */) = (uint)ImageBase + *(uint*)(pinh + 0x28 /* AddressOfEntryPoint */);
            NtSetContextThread((IntPtr)PROCESS_INFO[1] /* pi.hThread */, (IntPtr)ctx);
            NtResumeThread((IntPtr)PROCESS_INFO[1] /* pi.hThread */, IntPtr.Zero);
    
    
            return true;
        }
    
        #region WinNT Definitions
    
        private const uint CONTEXT_FULL = 0x10007;
        private const int CREATE_SUSPENDED = 0x4;
        private const int MEM_COMMIT = 0x1000;
        private const int MEM_RESERVE = 0x2000;
        private const int PAGE_EXECUTE_READWRITE = 0x40;
        private const ushort IMAGE_DOS_SIGNATURE = 0x5A4D; // MZ
        private const uint IMAGE_NT_SIGNATURE = 0x00004550; // PE00
    
        private static short SW_SHOW = 5;
        private static short SW_HIDE = 0;
        private const uint STARTF_USESTDHANDLES = 0x00000100;
        private const uint STARTF_USESHOWWINDOW = 0x00000001;
    
    
        #region WinAPI
        [DllImport("kernel32.dll", SetLastError = true)]
        private static extern bool CreateProcess(string lpApplicationName, string lpCommandLine, IntPtr lpProcessAttributes, IntPtr lpThreadAttributes, bool bInheritHandles, uint dwCreationFlags, IntPtr lpEnvironment, string lpCurrentDirectory, ref STARTUPINFO lpStartupInfo, int[] lpProcessInfo);
    
        [DllImport("kernel32.dll", SetLastError = true)]
        private static extern IntPtr VirtualAllocEx(IntPtr hProcess, IntPtr lpAddress, uint dwSize, uint flAllocationType, uint flProtect);
    
        [DllImport("ntdll.dll", SetLastError = true)]
        private static extern uint NtUnmapViewOfSection(IntPtr hProcess, IntPtr lpBaseAddress);
    
        [DllImport("ntdll.dll", SetLastError = true)]
        private static extern int NtWriteVirtualMemory(IntPtr hProcess, IntPtr lpBaseAddress, IntPtr lpBuffer, uint nSize, IntPtr lpNumberOfBytesWritten);
    
        [DllImport("ntdll.dll", SetLastError = true)]
        private static extern int NtGetContextThread(IntPtr hThread, IntPtr lpContext);
    
        [DllImport("ntdll.dll", SetLastError = true)]
        private static extern int NtSetContextThread(IntPtr hThread, IntPtr lpContext);
    
        [DllImport("ntdll.dll", SetLastError = true)]
        private static extern uint NtResumeThread(IntPtr hThread, IntPtr SuspendCount);
        #endregion
    
        #endregion
    }


    Please remember to mark the replies as answers if they help and unmark them if they provide no help, this will help others who are looking for solutions to the same or similar problem. Contact via my Twitter (Karen Payne) or Facebook (Karen Payne) via my MSDN profile but will not answer coding question on either.
    VB Forums - moderator
    profile for Karen Payne on Stack Exchange, a network of free, community-driven Q&A sites

    Sunday, January 6, 2019 5:41 PM
  • One more thought, extract to a temp folder then when finished the setup remove the file e.g.

    Dim installTempFolder = Path.Combine(Path.GetTempPath(), "MySetup")
    Another option which could go with the first option is to have the extracted file only run if a specific argument is passed thus it can't run outside of the setup operation.


    Please remember to mark the replies as answers if they help and unmark them if they provide no help, this will help others who are looking for solutions to the same or similar problem. Contact via my Twitter (Karen Payne) or Facebook (Karen Payne) via my MSDN profile but will not answer coding question on either.
    VB Forums - moderator
    profile for Karen Payne on Stack Exchange, a network of free, community-driven Q&A sites

    Sunday, January 6, 2019 5:44 PM
  • Thanks Karen for your great info, I really appreciate that :)
    Sunday, January 6, 2019 10:31 PM