473,289 Members | 2,089 Online
Bytes | Software Development & Data Engineering Community
Post Job

Home Posts Topics Members FAQ

Join Bytes to post your question to a community of 473,289 software developers and data experts.

Passing jagged array byte[][] to unmanaged code

Hi Gurus,

I need to transfer a jagged array of byte[][] by reference to unmanaged
function, The unmanaged code should changed the values of the array, and when
the unmanaged function returns I need to show the array data to the end user.

Can I do that?
How?
-------
Thanks
Sharon
Jun 13 '07 #1
17 7182
Sharon,

You are going to have to marshal this manually, as I don't think there
is a mechanism in the framework to handle this on your own.

You would have to iterate through each array of arrays, dynamically
allocating the memory in unmanaged memory, then copying the values. On
return, you would have to copy the values back.

Unsafe code would help a little bit here, as you wouldn't have to worry
about allocating and deallocating the memory (you could use stackalloc to
allocate the memory for you).
--
- Nicholas Paldino [.NET/C# MVP]
- mv*@spam.guard.caspershouse.com

"Sharon" <Sh*****@newsgroups.nospamwrote in message
news:9E**********************************@microsof t.com...
Hi Gurus,

I need to transfer a jagged array of byte[][] by reference to unmanaged
function, The unmanaged code should changed the values of the array, and
when
the unmanaged function returns I need to show the array data to the end
user.

Can I do that?
How?
-------
Thanks
Sharon

Jun 13 '07 #2
I'm afraid this kind of work will undermine the performance as there is a lot
of data to copy.
I thought there is a way to use the managed array by reference on the
unmanaged side and avoiding the memory copy.
If there is no solution for that, I think I will write some more piece of
code in native C++ (unmanaged) to do that.

--------
Thanks
Sharon
Jun 13 '07 #3
"Sharon" <Sh*****@newsgroups.nospamwrote in message
news:68**********************************@microsof t.com...
I'm afraid this kind of work will undermine the performance as there is a
lot
of data to copy.
I thought there is a way to use the managed array by reference on the
unmanaged side and avoiding the memory copy.
If there is no solution for that, I think I will write some more piece of
code in native C++ (unmanaged) to do that.

--------
Thanks
Sharon


What make you think that copying will be an issue? How large are these
array's? And why are you using an jagged array, while this kind of type
can't be handled directly in C or C++ in the first place?

Willy.

Jun 13 '07 #4

"Willy Denoyette [MVP]" <wi*************@telenet.bewrote in message
news:ey**************@TK2MSFTNGP05.phx.gbl...
"Sharon" <Sh*****@newsgroups.nospamwrote in message
news:68**********************************@microsof t.com...
>I'm afraid this kind of work will undermine the performance as there is a
lot
of data to copy.
I thought there is a way to use the managed array by reference on the
unmanaged side and avoiding the memory copy.
If there is no solution for that, I think I will write some more piece of
code in native C++ (unmanaged) to do that.

--------
Thanks
Sharon

What make you think that copying will be an issue? How large are these
array's? And why are you using an jagged array, while this kind of type
can't be handled directly in C or C++ in the first place?
C++, native as well as managed, handle jagged arrays just fine. But
unmanaged C++ can't directly handle .NET arrays of anything but fundamental
types, which includes .NET jagged arrays.

Why not change the C++ code in question to C++/CLI, then you can use the
jagged .NET array directly?

This poster also previously asked the same question on the C++ list (or
maybe it was interop), and got the same answers there.
>
Willy.
Jun 14 '07 #5
The data maybe be large as several giga bytes. and the data copy will be done
when moving it to the unmanaged code and once more when getting it back.

I'm getting a lot of System.Array that encapsulates a byte[] from a COM
component, so I thought to put this arrays (without copying) in a jagged
array of byte[][], and then letting another native C++ (unmanaged) DLL change
this jagged array for me for later use. This native C++ DLL is doing some
heavy algorithm and therefore is written in C++ and not .NET.

The original data that is read from a COM component to a managed code is
used for display and other stuff before it's moved to the C++ DLL (unmanaged
algorithm component). So I have the data in a managed memory, and should be
changed by an unmanaged code and back to the managed code.

How can I do it effectively regarding performance and development time.
Simple and effective ???
---------
Thanks
Sharon
Jun 14 '07 #6
I also believe that the best solution will be something like that.
I think that I will write an additional CLI/C++ component that will be used
as a bridge between the unmanaged code and the managed code.
---------
Thanks
Sharon
Jun 14 '07 #7
"Sharon" <Sh*****@newsgroups.nospamwrote in message
news:94**********************************@microsof t.com...
The data maybe be large as several giga bytes. and the data copy will be
done
when moving it to the unmanaged code and once more when getting it back.
Hmmm.... Several Gigabytes? Is this running on a 64-bit OS?
I'm getting a lot of System.Array that encapsulates a byte[] from a COM
component, so I thought to put this arrays (without copying) in a jagged
array of byte[][], and then letting another native C++ (unmanaged) DLL
change
this jagged array for me for later use. This native C++ DLL is doing some
heavy algorithm and therefore is written in C++ and not .NET.
Why a jagged array?
The original data that is read from a COM component to a managed code is
used for display and other stuff before it's moved to the C++ DLL
(unmanaged
algorithm component). So I have the data in a managed memory, and should
be
changed by an unmanaged code and back to the managed code.

How can I do it effectively regarding performance and development time.
Simple and effective ???

So, you are getting arrays of bytes from COM, which means that you are
already copying from native memory to managed memory. Also, the COM array is
not jagged, so why are you putting this data in a jagged array? Why not pass
the CLR byte array to C++ and let the C++ function change the array contents
without copying?

Willy.

Jun 14 '07 #8
"Ben Voigt [C++ MVP]" <rb*@nospam.nospamwrote in message
news:52**********************************@microsof t.com...
>
"Willy Denoyette [MVP]" <wi*************@telenet.bewrote in message
news:ey**************@TK2MSFTNGP05.phx.gbl...
>"Sharon" <Sh*****@newsgroups.nospamwrote in message
news:68**********************************@microso ft.com...
>>I'm afraid this kind of work will undermine the performance as there is
a lot
of data to copy.
I thought there is a way to use the managed array by reference on the
unmanaged side and avoiding the memory copy.
If there is no solution for that, I think I will write some more piece
of
code in native C++ (unmanaged) to do that.

--------
Thanks
Sharon

What make you think that copying will be an issue? How large are these
array's? And why are you using an jagged array, while this kind of type
can't be handled directly in C or C++ in the first place?

C++, native as well as managed, handle jagged arrays just fine. But
unmanaged C++ can't directly handle .NET arrays of anything but
fundamental types, which includes .NET jagged arrays.
Note that I said "this kind of type can't be handled directly in C and C++",
we are talking about C# here which implies "managed array types".
Why not change the C++ code in question to C++/CLI, then you can use the
jagged .NET array directly?
Maybe the OP can change the C++ code to C++/CLI, maybe he doesn't own the
source, or is not willing to introduce yet another language in his code
base.
This poster also previously asked the same question on the C++ list (or
maybe it was interop), and got the same answers there.
He also asked the same question several times before, and clearly said that
the "algorithm" was written by another group and had to be in unmanaged
code.

Willy.

Jun 14 '07 #9

"Willy Denoyette [MVP]" <wi*************@telenet.bewrote in message
news:e3**************@TK2MSFTNGP05.phx.gbl...
"Sharon" <Sh*****@newsgroups.nospamwrote in message
news:94**********************************@microsof t.com...
>The data maybe be large as several giga bytes. and the data copy will be
done
when moving it to the unmanaged code and once more when getting it back.

Hmmm.... Several Gigabytes? Is this running on a 64-bit OS?
>I'm getting a lot of System.Array that encapsulates a byte[] from a COM
component, so I thought to put this arrays (without copying) in a jagged
array of byte[][], and then letting another native C++ (unmanaged) DLL
change
this jagged array for me for later use. This native C++ DLL is doing some
heavy algorithm and therefore is written in C++ and not .NET.

Why a jagged array?
Simply an array of arrays. Jagged, because each member array can have a
different size.
>
>The original data that is read from a COM component to a managed code is
used for display and other stuff before it's moved to the C++ DLL
(unmanaged
algorithm component). So I have the data in a managed memory, and should
be
changed by an unmanaged code and back to the managed code.

How can I do it effectively regarding performance and development time.
Simple and effective ???
Stop receiving the COM array into a .NET array. Store each SAFEARRAY* as an
element in an array of IntPtr instead. Then give that IntPtr array to the
unmanaged code.
>

So, you are getting arrays of bytes from COM, which means that you are
already copying from native memory to managed memory. Also, the COM array
is not jagged, so why are you putting this data in a jagged array? Why not
pass
Each incoming array is one-dimensional, apparently. Knowing what jagged
means helps here.
the CLR byte array to C++ and let the C++ function change the array
contents without copying?
If the arrays coming from COM are allocated scattered throughout memory,
then it can't be passed as a single native array. It will have to be an
array of pointers.
>
Willy.

Jun 15 '07 #10
"Ben Voigt [C++ MVP]" <rb*@nospam.nospamwrote in message
news:ua**************@TK2MSFTNGP03.phx.gbl...
>
"Willy Denoyette [MVP]" <wi*************@telenet.bewrote in message
news:e3**************@TK2MSFTNGP05.phx.gbl...
>"Sharon" <Sh*****@newsgroups.nospamwrote in message
news:94**********************************@microso ft.com...
>>The data maybe be large as several giga bytes. and the data copy will be
done
when moving it to the unmanaged code and once more when getting it back.

Hmmm.... Several Gigabytes? Is this running on a 64-bit OS?
>>I'm getting a lot of System.Array that encapsulates a byte[] from a COM
component, so I thought to put this arrays (without copying) in a jagged
array of byte[][], and then letting another native C++ (unmanaged) DLL
change
this jagged array for me for later use. This native C++ DLL is doing
some
heavy algorithm and therefore is written in C++ and not .NET.

Why a jagged array?

Simply an array of arrays. Jagged, because each member array can have a
different size.
I know what a managed jagged array is, you can not pass such type from C#
(or any other managed code) to C++ , even if you could, C++ cannot directly
access *managed* jagged arrays, it has no idea how they are laid out in
memory.

>>
>>The original data that is read from a COM component to a managed code is
used for display and other stuff before it's moved to the C++ DLL
(unmanaged
algorithm component). So I have the data in a managed memory, and should
be
changed by an unmanaged code and back to the managed code.

How can I do it effectively regarding performance and development time.
Simple and effective ???

Stop receiving the COM array into a .NET array. Store each SAFEARRAY* as
an element in an array of IntPtr instead. Then give that IntPtr array to
the unmanaged code.
>>

So, you are getting arrays of bytes from COM, which means that you are
already copying from native memory to managed memory. Also, the COM array
is not jagged, so why are you putting this data in a jagged array? Why
not pass

Each incoming array is one-dimensional, apparently. Knowing what jagged
means helps here.
Again, I know what a *managed* jagged array is, it's a type that is not know
by C++.
>the CLR byte array to C++ and let the C++ function change the array
contents without copying?

If the arrays coming from COM are allocated scattered throughout memory,
then it can't be passed as a single native array. It will have to be an
array of pointers.
In the OP's case, the array that comes from COM is a one-dimentional byte
array, as such it gets marshaled as a one-dimentional managed array, so COM
is a non issue here.

What the OP can do is store the address of each individual array in an array
of IntPtr and pass that array to C++ together with an array that defines the
size of each array pointed to by the pointers in the array of pointers, and
a third parameter that defines the size of the array of pointers, but that
's not the same as passing a jagged array.

The signature could look something like this:

[DllImport("blabala")]
static extern Foo(IntPtr[] ptr, int[] sizeOfElem, int elem);

however, this is not possible:

[DllImport("blabala")]
static extern Foo(byte[][] ptr);

See what I mean?

Willy.


Jun 15 '07 #11

"Willy Denoyette [MVP]" <wi*************@telenet.bewrote in message
news:u$**************@TK2MSFTNGP05.phx.gbl...
"Ben Voigt [C++ MVP]" <rb*@nospam.nospamwrote in message
news:ua**************@TK2MSFTNGP03.phx.gbl...
>>
"Willy Denoyette [MVP]" <wi*************@telenet.bewrote in message
news:e3**************@TK2MSFTNGP05.phx.gbl...
>>"Sharon" <Sh*****@newsgroups.nospamwrote in message
news:94**********************************@micros oft.com...
The data maybe be large as several giga bytes. and the data copy will
be done
when moving it to the unmanaged code and once more when getting it
back.
Hmmm.... Several Gigabytes? Is this running on a 64-bit OS?

I'm getting a lot of System.Array that encapsulates a byte[] from a COM
component, so I thought to put this arrays (without copying) in a
jagged
array of byte[][], and then letting another native C++ (unmanaged) DLL
change
this jagged array for me for later use. This native C++ DLL is doing
some
heavy algorithm and therefore is written in C++ and not .NET.
Why a jagged array?

Simply an array of arrays. Jagged, because each member array can have a
different size.

I know what a managed jagged array is, you can not pass such type from C#
(or any other managed code) to C++ , even if you could, C++ cannot
directly access *managed* jagged arrays, it has no idea how they are laid
out in memory.

>>>
The original data that is read from a COM component to a managed code
is
used for display and other stuff before it's moved to the C++ DLL
(unmanaged
algorithm component). So I have the data in a managed memory, and
should be
changed by an unmanaged code and back to the managed code.

How can I do it effectively regarding performance and development time.
Simple and effective ???

Stop receiving the COM array into a .NET array. Store each SAFEARRAY* as
an element in an array of IntPtr instead. Then give that IntPtr array to
the unmanaged code.
>>>

So, you are getting arrays of bytes from COM, which means that you are
already copying from native memory to managed memory. Also, the COM
array is not jagged, so why are you putting this data in a jagged array?
Why not pass

Each incoming array is one-dimensional, apparently. Knowing what jagged
means helps here.
Again, I know what a *managed* jagged array is, it's a type that is not
know by C++.
>>the CLR byte array to C++ and let the C++ function change the array
contents without copying?

If the arrays coming from COM are allocated scattered throughout memory,
then it can't be passed as a single native array. It will have to be an
array of pointers.

In the OP's case, the array that comes from COM is a one-dimentional byte
array, as such it gets marshaled as a one-dimentional managed array, so
COM is a non issue here.

What the OP can do is store the address of each individual array in an
array of IntPtr and pass that array to C++ together with an array that
defines the size of each array pointed to by the pointers in the array of
pointers, and a third parameter that defines the size of the array of
pointers, but that 's not the same as passing a jagged array.
That *is* a jagged array. Any array of arrays is a jagged array, all
languages support the concept. P/Invoke cannot pass an array of
non-fundamental types and a .NET array is not a fundamental type. So native
C++ can't use a managed jagged array.
>
The signature could look something like this:

[DllImport("blabala")]
static extern Foo(IntPtr[] ptr, int[] sizeOfElem, int elem);
That is a native jagged array being passed. Now, instead of unmarshalling
the data from SAFEARRAY to a .NET array, and using Marshal to make a copy in
HGLOBAL memory, why not just store the SAFEARRAY* in the array, if the data
is just going to be passed back to unmanaged code?
>
however, this is not possible:

[DllImport("blabala")]
static extern Foo(byte[][] ptr);

See what I mean?

Willy.

Jun 15 '07 #12
"Ben Voigt [C++ MVP]" <rb*@nospam.nospamwrote in message
news:78**********************************@microsof t.com...
>
"Willy Denoyette [MVP]" <wi*************@telenet.bewrote in message
news:u$**************@TK2MSFTNGP05.phx.gbl...
>"Ben Voigt [C++ MVP]" <rb*@nospam.nospamwrote in message
news:ua**************@TK2MSFTNGP03.phx.gbl...
>>>
"Willy Denoyette [MVP]" <wi*************@telenet.bewrote in message
news:e3**************@TK2MSFTNGP05.phx.gbl...
"Sharon" <Sh*****@newsgroups.nospamwrote in message
news:94**********************************@micro soft.com...
The data maybe be large as several giga bytes. and the data copy will
be done
when moving it to the unmanaged code and once more when getting it
back.
>

Hmmm.... Several Gigabytes? Is this running on a 64-bit OS?

I'm getting a lot of System.Array that encapsulates a byte[] from a
COM
component, so I thought to put this arrays (without copying) in a
jagged
array of byte[][], and then letting another native C++ (unmanaged) DLL
change
this jagged array for me for later use. This native C++ DLL is doing
some
heavy algorithm and therefore is written in C++ and not .NET.
>

Why a jagged array?

Simply an array of arrays. Jagged, because each member array can have a
different size.

I know what a managed jagged array is, you can not pass such type from C#
(or any other managed code) to C++ , even if you could, C++ cannot
directly access *managed* jagged arrays, it has no idea how they are laid
out in memory.

>>>>
The original data that is read from a COM component to a managed code
is
used for display and other stuff before it's moved to the C++ DLL
(unmanaged
algorithm component). So I have the data in a managed memory, and
should be
changed by an unmanaged code and back to the managed code.
>
How can I do it effectively regarding performance and development
time.
Simple and effective ???

Stop receiving the COM array into a .NET array. Store each SAFEARRAY*
as an element in an array of IntPtr instead. Then give that IntPtr
array to the unmanaged code.

So, you are getting arrays of bytes from COM, which means that you are
already copying from native memory to managed memory. Also, the COM
array is not jagged, so why are you putting this data in a jagged
array? Why not pass

Each incoming array is one-dimensional, apparently. Knowing what jagged
means helps here.
Again, I know what a *managed* jagged array is, it's a type that is not
know by C++.
>>>the CLR byte array to C++ and let the C++ function change the array
contents without copying?

If the arrays coming from COM are allocated scattered throughout memory,
then it can't be passed as a single native array. It will have to be an
array of pointers.

In the OP's case, the array that comes from COM is a one-dimentional byte
array, as such it gets marshaled as a one-dimentional managed array, so
COM is a non issue here.

What the OP can do is store the address of each individual array in an
array of IntPtr and pass that array to C++ together with an array that
defines the size of each array pointed to by the pointers in the array of
pointers, and a third parameter that defines the size of the array of
pointers, but that 's not the same as passing a jagged array.

That *is* a jagged array. Any array of arrays is a jagged array, all
languages support the concept. P/Invoke cannot pass an array of
non-fundamental types and a .NET array is not a fundamental type. So
native C++ can't use a managed jagged array.
When I'm talking of jagged arrays I'm referring to an array type defined in
the CLI (CLR), I don't know if the C or C++ standard has a definition for
"jagged arrays", but "jagged arrays" on the CLR, are arrays of arrays,
right, but the constituent arrays don't need to be of the same size.

For instance the following illustrates how you can define and access a
jagged array of int C#:
int jagged [][] = new int[][]{
new int[]{1, 2, 3, 4},
new int[]{4, 5, 6}
};
jagged[0][2] = 100;
jagged[1][2] = 5;
...
how you can you define and access such an array type in C/C++, note I'm not
asking for an array of pointers.

>>
The signature could look something like this:

[DllImport("blabala")]
static extern Foo(IntPtr[] ptr, int[] sizeOfElem, int elem);

That is a native jagged array being passed.
How that?, the first argument is an array of IntPtr, marshaled as an array
of pointers, or do you mean that what is passed collectively defines an
array of arrays.

Now, instead of unmarshalling
the data from SAFEARRAY to a .NET array, and using Marshal to make a copy
in HGLOBAL memory, why not just store the SAFEARRAY* in the array, if the
data is just going to be passed back to unmanaged code?
I didn't say he should make a copy to "unmanaged" memory, I said he could
take the address of each individualy array store it in an array of IntPtr
(or void*) and pass that array to C++, something like this:

[DllImport("blabla.dll"), SuppressUnmanagedCodeSecurity] extern static
void Foo(IntPtr[] ia, int[] elems, int size);
...
// say jagged is an array that holds the marshaled COM arrays (be it
conforming or SAFEARRAY's is not the issue)
byte[][] jagged = new byte[][];
jagged[0] = CallCOM(); // returns an array of bytes.
jagged[1] = .......
.....
unsafe
{
IntPtr[] ptrArray = new IntPtr[jagged.Length];
int[] elems = new int[jagged.Length];
for(int n = 0; n < jagged.Length; n++)
{
fixed(byte* p = &jagged[n][0])
{
ptrArray[n] = new IntPtr(p);
elems[n] = jagged[n].Length;
}
}
Foo(ptrArray, elems, jagged.Length); // call "native code" that
changes the contents of jagged ... inline...
}
....

Willy.


Jun 15 '07 #13

"Willy Denoyette [MVP]" <wi*************@telenet.bewrote in message
news:el**************@TK2MSFTNGP04.phx.gbl...
"Ben Voigt [C++ MVP]" <rb*@nospam.nospamwrote in message
news:78**********************************@microsof t.com...
>>
"Willy Denoyette [MVP]" <wi*************@telenet.bewrote in message
news:u$**************@TK2MSFTNGP05.phx.gbl...
>>"Ben Voigt [C++ MVP]" <rb*@nospam.nospamwrote in message
news:ua**************@TK2MSFTNGP03.phx.gbl...

"Willy Denoyette [MVP]" <wi*************@telenet.bewrote in message
news:e3**************@TK2MSFTNGP05.phx.gbl...
"Sharon" <Sh*****@newsgroups.nospamwrote in message
news:94**********************************@micr osoft.com...
>The data maybe be large as several giga bytes. and the data copy will
>be done
>when moving it to the unmanaged code and once more when getting it
>back.
>>
>
Hmmm.... Several Gigabytes? Is this running on a 64-bit OS?
>
>I'm getting a lot of System.Array that encapsulates a byte[] from a
>COM
>component, so I thought to put this arrays (without copying) in a
>jagged
>array of byte[][], and then letting another native C++ (unmanaged)
>DLL change
>this jagged array for me for later use. This native C++ DLL is doing
>some
>heavy algorithm and therefore is written in C++ and not .NET.
>>
>
Why a jagged array?

Simply an array of arrays. Jagged, because each member array can have
a different size.
I know what a managed jagged array is, you can not pass such type from
C# (or any other managed code) to C++ , even if you could, C++ cannot
directly access *managed* jagged arrays, it has no idea how they are
laid out in memory.
>
>The original data that is read from a COM component to a managed code
>is
>used for display and other stuff before it's moved to the C++ DLL
>(unmanaged
>algorithm component). So I have the data in a managed memory, and
>should be
>changed by an unmanaged code and back to the managed code.
>>
>How can I do it effectively regarding performance and development
>time.
>Simple and effective ???

Stop receiving the COM array into a .NET array. Store each SAFEARRAY*
as an element in an array of IntPtr instead. Then give that IntPtr
array to the unmanaged code.

>
>
So, you are getting arrays of bytes from COM, which means that you are
already copying from native memory to managed memory. Also, the COM
array is not jagged, so why are you putting this data in a jagged
array? Why not pass

Each incoming array is one-dimensional, apparently. Knowing what
jagged means helps here.

Again, I know what a *managed* jagged array is, it's a type that is not
know by C++.

the CLR byte array to C++ and let the C++ function change the array
contents without copying?

If the arrays coming from COM are allocated scattered throughout
memory, then it can't be passed as a single native array. It will have
to be an array of pointers.
In the OP's case, the array that comes from COM is a one-dimentional
byte array, as such it gets marshaled as a one-dimentional managed
array, so COM is a non issue here.

What the OP can do is store the address of each individual array in an
array of IntPtr and pass that array to C++ together with an array that
defines the size of each array pointed to by the pointers in the array
of pointers, and a third parameter that defines the size of the array
of pointers, but that 's not the same as passing a jagged array.

That *is* a jagged array. Any array of arrays is a jagged array, all
languages support the concept. P/Invoke cannot pass an array of
non-fundamental types and a .NET array is not a fundamental type. So
native C++ can't use a managed jagged array.

When I'm talking of jagged arrays I'm referring to an array type defined
in the CLI (CLR), I don't know if the C or C++ standard has a definition
for "jagged arrays", but "jagged arrays" on the CLR, are arrays of arrays,
right, but the constituent arrays don't need to be of the same size.

For instance the following illustrates how you can define and access a
jagged array of int C#:
int jagged [][] = new int[][]{
new int[]{1, 2, 3, 4},
new int[]{4, 5, 6}
};
jagged[0][2] = 100;
jagged[1][2] = 5;
...
how you can you define and access such an array type in C/C++, note I'm
not asking for an array of pointers.
In C++, arrays and pointers are interchangable (except for sizeof), so an
array of pointers is an array of arrays. You can of course have an array
object which combines the pointer and the length information, so a C++
jagged array could also look like: std::vector<std::vector<int>*>
>
>>>
The signature could look something like this:

[DllImport("blabala")]
static extern Foo(IntPtr[] ptr, int[] sizeOfElem, int elem);

That is a native jagged array being passed.
How that?, the first argument is an array of IntPtr, marshaled as an array
of pointers, or do you mean that what is passed collectively defines an
array of arrays.

Now, instead of unmarshalling
>the data from SAFEARRAY to a .NET array, and using Marshal to make a copy
in HGLOBAL memory, why not just store the SAFEARRAY* in the array, if the
data is just going to be passed back to unmanaged code?

I didn't say he should make a copy to "unmanaged" memory, I said he could
take the address of each individualy array store it in an array of IntPtr
(or void*) and pass that array to C++, something like this:

[DllImport("blabla.dll"), SuppressUnmanagedCodeSecurity] extern static
void Foo(IntPtr[] ia, int[] elems, int size);
...
// say jagged is an array that holds the marshaled COM arrays (be it
conforming or SAFEARRAY's is not the issue)
byte[][] jagged = new byte[][];
jagged[0] = CallCOM(); // returns an array of bytes.
jagged[1] = .......
.....
unsafe
{
IntPtr[] ptrArray = new IntPtr[jagged.Length];
int[] elems = new int[jagged.Length];
for(int n = 0; n < jagged.Length; n++)
{
fixed(byte* p = &jagged[n][0])
{
ptrArray[n] = new IntPtr(p);
elems[n] = jagged[n].Length;
}
}
Foo(ptrArray, elems, jagged.Length); // call "native code" that
changes the contents of jagged ... inline...
}
...

Willy.

Jun 15 '07 #14
"Ben Voigt [C++ MVP]" <rb*@nospam.nospamwrote in message
news:36**********************************@microsof t.com...
>
"Willy Denoyette [MVP]" <wi*************@telenet.bewrote in message
news:el**************@TK2MSFTNGP04.phx.gbl...
>"Ben Voigt [C++ MVP]" <rb*@nospam.nospamwrote in message
news:78**********************************@microso ft.com...
>>>
"Willy Denoyette [MVP]" <wi*************@telenet.bewrote in message
news:u$**************@TK2MSFTNGP05.phx.gbl...
"Ben Voigt [C++ MVP]" <rb*@nospam.nospamwrote in message
news:ua**************@TK2MSFTNGP03.phx.gbl...
>
"Willy Denoyette [MVP]" <wi*************@telenet.bewrote in message
news:e3**************@TK2MSFTNGP05.phx.gbl.. .
>"Sharon" <Sh*****@newsgroups.nospamwrote in message
>news:94**********************************@mic rosoft.com...
>>The data maybe be large as several giga bytes. and the data copy
>>will be done
>>when moving it to the unmanaged code and once more when getting it
>>back.
>>>
>>
>Hmmm.... Several Gigabytes? Is this running on a 64-bit OS?
>>
>>I'm getting a lot of System.Array that encapsulates a byte[] from a
>>COM
>>component, so I thought to put this arrays (without copying) in a
>>jagged
>>array of byte[][], and then letting another native C++ (unmanaged)
>>DLL change
>>this jagged array for me for later use. This native C++ DLL is doing
>>some
>>heavy algorithm and therefore is written in C++ and not .NET.
>>>
>>
>Why a jagged array?
>
Simply an array of arrays. Jagged, because each member array can have
a different size.
>

I know what a managed jagged array is, you can not pass such type from
C# (or any other managed code) to C++ , even if you could, C++ cannot
directly access *managed* jagged arrays, it has no idea how they are
laid out in memory.
>>
>>The original data that is read from a COM component to a managed
>>code is
>>used for display and other stuff before it's moved to the C++ DLL
>>(unmanaged
>>algorithm component). So I have the data in a managed memory, and
>>should be
>>changed by an unmanaged code and back to the managed code.
>>>
>>How can I do it effectively regarding performance and development
>>time.
>>Simple and effective ???
>
Stop receiving the COM array into a .NET array. Store each SAFEARRAY*
as an element in an array of IntPtr instead. Then give that IntPtr
array to the unmanaged code.
>
>>
>>
>So, you are getting arrays of bytes from COM, which means that you
>are already copying from native memory to managed memory. Also, the
>COM array is not jagged, so why are you putting this data in a jagged
>array? Why not pass
>
Each incoming array is one-dimensional, apparently. Knowing what
jagged means helps here.
>
Again, I know what a *managed* jagged array is, it's a type that is not
know by C++.

>the CLR byte array to C++ and let the C++ function change the array
>contents without copying?
>
If the arrays coming from COM are allocated scattered throughout
memory, then it can't be passed as a single native array. It will
have to be an array of pointers.
>

In the OP's case, the array that comes from COM is a one-dimentional
byte array, as such it gets marshaled as a one-dimentional managed
array, so COM is a non issue here.

What the OP can do is store the address of each individual array in an
array of IntPtr and pass that array to C++ together with an array that
defines the size of each array pointed to by the pointers in the array
of pointers, and a third parameter that defines the size of the array
of pointers, but that 's not the same as passing a jagged array.

That *is* a jagged array. Any array of arrays is a jagged array, all
languages support the concept. P/Invoke cannot pass an array of
non-fundamental types and a .NET array is not a fundamental type. So
native C++ can't use a managed jagged array.

When I'm talking of jagged arrays I'm referring to an array type defined
in the CLI (CLR), I don't know if the C or C++ standard has a definition
for "jagged arrays", but "jagged arrays" on the CLR, are arrays of
arrays, right, but the constituent arrays don't need to be of the same
size.

For instance the following illustrates how you can define and access a
jagged array of int C#:
int jagged [][] = new int[][]{
new int[]{1, 2, 3, 4},
new int[]{4, 5, 6}
};
jagged[0][2] = 100;
jagged[1][2] = 5;
...
how you can you define and access such an array type in C/C++, note I'm
not asking for an array of pointers.

In C++, arrays and pointers are interchangable (except for sizeof), so an
array of pointers is an array of arrays. You can of course have an array
object which combines the pointer and the length information, so a C++
jagged array could also look like: std::vector<std::vector<int>*>

I expected this :-).
It's not because you can "construct" something that looks and behaves like a
"jagged" array in C++ that they are the same as managed "jagged arrays", a
"jagged array" is a well defined language feature in .NET (all managed
languages including C++/CLI) with well defined language syntax rules and
based on a CLS compliant type from the CTS, and this is not true in C++.
in C#
int[3][] ja;
ja is a jagged array.

which is not possible in C++
int ja[3][];
will not compile.....
and
int ja[3][5];

is a two dimentional rectangular array, an array of arrays, but it's not a
jagged array!

Anyway, what's important here and what the OP is after, is that they can be
passed and accessed *directly* across the managed/unmanaged language (here
C# and C++) boundaries *without* the need to resort to some kind of custom
marshaling (like I've illustrated), and we both know that this is not the
case, right?

Willy.

Jun 16 '07 #15
>In C++, arrays and pointers are interchangable (except for sizeof), so an
array of pointers is an array of arrays. You can of course have an array
object which combines the pointer and the length information, so a C++
jagged array could also look like: std::vector<std::vector<int>*>


I expected this :-).
It's not because you can "construct" something that looks and behaves like
a "jagged" array in C++ that they are the same as managed "jagged arrays",
a "jagged array" is a well defined language feature in .NET (all managed
No, it's not. It's composition of two features: an array is an object, and
having arrays of objects.
languages including C++/CLI) with well defined language syntax rules and
Then what is the syntax for a managed jagged array in C++/CLI? Oh, it's
something like:

cli::array<cli::array<int>^>^
based on a CLS compliant type from the CTS, and this is not true in C++.
in C#
int[3][] ja;
ja is a jagged array.

which is not possible in C++
int ja[3][];
The omitted dimension syntax is accepted in C and C++, but means something
entirely different. And I think it is the first dimension omitted, not the
last.
will not compile.....
and
int ja[3][5];

is a two dimentional rectangular array, an array of arrays, but it's not a
jagged array!
No, it's not an array of arrays at all. It is a single array, and can be
treated interchangeable as a 3x5 array, a 5x3 array, or a 15 element
one-dimensional array.

int ja1[5], ja2[5], ja3[5];
int* ja[] = { ja1, ja2, ja3 };

is an array of arrays.

Or, if you want to nitpick that this is an array of pointers,

int (&ja[])[5] = { ja1, ja2, ja3 };

Which is an array of arrays, but cannot be jagged.
>
Anyway, what's important here and what the OP is after, is that they can
be passed and accessed *directly* across the managed/unmanaged language
(here C# and C++) boundaries *without* the need to resort to some kind of
custom marshaling (like I've illustrated), and we both know that this is
not the case, right?
P/invoke can't handle arrays of ref class types, and an array is a ref
class, so no, p/invoke can't do an array of arrays (or array of lists, or
list of arrays, or array of strings, or ...). Jagged arrays aren't a
special case in any sense.
>
Willy.
Jun 16 '07 #16
"Ben Voigt [C++ MVP]" <rb*@nospam.nospamwrote in message
news:BD**********************************@microsof t.com...
>
>>In C++, arrays and pointers are interchangable (except for sizeof), so
an
array of pointers is an array of arrays. You can of course have an
array object which combines the pointer and the length information, so a
C++ jagged array could also look like: std::vector<std::vector<int>*>


I expected this :-).
It's not because you can "construct" something that looks and behaves
like a "jagged" array in C++ that they are the same as managed "jagged
arrays", a "jagged array" is a well defined language feature in .NET (all
managed

No, it's not. It's composition of two features: an array is an object,
and having arrays of objects.
Are you telling me that "jagged arrays" are not a .NET language concept
based on a well defined type in the type system and the CLR (CLI)?

The element type and shape of an array—including whether it is *jagged* or
*rectangular*, and the number of dimensions it has—are part of its type.
That why I keep saying that the declaration int[][] declares a distinct well
know array type!

Consider following snippets:

[1] An array of objects having an arrays of objects having an arrays of...
object[] oa = new object[2];
object[] oaa = new object[4];
oa[0] = oaa; // oa is an array of objects of array of objects
// Obviously the following is not possible, oa is not a jagged array
// oa[0][0] = new byte[4] {0, 2, 4, 6}; // NOT possible
// Following is OK.
oaa[0] = new byte[4] {0, 2, 4, 6};

Here 'oa' Defines an System.Object[] with Rank = 1, holding 2 elements of
element type CLASS (ELEMENT_TYPE_CLASS to be precise),
element oa[0] holds a System.Object[] with Rank = 1, holding 4 elements of
element type is CLASS (ELEMENT_TYPE_CLASS),
element oaa[0] Defines an System.Byte[] with Rank = 1, holding 4 elements of
element type Byte(ELEMENT_TYPE_BYTE)

[2]
string[] sa = new string[2];
sa[0] = "somestring";
Here 'sa' defines an System.String[] with Rank = 1, holding 4 elements of
element type CLASS (ELEMENT_TYPE_CLASS)

[3]

byte[,] nonJagged = new byte[4,5];
nonJagged[0,0] = 100;
nonJagged[1,1] = 200;
Here 'sa' defines an System.Byte[] with Rank = 2, holding 20 elements of
element type Byte(ELEMENT_TYPE_BYTE)
Notice Rank=2, This is a multi-dimentional rectangular array.

[4]

byte[][][] jagged = new byte[4][][];
jagged[0] = new byte[1][] {
new byte[4] {1, 2, 3, 4}};
jagged[1] ....

Here 'jagged' defines an System.Byte[][][] with Rank = 1, holding 4 elements
of element type SZARRAY(ELEMENT_TYPE_SZARRAY),
jagged[0] defines an System.Byte[][] with Rank = 1, holding 1 elements of
element type SZARRAY(ELEMENT_TYPE_SZARRAY)
and the element jagged[0] holds a reference to a
System.Byte[] with Rank = 1, holding 4 elements of element type
Byte(ELEMENT_TYPE_BYTE)

Take a look at the run-time type [4] above and notice the Element type
SZARRAY for the jagged array "jagged", SZARRAY is s type that indicates a
vector, an array with 0 bound and *no* upper bound. This is the way by which
the CLR makes a distiction between a "jagged array" and other array types,
the CLR treats them differently from the other types.
If you look at the snip in [3], you'll see the Rank being 2, which is the
way by which the CLR distincts multi-dimentional arrays from other array
types. You can't have an array with Rank 1 and Element type SZARRAY.

[2 ]show a regular array, that is Rank = 1 and Element type = CLASS.

[1] and [2] both define an array of element type CLASS, that means that they
are of the same Class (Execution Class) as such their instances point to the
same Method table, but the Class of [4] , is different from [1] (an array of
arrays of ...), so is it's Method table. The same is tru for [3] which is
treated differently as the others, this is reflected by it's Execution Class
which differs from the others.
See what I mean now?

>languages including C++/CLI) with well defined language syntax rules and

Then what is the syntax for a managed jagged array in C++/CLI? Oh, it's
something like:

cli::array<cli::array<int>^>^
Not sure what you mean by this...
Anyway, make it:
array<array<Int32>^>^ local = gcnew array<array< Int32 >^>(2);
or:
array<array<array<Int32>^>^>^ local1 = gcnew array<array<array< Int32
>^>^>(2);
to show that *only* one dimension (the first) can be specified, here we
declare "jagged arrays", using well defined language declaration syntax,
every
language has his own syntax, but finaly it boils down to the same thing.
>based on a CLS compliant type from the CTS, and this is not true in C++.
in C#
int[3][] ja;
ja is a jagged array.

which is not possible in C++
int ja[3][];

The omitted dimension syntax is accepted in C and C++, but means something
entirely different. And I think it is the first dimension omitted, not
the last.
That's exactly the point, the you can ommit the first dimentions, never the
last, that means that you can only define a rectangular array using that
array syntax in C++. A jagged array *may* not specify the last dimension
>will not compile.....
and
int ja[3][5];

is a two dimentional rectangular array, an array of arrays, but it's not
a jagged array!

No, it's not an array of arrays at all.
Right, my bad, no array of arrays, a two dimentional rectangular array, but
no jagged array.

It is a single array, and can be
treated interchangeable as a 3x5 array, a 5x3 array, or a 15 element
one-dimensional array.

int ja1[5], ja2[5], ja3[5];
int* ja[] = { ja1, ja2, ja3 };

is an array of arrays.
Right, still no jagged array.
Or, if you want to nitpick that this is an array of pointers,

int (&ja[])[5] = { ja1, ja2, ja3 };

Which is an array of arrays, but cannot be jagged.
Right, no jagged array.
>>
Anyway, what's important here and what the OP is after, is that they can
be passed and accessed *directly* across the managed/unmanaged language
(here C# and C++) boundaries *without* the need to resort to some kind of
custom marshaling (like I've illustrated), and we both know that this is
not the case, right?

P/invoke can't handle arrays of ref class types, and an array is a ref
class, so no, p/invoke can't do an array of arrays (or array of lists, or
list of arrays, or array of strings, or ...). Jagged arrays aren't a
special case in any sense.
Did I ever said otherwise?
It was me who said you can't pass a "jagged arrays" to C++, the PInvoke
marshaler has no knowlege on how to represent this type as an "unmanaged"
type (without creating a "new" kind of type of course).
That's why I asked the OP "why trying to pass a jagged array to C++". It
was me (and Nicholas) who said that the OP could pass a reference to a
single dimensional array or he should apply some custom marshaling, right?

Willy.
Jun 18 '07 #17
Are you telling me that "jagged arrays" are not a .NET language concept
based on a well defined type in the type system and the CLR (CLI)?
That is exactly what I am telling you. There is no concept of a jagged
array in the .NET runtime. What is a .NET language concept? .NET is an IL
runtime, not a language. It doesn't specify anything about the language.

C# may have special syntax for jagged arrays (I don't rightly remember, I
would have to look closely to see whether the dimensions are reversed in the
declaration), but translates them into a fundamental type: .NET array. The
element type of this array is itself an array type. There is no special
behavior from the .NET runtime.
>
The element type and shape of an array—including whether it is *jagged* or
*rectangular*, and the number of dimensions it has—are part of its type.
That why I keep saying that the declaration int[][] declares a distinct
well know array type!
Not distinct from object[] or string[]. It is basically a generic type
where the type argument is int[] (except that arrays were generic before the
runtime had support for arbitrary generic types).
>
Consider following snippets:

[1] An array of objects having an arrays of objects having an arrays of...
object[] oa = new object[2];
object[] oaa = new object[4];
oa[0] = oaa; // oa is an array of objects of array of objects
// Obviously the following is not possible, oa is not a jagged array
// oa[0][0] = new byte[4] {0, 2, 4, 6}; // NOT possible
Only because you have weak typing. This would work:

((object[])oa[0])[0] = new byte[4] { 0, 2, 4, 6 };
// Following is OK.
oaa[0] = new byte[4] {0, 2, 4, 6};

Here 'oa' Defines an System.Object[] with Rank = 1, holding 2 elements of
element type CLASS (ELEMENT_TYPE_CLASS to be precise),
element oa[0] holds a System.Object[] with Rank = 1, holding 4 elements of
element type is CLASS (ELEMENT_TYPE_CLASS),
element oaa[0] Defines an System.Byte[] with Rank = 1, holding 4 elements
of element type Byte(ELEMENT_TYPE_BYTE)

[2]
string[] sa = new string[2];
sa[0] = "somestring";
Here 'sa' defines an System.String[] with Rank = 1, holding 4 elements of
element type CLASS (ELEMENT_TYPE_CLASS)

[3]

byte[,] nonJagged = new byte[4,5];
nonJagged[0,0] = 100;
nonJagged[1,1] = 200;
Here 'sa' defines an System.Byte[] with Rank = 2, holding 20 elements of
element type Byte(ELEMENT_TYPE_BYTE)
Notice Rank=2, This is a multi-dimentional rectangular array.

[4]

byte[][][] jagged = new byte[4][][];
jagged[0] = new byte[1][] {
new byte[4] {1, 2, 3, 4}};
jagged[1] ....

Here 'jagged' defines an System.Byte[][][] with Rank = 1, holding 4
elements of element type SZARRAY(ELEMENT_TYPE_SZARRAY),
jagged[0] defines an System.Byte[][] with Rank = 1, holding 1 elements of
element type SZARRAY(ELEMENT_TYPE_SZARRAY)
and the element jagged[0] holds a reference to a
System.Byte[] with Rank = 1, holding 4 elements of element type
Byte(ELEMENT_TYPE_BYTE)
You just proved my point. jagged is an ordinary .NET array, each member of
which is byte[][].
>
Take a look at the run-time type [4] above and notice the Element type
SZARRAY for the jagged array "jagged", SZARRAY is s type that indicates a
vector, an array with 0 bound and *no* upper bound. This is the way by
which the CLR makes a distiction between a "jagged array" and other array
types, the CLR treats them differently from the other types.
If you look at the snip in [3], you'll see the Rank being 2, which is
the way by which the CLR distincts multi-dimentional arrays from other
array types. You can't have an array with Rank 1 and Element type
SZARRAY.

[2 ]show a regular array, that is Rank = 1 and Element type = CLASS.

[1] and [2] both define an array of element type CLASS, that means that
they are of the same Class (Execution Class) as such their instances point
to the same Method table, but the Class of [4] , is different from [1] (an
array of arrays of ...), so is it's Method table. The same is tru for [3]
which is treated differently as the others, this is reflected by it's
Execution Class which differs from the others.
See what I mean now?

>>languages including C++/CLI) with well defined language syntax rules and

Then what is the syntax for a managed jagged array in C++/CLI? Oh, it's
something like:

cli::array<cli::array<int>^>^

Not sure what you mean by this...
Anyway, make it:
(missing "using namespace System; using namespace cli;")
array<array<Int32>^>^ local = gcnew array<array< Int32 >^>(2);
or:
array<array<array<Int32>^>^>^ local1 = gcnew array<array<array< Int32
^>^>(2);
to show that *only* one dimension (the first) can be specified, here we
declare "jagged arrays", using well defined language declaration syntax,
This is not language syntax for jagged arrays. This is language syntax for
a use of a generic ref class named cli::array, where the type parameter is
cli::array<int>^.
every
language has his own syntax, but finaly it boils down to the same thing.
>>based on a CLS compliant type from the CTS, and this is not true in C++.
in C#
int[3][] ja;
ja is a jagged array.

which is not possible in C++
int ja[3][];

The omitted dimension syntax is accepted in C and C++, but means
something
entirely different. And I think it is the first dimension omitted, not
the last.

That's exactly the point, the you can ommit the first dimentions, never
the
last, that means that you can only define a rectangular array using that
array syntax in C++. A jagged array *may* not specify the last dimension
>>will not compile.....
and
int ja[3][5];

is a two dimentional rectangular array, an array of arrays, but it's not
a jagged array!

No, it's not an array of arrays at all.

Right, my bad, no array of arrays, a two dimentional rectangular array,
but
no jagged array.
It's 15 elements laid out sequentially in memory.
>
It is a single array, and can be
>treated interchangeable as a 3x5 array, a 5x3 array, or a 15 element
one-dimensional array.

int ja1[5], ja2[5], ja3[5];
int* ja[] = { ja1, ja2, ja3 };

is an array of arrays.
Right, still no jagged array.
Of course it is a jagged array. I can change the length of ja[0] without
changing the length of ja[1] or ja[2].

int ja4[6];

ja[0] = ja4;

>
>Or, if you want to nitpick that this is an array of pointers,

int (&ja[])[5] = { ja1, ja2, ja3 };

Which is an array of arrays, but cannot be jagged.

Right, no jagged array.
>>>
Anyway, what's important here and what the OP is after, is that they can
be passed and accessed *directly* across the managed/unmanaged language
(here C# and C++) boundaries *without* the need to resort to some kind
of
custom marshaling (like I've illustrated), and we both know that this is
not the case, right?

P/invoke can't handle arrays of ref class types, and an array is a ref
class, so no, p/invoke can't do an array of arrays (or array of lists, or
list of arrays, or array of strings, or ...). Jagged arrays aren't a
special case in any sense.
Did I ever said otherwise?
It was me who said you can't pass a "jagged arrays" to C++, the PInvoke
marshaler has no knowlege on how to represent this type as an "unmanaged"
type (without creating a "new" kind of type of course).
Yes. You keep insisting that a jagged array is a special type. It is not.
If a jagged array was anything more than a composed array, then the
following would not work:

class Gen<T>
{
public static void UseIt(T[] t) { ... } // this is not a jagged array,
right?
}

int[][] a; // but this is a jagged array you say

Get<int[]>.UseIt(a); // passing a jagged array to a function that expects a
plain array?
Jun 18 '07 #18

This thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

1
by: lolomgwtf | last post by:
I have a managed C++ method that wraps unmanaged code and creates a managed object holding data retrieved form an unmanged one. I want create an instance of this managed class in C#, pass it to...
2
by: lolomgwtf | last post by:
I have a managed C++ method that wraps unmanaged code and creates a managed object holding data retrieved form an unmanged one. I want create an instance of this managed class in C#, pass it to...
2
by: Claire | last post by:
After giving up on passing nested structs to an unmanaged DLL, I planned that I'd pass a simple buffer of bytes (the same size as the struct) to the dll, convert to a memory stream and read in the...
17
by: mr.resistor | last post by:
hey i am having a few problems calling a C DLL from C#. i am using a simple function that takes an array of floats and an integer as an input, but i cannot seem to get it to work. when i try to...
4
by: Andreas Reiff | last post by:
Hi! I want some communication to take place between a c++ app and a c++ .dll with an intermediate managed/unmanaged c++ dll. Basicall, I want the unmanaged c++ dll to have a callback to the...
9
by: =?Utf-8?B?U2hhcm9u?= | last post by:
In my managed code (C#) I have a some dozens of single dimension byte array. I get each of this arrays from another unmanaged code (first DLL). I need to stitch these arrays to a dual dimensions...
0
by: eitanyan | last post by:
I am trying to create a Java to .Net interop and the way I am doing it is by creating a C# com object and a native unmanaged c++ dll that uses JNIEnv of java. the java is loading the native c++ dll...
0
by: mjaaland | last post by:
Hi! I've been working with DLLimports passing structs and various other parameters to unmanaged code. I had problems earlier sending pointer to structs to the unmanaged code, and this forum solved...
13
by: Andy Baker | last post by:
I am attempting to write a .NET wrapper in C# for an SDK that has been supplied as a .LIB file and a .h header file. I have got most of the functions to work but am really struggling with the...
2
isladogs
by: isladogs | last post by:
The next Access Europe meeting will be on Wednesday 7 Feb 2024 starting at 18:00 UK time (6PM UTC) and finishing at about 19:30 (7.30PM). In this month's session, the creator of the excellent VBE...
0
by: MeoLessi9 | last post by:
I have VirtualBox installed on Windows 11 and now I would like to install Kali on a virtual machine. However, on the official website, I see two options: "Installer images" and "Virtual machines"....
0
by: DolphinDB | last post by:
Tired of spending countless mintues downsampling your data? Look no further! In this article, you’ll learn how to efficiently downsample 6.48 billion high-frequency records to 61 million...
0
by: Aftab Ahmad | last post by:
Hello Experts! I have written a code in MS Access for a cmd called "WhatsApp Message" to open WhatsApp using that very code but the problem is that it gives a popup message everytime I clicked on...
0
by: Aftab Ahmad | last post by:
So, I have written a code for a cmd called "Send WhatsApp Message" to open and send WhatsApp messaage. The code is given below. Dim IE As Object Set IE =...
0
isladogs
by: isladogs | last post by:
The next Access Europe meeting will be on Wednesday 6 Mar 2024 starting at 18:00 UK time (6PM UTC) and finishing at about 19:15 (7.15PM). In this month's session, we are pleased to welcome back...
0
by: marcoviolo | last post by:
Dear all, I would like to implement on my worksheet an vlookup dynamic , that consider a change of pivot excel via win32com, from an external excel (without open it) and save the new file into a...
1
isladogs
by: isladogs | last post by:
The next Access Europe meeting will be on Wednesday 6 Mar 2024 starting at 18:00 UK time (6PM UTC) and finishing at about 19:15 (7.15PM). In this month's session, we are pleased to welcome back...
0
by: jfyes | last post by:
As a hardware engineer, after seeing that CEIWEI recently released a new tool for Modbus RTU Over TCP/UDP filtering and monitoring, I actively went to its official website to take a look. It turned...

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.