|
You should NOT pass an int directly as I explained - an int is 4 bytes but on a 64 bit system the function requires 8 bytes.
If you really need to pass a value directly you should create an IntPtr from it:
new IntPtr(yourInt)
By the way, the return value should also be an IntPtr.
Don't forget you can overload the method, so long as the size of the parameters are correct it won't fail.
using System;
using System.Drawing;
using System.Runtime.InteropServices;
internal static class NativeMethods
{
[DllImport("User32.dll", SetLastError = true)]
public static extern IntPtr SendMessage(
IntPtr hWnd, int Msg, IntPtr wParam, IntPtr lParam);
[DllImport("User32.dll", SetLastError = true)]
public static extern IntPtr SendMessage(
IntPtr hWnd, int Msg, IntPtr wParam, ref Size lParam);
}
Now you need to work out how to get the size back out once you receive the message, and you may need to pin the Size parameter in memory so it doesn't get moved or go out of scope and get collected...
|
|
|
|
|
ok it worked like a charm thank you soo much ,
just a question, isn't there a general way so it could only be one declaration and be able to pass any object?
modified on Friday, May 6, 2011 2:44 PM
|
|
|
|
|
That is the purpose of an IntPtr. When passing data using unmanaged memory a portion of that memory should be allocated to holding the data. The pointer to that memory location is then passed to the function. On the receiving side of the message the pointer is retrieved and the data read at that location then the memory freed. There are several ways to do this, the easiest is a combination of the BitConverter and Marshal classes.
Something like this will convert your Size to/from an IntPtr:
public static IntPtr SizeToPointer(Size size)
{
byte[] bytes = new byte[8];
Array.Copy(BitConverter.GetBytes(size.Width), 0, bytes, 0, 4);
Array.Copy(BitConverter.GetBytes(size.Height), 0, bytes, 4, 4);
IntPtr result = Marshal.AllocHGlobal(8);
Marshal.Copy(bytes, 0, result, 8);
return result;
}
public static Size PointerToSize(IntPtr pointer)
{
byte[] bytes = new byte[8];
Marshal.Copy(pointer, bytes, 0, 8);
Size result = new Size(BitConverter.ToInt32(bytes, 0), BitConverter.ToInt32(bytes, 4));
Marshal.FreeHGlobal(pointer);
return result;
}
It is very important that the memory is freed! I have done this in the PointerToSize function. If this is not called then the memory will leak.
[Edit]
I have just tested this with two forms. With both forms shown, this in form1:
NativeMethods.SendMessage(
form2.Handle, 100, IntPtr.Zero, NativeMethods.SizeToPointer(
new Size(123, 456)));
and this in form2
protected override void WndProc(ref Message m)
{
if (m.Msg == 100)
{
Size size = NativeMethods.PointerToSize(m.LParam);
MessageBox.Show(size.ToString());
}
base.WndProc(ref m);
}
The 100 was just a random number I chose for the message - it will be important to use numbers that Windows doesn't already use!
[/Edit]
[Edit2]
Check this[^] out to make sure you don't clash your message numbers.
[/Edit2]
Dave
Binging is like googling, it just feels dirtier.
Please take your VB.NET out of our nice case sensitive forum.
Astonish us. Be exceptional. (Pete O'Hanlon)
BTW, in software, hope and pray is not a viable strategy. (Luc Pattyn)
modified on Friday, May 6, 2011 3:34 PM
|
|
|
|
|
If you're not happy with all the conversions to/from byte[] then it can be done instead with a class decorated with the StructLayoutAttribute. You can wrap the size in a custom wrapper class and use two other methods of the Marshal class which makes life a bit simpler. Each field in the class must be a blittable[^] type.
public static IntPtr ConvertSizeToPointer(Size size)
{
SizeWrapper wrapper = new SizeWrapper(size);
IntPtr result = Marshal.AllocHGlobal(Marshal.SizeOf(wrapper));
Marshal.StructureToPtr(wrapper, result, true);
return result;
}
public static Size ConvertPointerToSize(IntPtr pointer)
{
SizeWrapper sizeWrapper = new SizeWrapper();
Marshal.PtrToStructure(pointer, sizeWrapper);
Marshal.FreeHGlobal(pointer);
return sizeWrapper.Size;
}
[StructLayout(LayoutKind.Sequential)]
internal class SizeWrapper
{
private int height;
private int width;
public SizeWrapper()
{ }
public SizeWrapper(Size size)
{
this.width = size.Width;
this.height = size.Height;
}
public int Height
{
get { return height; }
}
public Size Size
{
get { return new Size(width, height); }
}
public int Width
{
get { return width; }
}
}
|
|
|
|
|
manchukuo wrote: one declaration and be able to pass any object
I've been thinking about this a little more as it seemed an obvious candidate for generics. This seems to work...
using System;
using System.Drawing;
using System.Runtime.InteropServices;
internal static class NativeMethods
{
[DllImport("User32.dll", SetLastError = true)]
public static extern IntPtr SendMessage(
IntPtr hWnd, int Msg, IntPtr wParam, IntPtr lParam);
[DllImport("User32.dll", SetLastError = true)]
public static extern IntPtr SendMessage(
IntPtr hWnd, int Msg, IntPtr wParam, GCHandle lParam);
public static GCHandle CreateGCHandle<T>(T obj)
{
return GCHandle.Alloc(obj, GCHandleType.Pinned);
}
public static T GetFromPointer<T>(IntPtr pointer)
{
GCHandle gcHandle = GCHandle.FromIntPtr(pointer);
T result = (T)gcHandle.Target;
gcHandle.Free();
return result;
}
}
|
|
|
|
|
Thanks this has though me a lot,thanks for your time
|
|
|
|
|
Hello,
How do I generate random numbers, say between 1 and 10, that return all the 10 numbers without repeatedly looping? Is there a way doing that in C#?
Thanks David, Luc Pattyn, PIEBALDconsult, orc_orc_orc, Prasanta_Prince for your all your responses and appreciate your time. I'll try the solutions provided by you
Little clarification on 'Repeatedly looping' (sorry for not being clear):
Lets say that if I want to generate random numbers between 1 and n, I use, say, rand() method that returns a random value every time I call this method. But there are chances that I get duplicate numbers being generated. So I need to skip (ignore) this duplicate number since it was already generated. But there is no guarantee that the same number doesn't appear again and again. So I need to keep looping until I get all the n numbers. The number of loops could grow as n grows, say 500. Is there a way to avoid the duplicates without doing a 'check' so that I can avoid extra loops? Performance is a concern.
Again thanks for your responses.
modified on Saturday, May 7, 2011 3:38 AM
|
|
|
|
|
meet_ssr wrote: without repeatedly looping
Is one loop OK? You need at least one.
|
|
|
|
|
What exactly do you mean by "without repeatedly looping"?
If you mean "should not always repeat a sequence of length 10" then the System.Random class can do that.
If you mean "should never have the same sequence of length 10 twice in a row" then you'd have to do some bookkeeping and when you're about the generate the 10th number in what would be the second sequence you must make it unequal to the 10th byte of the actual sequence.
Or do you want to draw 10 numbers without ever repeating a previous number? In that case, the simplest way IMO is to fill an array with 1 .. 10, and then when drawing a number from it, swap the chosen number with the last element in the array you hasn't been chosen yet. That way drawing a number is constant time, requires nothing other than that one array, and it's all very easy.
|
|
|
|
|
That is not random numbers at all, that is an arbitrary permutation of a known set of numbers.
One way to achieve it is like this (in pseudo-code):
Collection coll=new Collection(holding all elements);
int n=coll.Count;
for(int i=n; i>0; i--) {
int j=RandomGenerator.Next(0, i);
int pick=coll[j];
coll.RemoveAt(j);
}
Luc Pattyn [Forum Guidelines] [My Articles] Nil Volentibus Arduum
Please use <PRE> tags for code snippets, they preserve indentation, improve readability, and make me actually look at the code.
|
|
|
|
|
I would agree, but you'd have a RemoveAt which is not at the end but "anywhere" and that's slow. Why not just swap it with the last element?
|
|
|
|
|
Yes, swapping would work fine (you already had said that).
I set out to give a simple solution and no real code; there are many ways to do it, and for most of them several optimizations are possible.
Personally, for a small number of elements, I would do it quite differently: just generating the R-th permutation algorithmically, with a single random number R (in the range 0..n!-1) and a series of divisions. No collection, no objects, just divisions. But that is not the most obvious approach...
Luc Pattyn [Forum Guidelines] [My Articles] Nil Volentibus Arduum
Please use <PRE> tags for code snippets, they preserve indentation, improve readability, and make me actually look at the code.
modified on Friday, May 6, 2011 10:12 AM
|
|
|
|
|
Ah factoradics, nice, I hadn't thought of that option for this case
|
|
|
|
|
You seem to have a univoter stuck to your backside.
|
|
|
|
|
Yea there's a whole page of univotes in my Rep History. Very odd.
Thanks for compensating
|
|
|
|
|
int maxSize = 10;
char[] chars = new char[62];
string a;
a = "1234567890";
chars = a.ToCharArray();
int size = maxSize;
byte[] data = new byte[1];
RNGCryptoServiceProvider crypto = new RNGCryptoServiceProvider();
crypto.GetNonZeroBytes(data);
size = maxSize;
data = new byte[size];
crypto.GetNonZeroBytes(data);
StringBuilder resultUID = new StringBuilder(size);
foreach (byte b in data)
{
resultUID.Append(chars[b % (chars.Length - 1)]);
}
string generatedNumber = resultUID.ToString();
This will generate a number. It will never return the same number. You can specify the length of it by changing the maxSize. You can add letters by just updating string variable "a" if you want.
|
|
|
|
|
Random rnd = new Random(seed);
int num=rnd.Next(1,10);
Hope this can help you.
|
|
|
|
|
Hello,
How do I generate random numbers, say between 1 and 10, that return all the 10 numbers without repeatedly looping? Is there a way doing that in C#?
Thanks David, Luc Pattyn, PIEBALDconsult, orc_orc_orc, Prasanta_Prince for your all your responses and appreciate your time. I'll try the solutions provided by you
Little clarification on 'Repeatedly looping' (sorry for not being clear):
Lets say that if I want to generate random numbers between 1 and n, I use, say, rand() method that returns a random value every time I call this method. But there are chances that I get duplicate numbers being generated. So I need to skip (ignore) this duplicate number since it was already generated. But there is no guarantee that the same number doesn't appear again and again. So I need to keep looping until I get all the n numbers. The number of loops could grow as n grows, say 500. Is there a way to avoid the duplicates without doing a 'check' so that I can avoid extra loops? Performance is a concern.
Again thanks for your responses.
|
|
|
|
|
Hi meet_ssr,
You can construct a List<int> object with incrementing from 0 to n (say 0 to 10: 0,1,2,3,4,5,6,7,8,9); then pop at the index given by random(). Let me show you:
private static void NonRecurrentRandomize(int capacity)
{
List<int> orderedList = new List<int>(capacity);
for (int i = 0; i < capacity; i++)
{
orderedList.Add(i);
}
Random r = new Random();
while (orderedList.Count > 0)
{
int popIndex = r.Next(0, orderedList.Count);
Console.WriteLine(orderedList[popIndex]);
orderedList.RemoveAt(popIndex);
}
}
Hope this can be useful for you. (by the way i tested it in vs 2010)
Cheers.
Ozgur Sonmez.
|
|
|
|
|
Sonmez,
This is great. It is working fine to our needs.
Thanks for that.
|
|
|
|
|
meet_ssr;
You're welcome.
Glad having helped you.
do rather than say, be rather than do.
dr.ozgur.sonmez
|
|
|
|
|
I would create a hashset and add the numbers as they're generated. Since a hashset doesn't allow duplicate keys, you could just keep generating random numbers until you have 10 hashset entries.
HashSet<int> hash = new HashSet<int>();
Random random = new Random(DateTime.Now.Milliseconds);
int value = 0;
int final = 0;
do
{
try
{
if (hash.Count == 9)
{
final++;
hash.Add(final);
}
value = random.Next(1, 10);
hash.Add(value);
}
catch (Exception)
{
}
}
while (hash.Count < 10)
".45 ACP - because shooting twice is just silly" - JSOP, 2010 ----- You can never have too much ammo - unless you're swimming, or on fire. - JSOP, 2010 ----- "Why don't you tie a kerosene-soaked rag around your ankles so the ants won't climb up and eat your candy ass." - Dale Earnhardt, 1997
|
|
|
|
|
I coded a small contest . You can download it from here[^]
In my machine result is thus:
TestHashSet() completed in
00:00:00.0380860
TestList() completed in
00:00:00.0009766
do rather than say; be rather than do.
Ozgur Sonmez.
|
|
|
|
|
I haven't looked at your test, but if you'd like to time this code, have at it. I have no idea if it's any faster or slower, but it seems almost instantaneous to me Of course, every run is going to take a different amount of time because of the random.Next() function. The code below changes the range of random numbers if possible.
HashSet<int> hash = new HashSet<int>();
Random random = new Random(DateTime.Now.Millisecond);
int value = 0;
int start = 1;
int stop = 10;
do
{
try
{
value = random.Next(start, stop);
hash.Add(value);
if (value == start)
{
start++;
}
else if (value == stop)
{
stop--;
}
if (start == stop && hash.Count < 10)
{
hash.Add(start);
}
}
catch (Exception)
{
}
} while (hash.Count < 10);
".45 ACP - because shooting twice is just silly" - JSOP, 2010 ----- You can never have too much ammo - unless you're swimming, or on fire. - JSOP, 2010 ----- "Why don't you tie a kerosene-soaked rag around your ankles so the ants won't climb up and eat your candy ass." - Dale Earnhardt, 1997
|
|
|
|
|
meet_ssr wrote: Performance is a concern
cheers.
Ozgur Sonmez.
|
|
|
|
|