External application receives message but no contained data using sharedmemory - c#

I am using sharedmemory in my c# app with c++ interop. Currently I am marshalling a struct to a pointer and broadcasting the message. The program I am broadcasting to, opens up correctly with the debug message, but doesn't show/bring-in the data that I had in use within my struct.
Thanks!
The app I am trying to talk to was written in c++ and I am coding in c#. I am using all the DLLImports correctly (I think) and it compiles and runs error free.
using System.Runtime.InteropServices;
[DllImport("user32", CallingConvention = CallingConvention.StdCall, CharSet = CharSet.Unicode)]
public static extern uint RegisterWindowMessageW([In]string lpString);
[DllImport("user32", CallingConvention = CallingConvention.StdCall, CharSet = CharSet.Ansi)]
public static extern uint RegisterWindowMessageA([In]string lpString);
[DllImport("kernel32", CallingConvention = CallingConvention.StdCall, CharSet = CharSet.Auto)]
public static extern IntPtr OpenFileMapping(FileMapAccessRights dwDesiredAccess, int bInheritHandle, [In]String lpName);
[DllImport("kernel32", CallingConvention = CallingConvention.StdCall, CharSet = CharSet.Auto)]
public static extern IntPtr MapViewOfFile(IntPtr hFileMappingObject, FileMapAccessRights dwDesiredAccess, uint dwFileOffsetHigh, uint dwFileOffsetLow, UIntPtr dwNumberOfBytesToMap);
[DllImport("kernel32", CallingConvention = CallingConvention.StdCall)]
public static extern int UnmapViewOfFile(IntPtr lpBaseAddress);
[DllImport("kernel32", CallingConvention = CallingConvention.StdCall)]
public static extern int CloseHandle(IntPtr hObject);
[DllImport("user32.dll")]
public static extern IntPtr PostMessage(IntPtr hWnd, uint msg, int wParam, int lParam);
uint WM_ZOOM_XYZ = RegisterWindowMessageA("WM_ZOOM_XYZ");
int i = Broadcast_Zoom_Message(10000, 10000, 0, WM_ZOOM_XYZ);
public int Broadcast_Zoom_Message(double dbX, double dbY, double dbZ, uint uMessage)
{
string smSharedMemory = "COORDINATES";
IntPtr hMem = OpenFileMapping(FileMapAccessRights.Write, FALSE, smSharedMemory);
if (IntPtr.Zero == hMem)
{
return 0;
}
IntPtr pvHead = MapViewOfFile(hMem, FileMapAccessRights.Write, 0, 0, UIntPtr.Zero);
if (IntPtr.Zero == pvHead)
{
CloseHandle(hMem);
MessageBox.Show(
"Unable to view " + smSharedMemory,
"Error", MessageBoxButtons.OK, MessageBoxIcon.Stop);
return 0;
}
CoordinatesStruct structCoords = new CoordinatesStruct();
Marshal.PtrToStructure(pvHead, structCoords);
int bVersionOk = FALSE;
if (1 == structCoords.uMajorVersion)
{
if (WM_ZOOM_XYZ == uMessage)
{
structCoords.dbDesiredX = dbX;
structCoords.dbDesiredY = dbY;
structCoords.dbDesiredZ = dbZ;
}
bVersionOk = TRUE;
}
else
{
MessageBox.Show(
"Unrecognized shared memory: " +
structCoords.uMajorVersion.ToString() + "." + structCoords.uMinorVersion.ToString());
}
if (IntPtr.Zero != hMem)
{
CloseHandle(hMem);
}
UnmapViewOfFile(pvHead);
IntPtr HWND_BROADCAST = (IntPtr)0xffff;
if (bVersionOk == TRUE)
{
PostMessage(HWND_BROADCAST, uMessage, 0, 0);
return 1;
}
else
return 0;
}

I think your intention was to put the changed structCoords back to the mapped file. When we use Marshal.PtrToStructure() we receive a copy of the content of the unmanaged memory. The changes of the received object will not reflect in the unmanaged memory. When we are done with the data, we should put the changes back to the memory using Marshal.StructureToPtr.
Here is what I think it should be:
if (1 == structCoords.uMajorVersion)
{
if (WM_ZOOM_XYZ == uMessage)
{
structCoords.dbDesiredX = dbX;
structCoords.dbDesiredY = dbY;
structCoords.dbDesiredZ = dbZ;
}
bVersionOk = TRUE;
Marshal.StructureToPtr(structCoords , pvHead, false); // <-- this is what you (I) forgot!
}

Related

Can't toggle 'Align icons to grid' on the desktop

Here's the code I'm using:
private void Button_Click(object sender, RoutedEventArgs e) {
SendMessage(GetDesktopWindow(), LVM_ARRANGE, LVA_SNAPTOGRID, 0);
}
public const uint LVM_ARRANGE = 0x1000 + 22;
public const int LVA_SNAPTOGRID = 0x0005;
[DllImport("User32.dll", CharSet = CharSet.Auto)]
public static extern IntPtr GetDesktopWindow();
[DllImport("user32.dll")]
public static extern int SendMessage(IntPtr hWnd, uint msg, int wParam, int lParam);
Nothing happens when I run it. Code is borrowed from https://www.codeproject.com/Messages/1168961/Re-Auto-Arrange-desktop-icons.aspx
Tried different Windows versions too.
This code worked for me. Note that it doesn't appear to change the options, so although it arranges to the grid for me the View->Align Icons To Grid is still unchecked. The issue is outlined here: How do I get the window handle of the desktop?
Your problem results from a fairly widespread confusion over what the
desktop window actually is. The GetDesktopWindow function does
precisely what it's documented to do: it returns a handle to the
desktop window. This, however, is not the same window that contains
the desktop icons.
So I used the answer here: Get handle to desktop / shell window but with replacing or adding methods and p/invoke calls until I had everything necessary because that link only gives method calls and not the dll imports (I may have left some superfluous stuff in here).
static void Main()
{
SendMessage(GetDesktopWindow(DesktopWindow.SysListView32), LVM_ARRANGE, LVA_SNAPTOGRID, 0);
Console.ReadLine();
}
public const int LVM_ARRANGE = 4118;
public const int LVA_SNAPTOGRID = 5;
[DllImport("user32.dll")]
static extern IntPtr GetShellWindow();
[DllImport("user32.dll", CharSet = CharSet.Unicode)]
static extern IntPtr FindWindowEx(IntPtr parentHandle, IntPtr childAfter, string lclassName, string windowTitle);
[DllImport("User32.dll", CharSet = CharSet.Auto)]
public static extern IntPtr GetDesktopWindow();
[DllImport("user32.dll")]
public static extern int SendMessage(IntPtr hWnd, uint msg, int wParam, int lParam);
[DllImport("user32.dll")]
private static extern bool EnumWindows(EnumWindowsProc enumProc, IntPtr lParam);
public delegate bool EnumWindowsProc(IntPtr hWnd, IntPtr lParam);
[DllImport("user32.dll", CharSet = CharSet.Unicode)]
private static extern int GetWindowText(IntPtr hWnd, StringBuilder strText, int maxCount);
[DllImport("user32.dll", CharSet = CharSet.Unicode)]
private static extern int GetWindowTextLength(IntPtr hWnd);
public enum DesktopWindow
{
ProgMan,
SHELLDLL_DefViewParent,
SHELLDLL_DefView,
SysListView32
}
public static IntPtr GetDesktopWindow(DesktopWindow desktopWindow)
{
IntPtr _ProgMan = GetShellWindow();
IntPtr _SHELLDLL_DefViewParent = _ProgMan;
IntPtr _SHELLDLL_DefView = FindWindowEx(_ProgMan, IntPtr.Zero, "SHELLDLL_DefView", null);
IntPtr _SysListView32 = FindWindowEx(_SHELLDLL_DefView, IntPtr.Zero, "SysListView32", "FolderView");
if (_SHELLDLL_DefView == IntPtr.Zero)
{
EnumWindows((hwnd, lParam) =>
{
if (GetWindowText(hwnd) == "WorkerW")
{
IntPtr child = FindWindowEx(hwnd, IntPtr.Zero, "SHELLDLL_DefView", null);
if (child != IntPtr.Zero)
{
_SHELLDLL_DefViewParent = hwnd;
_SHELLDLL_DefView = child;
_SysListView32 = FindWindowEx(child, IntPtr.Zero, "SysListView32", "FolderView"); ;
return false;
}
}
return true;
}, IntPtr.Zero);
}
switch (desktopWindow)
{
case DesktopWindow.ProgMan:
return _ProgMan;
case DesktopWindow.SHELLDLL_DefViewParent:
return _SHELLDLL_DefViewParent;
case DesktopWindow.SHELLDLL_DefView:
return _SHELLDLL_DefView;
case DesktopWindow.SysListView32:
return _SysListView32;
default:
return IntPtr.Zero;
}
}
public static string GetWindowText(IntPtr hWnd)
{
int size = GetWindowTextLength(hWnd);
if (size > 0)
{
var builder = new StringBuilder(size + 1);
GetWindowText(hWnd, builder, builder.Capacity);
return builder.ToString();
}
return String.Empty;
}

Next Song Button For External Media Player?

Feel free to edit title.
Ok so i'm trying to create a short key button that skips to the next song of any media player? like what some keyboards have as in FN + F11 and it goes to next song is there anyway to integrate that into c# for my own keyboard? i have this code so far but all its doing is posting a msg onto the textbox1.
// Structure contain information about low-level keyboard input event
[StructLayout(LayoutKind.Sequential)]
private struct KBDLLHOOKSTRUCT
{
public Keys key;
public int scanCode;
public int flags;
public int time;
public IntPtr extra;
}
//System level functions to be used for hook and unhook keyboard input
private delegate IntPtr LowLevelKeyboardProc(int nCode, IntPtr wParam, IntPtr lParam);
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
private static extern IntPtr SetWindowsHookEx(int id, LowLevelKeyboardProc callback, IntPtr hMod, uint dwThreadId);
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
private static extern bool UnhookWindowsHookEx(IntPtr hook);
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
private static extern IntPtr CallNextHookEx(IntPtr hook, int nCode, IntPtr wp, IntPtr lp);
[DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
private static extern IntPtr GetModuleHandle(string name);
[DllImport("user32.dll", CharSet = CharSet.Auto)]
private static extern short GetAsyncKeyState(Keys key);
//Declaring Global objects
private IntPtr ptrHook;
private LowLevelKeyboardProc objKeyboardProcess;
private IntPtr captureKey(int nCode, IntPtr wp, IntPtr lp)
{
if (nCode >= 0)
{
KBDLLHOOKSTRUCT objKeyInfo = (KBDLLHOOKSTRUCT)Marshal.PtrToStructure(lp, typeof(KBDLLHOOKSTRUCT));
// Keys
if (objKeyInfo.key == Keys.F10 && ModifierKeys == Keys.Alt)
{
textBox1.Focus();
a += 1;
c += 1;
textBox1.Text += Convert.ToString(c) + ". " + "Previous Song" + Environment.NewLine;
PrevSongCount.Text = Convert.ToString(a);
AllUpCount.Text = Convert.ToString(c);
return (IntPtr)1;
}
if (objKeyInfo.key == Keys.F11 && ModifierKeys == Keys.Alt)
{
textBox1.Focus();
b += 1;
c += 1;
textBox1.Text += Convert.ToString(c) + ". " + "Next Song" + Environment.NewLine;
NextSongCount.Text = Convert.ToString(b);
AllUpCount.Text = Convert.ToString(c);
return (IntPtr)1;
}
}
return CallNextHookEx(ptrHook, nCode, wp, lp);
}
bool HasAltModifier(int flags)
{
return (flags & 0x20) == 0x20;
}
This was not as easy as I thought. But finally I managed to do it and the solution was shockingly simple.
After compiling this you are using the venerable virtual media keyboard codes.
http://msdn.microsoft.com/en-us/library/dd375731%28v=VS.85%29.aspx
I used this cmd line prog for my microsoft natural keyboard which does not have media keys but has 5 programmable keys and to get it to work you hack the registry
HKEY_CURRENT_USER\Software\Microsoft\IntelliType Pro\EventMapping\82 or
HKEY_CURRENT_USER\Software\Microsoft\IntelliType Pro\ModelSpecific\1016\EventMapping\82
where the 81 is just one of the dynamic keys (78-82)
and put the value previous or next into the Arguments key.
using System;
using System.Runtime.InteropServices;
namespace NxtTrack
{
class Program
{
[DllImport("user32.dll")]
private static extern bool PostMessage(IntPtr hWnd, uint Msg, UIntPtr wParam, IntPtr lParam);
[DllImport("user32.dll")]
public static extern void keybd_event(byte vkCode, byte scanCode, int flags, IntPtr extraInfo);
enum TrackMove
{
Previous,Next
}
static void Main(string[] args)
{
TrackMove trackMove;
try
{
if(args[0].ToLower().Contains("previous"))
trackMove = TrackMove.Previous;
else if(args[0].ToLower().Contains("next"))
trackMove = TrackMove.Next;
else
{
throw new Exception("wrong param");
}
}
catch
{
Console.WriteLine("Params needed: Next or Previous");
return;
}
TrackKeys(trackMove);
}
private static void TrackKeys(TrackMove trackMove)
{
//http://msdn.microsoft.com/en-us/library/dd375731%28v=VS.85%29.aspx
byte msg = trackMove == TrackMove.Previous ? (byte)0xB1 : (byte)0xB0;
keybd_event(msg, 0x45, 0, IntPtr.Zero);
}
}
}

C# and partially working SendMessage?

I've tried to send text messages to various applications in Windows 7 (eg. Notepad++, Notepad etc.). SendMessage is working fine for Notepad but not for Notepad++.
If i'm sending text to Notepad everything appears fine, whole text and i'm getting 1 as return from SendMessage method. But for Notepad++ only first letter appears and method SendMessage is returning 0, however Marshal.GetLastWin32Error() is not returning any error (result 0)?
Here's the code:
GUITHREADINFO gti = new GUITHREADINFO();
IntPtr hWnd = GetForegroundWindow();
uint processId;
uint activeThreadId = GetWindowThreadProcessId(hWnd, out processId);
if (GetInfo(activeThreadId, out gti))
{
int EM_REPLACESEL = 0x00C2;
int error = Marshal.GetLastWin32Error();
int result = SendMessageW(gti.hwndCaret, EM_REPLACESEL, -1, passed);//3rd param doesn't change anything
error = Marshal.GetLastWin32Error();
}
WinAPI functions and GetInfo method as long with required structures are defined as:
[DllImport("User32.dll", EntryPoint = "SendMessageW", SetLastError = true, CharSet = CharSet.Unicode)]
public static extern int SendMessageW(IntPtr hWnd, int uMsg, int wParam, string lParam);
[DllImport("user32.dll")]
static extern IntPtr GetForegroundWindow();
[DllImport("user32.dll", SetLastError = true)]
static extern uint GetWindowThreadProcessId(IntPtr hWnd, out uint lpdwProcessId);
//"Borrowed" code
public static bool GetInfo(uint hwnd, out GUITHREADINFO lpgui)
{
uint lpdwProcessId;
uint threadId = GetWindowThreadProcessId(hwnd, out lpdwProcessId);
lpgui = new GUITHREADINFO();
lpgui.cbSize = Marshal.SizeOf(lpgui);
return GetGUIThreadInfo(threadId, ref lpgui);
}
[StructLayout(LayoutKind.Sequential)]
public struct RECT
{
public int iLeft;
public int iTop;
public int iRight;
public int iBottom;
}
[StructLayout(LayoutKind.Sequential)]
public struct GUITHREADINFO
{
public int cbSize;
public int flags;
public IntPtr hwndActive;
public IntPtr hwndFocus;
public IntPtr hwndCapture;
public IntPtr hwndMenuOwner;
public IntPtr hwndMoveSize;
public IntPtr hwndCaret;
public RECT rectCaret;
}
So well i wonder what should i do to fix it so it would work (fully) for all windows not only for edit control in Notepad?

HDMI TV sometimes not detected in windows 7? Possible to invoke Detect in code?

i have a standalone public kiosk pc that startups automatically everyday. It is connected to a HD TV and sometimes it is not detected. i have to personally go down to the PC, go to Screen Resolution and press Detect which it works.
my question is how do i know if the monitor i want it to display is connected properly in code?
thanks
I did manage to find some code on the MSDN site where a user is using code to determine which type of monitor is connected. I hope this may be a good starting point for you.
using System;
using System.Runtime.InteropServices;
using System.Windows;
using System.Windows.Interop;
namespace CRT
{
/// <summary>
/// Interaction logic for Window1.xaml
/// </summary>
public partial class Window1 : Window
{
public class NativeMethods
{
[DllImport("user32.dll", EntryPoint = "MonitorFromWindow", SetLastError = true)]
public static extern IntPtr MonitorFromWindow(
[In] IntPtr hwnd, uint dwFlags);
[DllImport("dxva2.dll", EntryPoint = "GetNumberOfPhysicalMonitorsFromHMONITOR", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool GetNumberOfPhysicalMonitorsFromHMONITOR(
IntPtr hMonitor, ref uint pdwNumberOfPhysicalMonitors);
[DllImport("dxva2.dll", EntryPoint = "GetPhysicalMonitorsFromHMONITOR", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool GetPhysicalMonitorsFromHMONITOR(
IntPtr hMonitor,
uint dwPhysicalMonitorArraySize,
[Out] NativeStructures.PHYSICAL_MONITOR[] pPhysicalMonitorArray);
[DllImport("dxva2.dll", EntryPoint = "DestroyPhysicalMonitors", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool DestroyPhysicalMonitors(
uint dwPhysicalMonitorArraySize, [Out] NativeStructures.PHYSICAL_MONITOR[] pPhysicalMonitorArray);
[DllImport("dxva2.dll", EntryPoint = "GetMonitorTechnologyType", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool GetMonitorTechnologyType(
IntPtr hMonitor, ref NativeStructures.MC_DISPLAY_TECHNOLOGY_TYPE pdtyDisplayTechnologyType);
[DllImport("dxva2.dll", EntryPoint = "GetMonitorCapabilities", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool GetMonitorCapabilities(
IntPtr hMonitor, ref uint pdwMonitorCapabilities, ref uint pdwSupportedColorTemperatures);
}
public class NativeConstants
{
public const int MONITOR_DEFAULTTOPRIMARY = 1;
public const int MONITOR_DEFAULTTONEAREST = 2;
public const int MONITOR_DEFAULTTONULL = 0;
}
public class NativeStructures
{
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
public struct PHYSICAL_MONITOR
{
public IntPtr hPhysicalMonitor;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 128)] public string szPhysicalMonitorDescription;
}
public enum MC_DISPLAY_TECHNOLOGY_TYPE
{
MC_SHADOW_MASK_CATHODE_RAY_TUBE,
MC_APERTURE_GRILL_CATHODE_RAY_TUBE,
MC_THIN_FILM_TRANSISTOR,
MC_LIQUID_CRYSTAL_ON_SILICON,
MC_PLASMA,
MC_ORGANIC_LIGHT_EMITTING_DIODE,
MC_ELECTROLUMINESCENT,
MC_MICROELECTROMECHANICAL,
MC_FIELD_EMISSION_DEVICE,
}
}
public Window1() { InitializeComponent(); }
private void Button_Click(object sender, RoutedEventArgs e)
{
WindowInteropHelper helper = new WindowInteropHelper(this);
IntPtr hMonitor = NativeMethods.MonitorFromWindow(helper.Handle, NativeConstants.MONITOR_DEFAULTTOPRIMARY);
int lastWin32Error = Marshal.GetLastWin32Error();
uint pdwNumberOfPhysicalMonitors = 0u;
bool numberOfPhysicalMonitorsFromHmonitor = NativeMethods.GetNumberOfPhysicalMonitorsFromHMONITOR(
hMonitor, ref pdwNumberOfPhysicalMonitors);
lastWin32Error = Marshal.GetLastWin32Error();
NativeStructures.PHYSICAL_MONITOR[] pPhysicalMonitorArray =
new NativeStructures.PHYSICAL_MONITOR[pdwNumberOfPhysicalMonitors];
bool physicalMonitorsFromHmonitor = NativeMethods.GetPhysicalMonitorsFromHMONITOR(
hMonitor, pdwNumberOfPhysicalMonitors, pPhysicalMonitorArray);
lastWin32Error = Marshal.GetLastWin32Error();
uint pdwMonitorCapabilities = 0u;
uint pdwSupportedColorTemperatures = 0u;
var monitorCapabilities = NativeMethods.GetMonitorCapabilities(
pPhysicalMonitorArray[0].hPhysicalMonitor, ref pdwMonitorCapabilities, ref pdwSupportedColorTemperatures);
lastWin32Error = Marshal.GetLastWin32Error();
NativeStructures.MC_DISPLAY_TECHNOLOGY_TYPE type =
NativeStructures.MC_DISPLAY_TECHNOLOGY_TYPE.MC_SHADOW_MASK_CATHODE_RAY_TUBE;
var monitorTechnologyType = NativeMethods.GetMonitorTechnologyType(
pPhysicalMonitorArray[0].hPhysicalMonitor, ref type);
lastWin32Error = Marshal.GetLastWin32Error();
var destroyPhysicalMonitors = NativeMethods.DestroyPhysicalMonitors(
pdwNumberOfPhysicalMonitors, pPhysicalMonitorArray);
lastWin32Error = Marshal.GetLastWin32Error();
this.lbl.Content = type;
}
}
}

c# BeginUpdateResource

I would like to add a string resource to an executable file programmatically. Just for example purposes, let's say I am trying to add a string named "String SO" which holds the value of "stringVal"
If this helps anyone - if I were to do this through VS.net I could just right click on my Project => Resources => Add New String Resource etc..
I am using the following Win32 API's:
[DllImport("kernel32.dll", SetLastError = true)]
public static extern IntPtr BeginUpdateResource(string pFileName,
[MarshalAs(UnmanagedType.Bool)]bool bDeleteExistingResources);
[DllImport("kernel32.dll", SetLastError = true)]
public static extern bool UpdateResource(IntPtr hUpdate, uint lpType, uint lpName, ushort wLanguage, byte[] lpData, uint cbData);
[DllImport("kernel32.dll", SetLastError = true)]
public static extern bool EndUpdateResource(IntPtr hUpdate, bool fDiscard);
So, I have found a couple of pages online but none of them seem to help me in what I am trying to do. If any of you are able to find anything I would be very grateful.
Otherwise, I would greatly appreciate any snippets that may help.
Thank you,
Evan
There is a very helpful library for many resource-tasks at github.
Many classes and function do wrap those window-api-calls around UpdateResource(...), etc.
Hope that helps.
I'm injecting an application byte[] as a resource to execute it on runtime. Here's my piece of code, hope it helps:
class AddResource
{
[DllImport("kernel32.dll", SetLastError = true)]
static extern bool UpdateResource(IntPtr hUpdate, string lpType, string lpName, ushort wLanguage, IntPtr lpData, uint cbData);
[DllImport("kernel32.dll", SetLastError = true)]
static extern IntPtr BeginUpdateResource(string pFileName,
[MarshalAs(UnmanagedType.Bool)]bool bDeleteExistingResources);
[DllImport("kernel32.dll", SetLastError = true)]
static extern bool EndUpdateResource(IntPtr hUpdate, bool fDiscard);
private static IntPtr ToPtr(object data)
{
GCHandle h = GCHandle.Alloc(data, GCHandleType.Pinned);
IntPtr ptr;
try
{
ptr = h.AddrOfPinnedObject();
}
finally
{
h.Free();
}
return ptr;
}
public static bool InjectResource(string filename, byte[] bytes, string resourceName)
{
try
{
IntPtr handle = BeginUpdateResource(filename, false);
byte[] file1 = bytes;
IntPtr fileptr = ToPtr(file1);
bool res = UpdateResource(handle, resourceName,
//"RT_RCDATA",
"0", 0, fileptr, Convert.ToUInt32(file1.Length));
EndUpdateResource(handle, false);
}
catch
{
return false;
}
return true;
}
public static void CopyStream(Stream input, Stream output,long sz)
{
// Insert null checking here for production
byte[] buffer = new byte[sz];
int bytesRead;
while ((bytesRead = input.Read(buffer, 0, buffer.Length)) > 0)
{
output.Write(buffer, 0, bytesRead);
}
}
}
Here is how I use it:
using (Stream input = Assembly.GetExecutingAssembly().GetManifestResourceStream("AppLicensing.Resources.SAppStarter.exe"))
using (Stream output = File.Create(outputFilePath))
{
long sz = input.Length;
AddResource.CopyStream(input, output, sz);
}
//inject crypted bytes
AddResource.InjectResource(outputFilePath, Encryptor.cryptedbytes, "RT_RCDATA");
And here is how I extract the resource (notice the "RT_RCDATA" -> that s the name of the resource):
class ReadResource
{
[DllImport("kernel32.dll", CharSet = CharSet.Auto)]
public static extern IntPtr GetModuleHandle(string lpModuleName);
[DllImport("kernel32.dll", SetLastError = true)]
static extern IntPtr FindResource(IntPtr hModule, string lpName, string lpType);
[DllImport("Kernel32.dll", EntryPoint = "SizeofResource", SetLastError = true)]
private static extern uint SizeofResource(IntPtr hModule, IntPtr hResource);
[DllImport("Kernel32.dll", EntryPoint = "LoadResource", SetLastError = true)]
private static extern IntPtr LoadResource(IntPtr hModule, IntPtr hResource);
public static byte[] GetFromResource(String resourceName)
{
try
{
IntPtr hModule = GetModuleHandle(System.Diagnostics.Process.GetCurrentProcess().MainModule.ModuleName);
IntPtr loc = FindResource(hModule, "0", resourceName);
uint size = SizeofResource(hModule, loc);
IntPtr x = LoadResource(hModule, loc);
byte[] bPtr = new byte[size];
Marshal.Copy(x, bPtr, 0, (int)(size));
return bPtr;
}
catch (Exception e)
{
System.Windows.Forms.MessageBox.Show(e.ToString());
System.Environment.Exit(0);
return null;
}
}
}
byte[] encryptedData = ReadResource.GetFromResource("RT_RCDATA");
The code gets a bit messy... hope this helps.
Although the author is dealing with his own issue right now, the SO question UpdateResource function fails has code snippet for using these calls.
The code from Samson work with String lpType, that mean you can't actually add RT_RCDATA resource either reading from it, it's only create and read lpType named "RT_RCDATA" only. If you want it to read real RT data you'll need to modify lpType from string to uint and this is RT API table:
private const uint RT_CURSOR = 0x00000001;
private const uint RT_BITMAP = 0x00000002;
private const uint RT_ICON = 0x00000003;
private const uint RT_MENU = 0x00000004;
private const uint RT_DIALOG = 0x00000005;
private const uint RT_STRING = 0x00000006;
private const uint RT_FONTDIR = 0x00000007;
private const uint RT_FONT = 0x00000008;
private const uint RT_ACCELERATOR = 0x00000009;
private const uint RT_RCDATA = 0x0000000a;
private const uint RT_MESSAGETABLE = 0x0000000b;

Categories