|
Well, the msdn documentation for this is a little mess, but I remember some time ago, after some hours of research, I read that we had to pass a two dimensional array in these cases, I mean, we have to pass int[,] for an int** parameter in the unmanaged version, though I don't remember exactly if we could pass the reference itself. I still think there is a way to avoid copying data from one place to another. This time we should import the unmanaged function, setting IntPtr as the type for the fisrt parameter. The class I told you before would change as follows:
public class ByteMatrix
{
byte[,] _matrix;
int _n;
int _m;
public ByteMatrix(int n, int m)
{
_matrix = new byte[n, m];
_n = n;
_m = m;
}
[DllImport ... whatever]
private static extern int unmanagedFunction(IntPtr array, int n, int m);
public int CallUnmanaged()
{
GCHandle handle = GCHandle.Alloc(_matrix, GCHandleType.Pinned);
int ret = unmanagedFunction(handle.AddrOfPinnedObject(), _n, _m);
handle.Free();
return ret;
}
|
|
|
|
|
1) byte[] vectors are not of equal length, it needs to use jagged array byte[][] instead but that does not work with your solution
2) byte[,] array is not C byte** array, which is array of pointers to rows, the memory is different, in unmanaged function data[0] is 0x0000000 address
It needs array of handles and pin each byte[] from the list
Чесноков
|
|
|
|
|
I've been lucky and have found it again. Here is a link[^] to the msdn documentation for this. See how they import the TestMatrixOfInts function.
I don't have time to make tests, but I am trying to help you. However, I won't be able to do so if you discard my suggestions before giving them a try. I know it may seem wrong at a first glance, but anyway a .NET bidimensional array might be internally implemented with an array of arrays.
Anyway, up to this moment I had understood that all of your byte[] arrays were the same size, but now I am not sure if that premise is correct. Is it?
Edit:
I wrote this before reading the part of the conversation with Dave about this topic. Now I have a better picture of it. The byte[] arrays are not of the same size, so a bidimensional array would not be helpful.
You have suggested stackalloc, but that is not what I recommend you. It allocates the memory in the stack, not in the heap, and that memory will be released when the method ends. Dave gave you a good advise with the IntPtr[] array, but instead of making Marshal.AllocHGlobal and Marshal.Copy you can use GCHandle, so you would not have to make a copy of the arrays into the global heap. Something like this:
int CallUnmanagedMethod(List<byte[]> lst)
{
GCHandle[] handleArray = new GCHandle[lst.Count];
for (int i=0; i<lst.Count; i++)
handleArray[i] = GCHandle.Alloc(lst[i], GCHandleType.Pinned);
IntPtr[] pointers = (from GCHandle handle in handleArray select
handle.GetAddrOfPinnedObject()).ToArray();
int ret = unmanagedMethod(pointers, ...
foreach (GCHandle handle in handleArray)
handle.Free();
return ret;
}
This method would just pin into the managed heap the byte[] arrays you have in the list, without making any copy of them, then, using GCHandle, you build an IntPtr[] array to hold the address of each one and you can make the P/Invoke call.
|
|
|
|
|
_Erik_ wrote: I don't have time to make tests, but I am trying to help you. However, I won't be able to do so if you discard my suggestions before giving them a try. I
I tried to pass either byte[][] or byte[,] directly. First is not valid to be passed.
Second does not contain pointers to its rows and in native function data[0] results in the value hold in first element in the managed array.
MSDN link you posted is useful.
I gathered from your and Dave ideas the following solution before your post
That one atually works.
http://www.codeproject.com/Messages/3740534/Re-How-to-pin-List-to-unmanaged-byte.aspx[^]
But I wanted to keep only IntPtr[] array and restore handles with GCHandle.FromIntPtr() which results in .NET message box of incorrect operation in debugger, my next post.
Чесноков
|
|
|
|
|
Yes, GCHandle is a pretty delicate thing. When a GCHandle is created it adds a new entry to the AppDomain's handle table, and this entry is kept there until Free method is invoked. The problems may arise when we create more GCHandle objects to the same target and in the same method. Remember GCHandle is also a struc, I mean, a value type, so any instance of it will be a different copy into the stack. Even if you made this:
GCHandle handle2 = handle1;
Since GCHandle is a struct, freeing handle2 would not free handle1, and this might take us to a strange situation becouse handle1's target might become a null reference, and this handle would still be in the AppDomain's handle table. This is the reason why I always try to avoid making several copies of a GCHandle.
Summarizing, it is much better to maintain the array of GCHandle objects than trying to recreate them.
|
|
|
|
|
I presume byte[][] or byte[,] layout is different.
It is not array of pointers and it is possible to avoid fixed with byte[] array
Чесноков
|
|
|
|
|
First thing(s) thats important to know is:
1) who creates the byte[]? obviously the C# side is the caller, but what I mean is, is it calling the C++ code to say "you build the buffer and give it back in this pointer", or is it saying "heres a buffer, fill it"?
2) does the C++ code need to grow or modify the array? or just read it?
3) who owns the buffer after the call? Does the C# side still own it, or does the C++ side now own it?
4) do you have control to modify the C++ side?
|
|
|
|
|
1) C# application creates those byte[] array buffers and fills them with data
2) there is no need to modify, only read it
3) C# owns them since that is the application created the
4) yes but the prefered format is array of pointers byte**
As C# application creates those buffers they are managed resources.
As they are passed as pointers C++ application can also write to them, but that is no needed.
Чесноков
|
|
|
|
|
Have you looked at Marshall.AllocHGlobal and Marshall.Copy?
|
|
|
|
|
Yes, I do not want to create a copy of the data
Чесноков
|
|
|
|
|
Too bad . You can't pass List<byte[]> to C++ byte**. byte** expects contiguous rows and you aren't giving it that. List<byte[]> is not contiguous rows of memory. Since you refuse to change either side, I don't know what to tell you.
-- Modified Thursday, January 20, 2011 3:52 PM
|
|
|
|
|
Hello Everybody,
As you know In vb.net or vb6 the On Error Resume Next is use to error handling in a function or procedure. In C# have any one for handling error?
Best Regard
If you can think then I Can.
|
|
|
|
|
Hi,
I would really not recommend you to use "On Error Resume Next", but if you really need it though you can see this article for a solution:
http://www.dotnetfunda.com/articles/article168.aspx[^]
A very basic implementation in C# that does the same would be:
try { foo; } catch {}
|
|
|
|
|
thanks sir
If you can think then I Can.
|
|
|
|
|
Such a good answer because of the question, but such a bad answer because I hate to see empty try-catches... I'm now in an argument with myself on whether to vote up or down...
I wasn't, now I am, then I won't be anymore.
|
|
|
|
|
eg_Anubhava wrote: As you know In vb.net or vb6 the On Error Resume Next is use to error handling
In VB6, that was the case. It's still usable in VB.NET, but not recommended at all.
Use Try/Catch blocks in VB.NET and C#. BTW: C# doesn't have an alternative to this.
|
|
|
|
|
This[^] might help you.
The funniest thing about this particular signature is that by the time you realise it doesn't say anything it's too late to stop reading it.
My latest tip/trick
|
|
|
|
|
On Error Resume Next was an abortion of a solution, used to help complete idiots make an even bigger mess of things than they had started with.
What it does is hide errors. Not fix them, not get rid of them, just hide them. Until they become so huge they corrupt your data, or loose hours of user work.
Imagine if you will: as simple index error:
string[] veryValuableDataFromUsers = new string[10];
veryValuableDataFromUsers [10] = myUserTextBox.Text;
foreach (string data in veryValuableDataFromUsers)
{
SaveMyData(data);
} Now, if you run this as is, an exception will be thrown when you try to access array element 10: because the array elements run from 0 to 9 inclusive. You are told what the problem is, you can can fix it in testing, all is fine.
If you had On Error Resume Next, what happens? No error. the bad index is ignored, no problem occurs.
Until the user tries to find his data, anyway.
At which point there are two problems:
1) Very annoyed user, with possibly crucial and not recoverable information lost.
2) Bug to fix, with no idea at all of how the data came to be lost. You may even blame the idiot user for "not saving it" in the first place. 100,000 lines of code to find the problem in.
Don't do it.
Exceptions are there to tell you there is a problem, and let you deal with it.
Don't use empty catch blocks.
Log exceptions in production if you can't deal with them - that way you at least have a record of what happened when you come to fix it.
But do try to handle errors correctly before they become a major problem.
Real men don't use instructions. They are only the manufacturers opinion on how to put the thing together.
|
|
|
|
|
Well us "idiots" had to use on error resume next when writing vb6 (and before) and vbscript in asp as it was our only means of catching an error due to object creation issues, etc. While it certainly opens itself up to what your refer to...if you never were "forced" to use it even in its intented purpose... not sure "idiots" apply in all cases.
'Never argue with an idiot; they'll drag you down to their level and beat you with experience.' ~ anonymous
|
|
|
|
|
No you are right, "idiots" was a little over the top.
The idiots were the designers who thought it would be a good idea in the first place! I had no problem with On Error Goto , it was the inclusion of resume next as a specific way to ignore any problem which did occur which got my back up.
Having been raised with FORTRAN compilers which had a default On Error Resume Next in that they did no error checking whatsoever (and would allow you to declare a character variable and use it as a four dimensional array of floats) I saw what damage a lack of error checking can do. It was a retrograde step to allow novices in particular to easily disable error checking with a single line of code.
Real men don't use instructions. They are only the manufacturers opinion on how to put the thing together.
|
|
|
|
|
No problem.
'Never argue with an idiot; they'll drag you down to their level and beat you with experience.' ~ anonymous
'Life's real failure is when you do not realize how close you were to success when you gave up.' ~ anonymous
|
|
|
|
|
Couldn't you have used on error goto instead?
|
|
|
|
|
eg_Anubhava wrote: As you know In vb.net or vb6 the On Error Resume Next is use to error handling
Just a tip: that was not "error handling"; that was "error swallowing". Error handling was achieved with "On Error Goto"
|
|
|
|
|
If you can narrow down the affected code to a line or two, then the following VB code:
On Error Resume Next
Foo()
can be converted to:
try
{
Foo();
}
catch
{
}
For longer code blocks, you'll have to use a separate try/empty catch for each single line of code.
David Anton
Convert between VB, C#, C++, & Java
www.tangiblesoftwaresolutions.com
modified on Tuesday, January 18, 2011 4:42 PM
|
|
|
|
|
Hey there,
I've created a component which renders a menu onto the form it's attached to. However, whenever I place controls in the region where the extension is (i'm extending the glass non-client area using the DWM API methods), it causes the designer to crash and the application itself crashes.
Naturally, I need to be able to adjust the boundaries of where controls can be placed at design and run-time. I've considered using the non-client area API methods to increase the height of the caption at design-time, but I was wondering if there's an alternate way of doing this? I've also considering changing the form's padding to suit the height of the glass extension, but this would be modifiable at design time by the user.
Thank you.
|
|
|
|
|