How to declare a pointerto an array of bytes

G

Guest

I am trying to call VerQueryValue from a C# program. VerQueryValue takes as
one of its parameters a pointer to a pointer to an array of bytes, which it
uses to return a pointer to the required array. Now, I can call it like this:
byte* lpBuffer;
int length;
string subBlock = @"\StringFileInfo\" + langCodePage +
@"\FileDescription";
result = VerQueryValue(buffer, subBlock, &lpBuffer, &length);
but then I don't have a byte[] to pass to an ASCIEncoding object to decode.
What I really want to do is declare
byte[]* lplpBuffer
and then pass that to VerQueryValue, but C# apparently won't allow that.
(Oddly enough if I declare
byte[] lpBuffer;
I get an error "cannot convert from byte[]* to byte**", which is peculiar if
it doesn't recognise byte[]* as a type anyway)
Can anyone shed any light?
 
W

Willy Denoyette [MVP]

Dave said:
I am trying to call VerQueryValue from a C# program. VerQueryValue takes as
one of its parameters a pointer to a pointer to an array of bytes, which
it
uses to return a pointer to the required array. Now, I can call it like
this:
byte* lpBuffer;
int length;
string subBlock = @"\StringFileInfo\" + langCodePage +
@"\FileDescription";
result = VerQueryValue(buffer, subBlock, &lpBuffer, &length);
but then I don't have a byte[] to pass to an ASCIEncoding object to
decode.
What I really want to do is declare
byte[]* lplpBuffer
and then pass that to VerQueryValue, but C# apparently won't allow that.
(Oddly enough if I declare
byte[] lpBuffer;
I get an error "cannot convert from byte[]* to byte**", which is peculiar
if
it doesn't recognise byte[]* as a type anyway)
Can anyone shed any light?

No need to use pointers, pass the byte[] by reference:

byte[] lpBuffer;
VerQueryValue(...., ref lpBuffer,...);

Willy.
 
G

Guest

'Fraid not! That gives "cannot convert from 'ref byte[]' to 'byte**'
--
Dave


Willy Denoyette said:
Dave said:
I am trying to call VerQueryValue from a C# program. VerQueryValue takes as
one of its parameters a pointer to a pointer to an array of bytes, which
it
uses to return a pointer to the required array. Now, I can call it like
this:
byte* lpBuffer;
int length;
string subBlock = @"\StringFileInfo\" + langCodePage +
@"\FileDescription";
result = VerQueryValue(buffer, subBlock, &lpBuffer, &length);
but then I don't have a byte[] to pass to an ASCIEncoding object to
decode.
What I really want to do is declare
byte[]* lplpBuffer
and then pass that to VerQueryValue, but C# apparently won't allow that.
(Oddly enough if I declare
byte[] lpBuffer;
I get an error "cannot convert from byte[]* to byte**", which is peculiar
if
it doesn't recognise byte[]* as a type anyway)
Can anyone shed any light?

No need to use pointers, pass the byte[] by reference:

byte[] lpBuffer;
VerQueryValue(...., ref lpBuffer,...);

Willy.
 
W

Willy Denoyette [MVP]

..
Dave said:
'Fraid not! That gives "cannot convert from 'ref byte[]' to 'byte**'
--
Dave


:

Please show us your VerQueryValue function declaration as declared in C,
describe the function semantics, who's allocating the buffers C# or the
unmanaged function, why the double redirection?

Willy.
 
G

Guest

You need to declare the function like the following:
[DllImport("WhatEver.dll")]
public unsafe static extern void VerQueryValue (byte** buffer);

In the method you need to put the following:

//allocate memory on the heap
byte* dataArray = (byte*)Marshal.AllocCoTaskMem(20);
byte** dataArrayArray = &dataArray;

//call the unmanaged function you import from dll file
VerQueryValue(dataArrayArray);

//do what every you want here, before free the memory

//free the memory
Marshal.FreeCoTaskMem((IntPtr)dataArray);


hope it helps,
Ivan Wong
 
G

Guest

Hi guys, thanks for helping on this.
I have just found an MSDN tutorial at
http://msdn.microsoft.com/library/d.../en-us/csref/html/vcwlkunsafecodetutorial.asp
which explains how to do this. I can't say I fully understand how it gets
around the all the convolutions of pointers to pointers etc, but I've used it
and it works. Thanks to you all for looking at it. Hopefully this thread will
help someone else.
--
Dave


Willy Denoyette said:
..
Dave said:
'Fraid not! That gives "cannot convert from 'ref byte[]' to 'byte**'
--
Dave


:

Please show us your VerQueryValue function declaration as declared in C,
describe the function semantics, who's allocating the buffers C# or the
unmanaged function, why the double redirection?

Willy.
 
W

Willy Denoyette [MVP]

Dave, the samples in the tutorial illustrates you how to use unsafe
constructs, but as I said before YOU don't need unsafe constructs to achieve
the same if you don't want to. Use unsafe only when you realy need to (IMO
never in C#).

Here is the same sample not using unsafe constructs:

...
public class Win32Imports
{
[DllImport("version.dll")]
public static extern bool GetFileVersionInfo (string sFileName,
int handle, int size, byte[] infoBuffer);
[DllImport("version.dll")]
public static extern int GetFileVersionInfoSize (string sFileName,
out int handle);
[DllImport("version.dll")]
public static extern bool VerQueryValue (byte[] pBlock,
string pSubBlock, out string pValue, out uint len);

[DllImport("version.dll")]
public static extern bool VerQueryValue (byte[] pBlock,
string pSubBlock, out IntPtr pValue, out uint len);
}

public class C
{
public static int Main ()
{
try
{
int handle = 0;
// Figure out how much version info there is:
int size =
Win32Imports.GetFileVersionInfoSize("printversion.exe",
out handle);

if (size == 0) return -1;

byte[] buffer = new byte[size];

if (!Win32Imports.GetFileVersionInfo("printversion.exe",
handle, size, buffer))
{
Console.WriteLine("Failed to query file version
information.");
return 1;
}
IntPtr subBlock = IntPtr.Zero;
uint len = 0;
// Get the locale info from the version info:
if (!Win32Imports.VerQueryValue (buffer,
@"\VarFileInfo\Translation", out subBlock, out len))
{
Console.WriteLine("Failed to query version
information.");
return 1;
}
int p = (int)subBlock;
int i1 = Marshal.ReadInt16((IntPtr)p);
p+=2;
int i2 = Marshal.ReadInt16((IntPtr)p);
string sb = String.Format("{0:X4}{1:X4}",i1, i2);
string spv = @"\StringFileInfo\" + sb +
@"\ProductVersion";

// Get the ProductVersion value for this program:
string versionInfo;

if (!Win32Imports.VerQueryValue (buffer, spv, out
versionInfo, out len))
{
Console.WriteLine("Failed to query version
information.");
return 1;
}

Console.WriteLine ("ProductVersion == {0}", versionInfo);
}
catch (Exception e)
{
Console.WriteLine ("Caught unexpected exception " +
e.Message);
}

return 0;
}
}



Willy.

Dave said:
Hi guys, thanks for helping on this.
I have just found an MSDN tutorial at
http://msdn.microsoft.com/library/d.../en-us/csref/html/vcwlkunsafecodetutorial.asp
which explains how to do this. I can't say I fully understand how it gets
around the all the convolutions of pointers to pointers etc, but I've used
it
and it works. Thanks to you all for looking at it. Hopefully this thread
will
help someone else.
--
Dave


Willy Denoyette said:
..
Dave said:
'Fraid not! That gives "cannot convert from 'ref byte[]' to 'byte**'
--
Dave


:

Please show us your VerQueryValue function declaration as declared in C,
describe the function semantics, who's allocating the buffers C# or the
unmanaged function, why the double redirection?

Willy.
 
G

Guest

Hi Willy.
yes, thanks for that. Once I got the code from the sample working I started
taking out the unsafe constructs and eventually lo and behold they were all
gone and it still worked. I'm an experienced C++ programmer but still new to
C#. Actually I'm quite impressed that it can make all those calls without
resorting to pointers.
--
Dave


Willy Denoyette said:
Dave, the samples in the tutorial illustrates you how to use unsafe
constructs, but as I said before YOU don't need unsafe constructs to achieve
the same if you don't want to. Use unsafe only when you realy need to (IMO
never in C#).

Here is the same sample not using unsafe constructs:

...
public class Win32Imports
{
[DllImport("version.dll")]
public static extern bool GetFileVersionInfo (string sFileName,
int handle, int size, byte[] infoBuffer);
[DllImport("version.dll")]
public static extern int GetFileVersionInfoSize (string sFileName,
out int handle);
[DllImport("version.dll")]
public static extern bool VerQueryValue (byte[] pBlock,
string pSubBlock, out string pValue, out uint len);

[DllImport("version.dll")]
public static extern bool VerQueryValue (byte[] pBlock,
string pSubBlock, out IntPtr pValue, out uint len);
}

public class C
{
public static int Main ()
{
try
{
int handle = 0;
// Figure out how much version info there is:
int size =
Win32Imports.GetFileVersionInfoSize("printversion.exe",
out handle);

if (size == 0) return -1;

byte[] buffer = new byte[size];

if (!Win32Imports.GetFileVersionInfo("printversion.exe",
handle, size, buffer))
{
Console.WriteLine("Failed to query file version
information.");
return 1;
}
IntPtr subBlock = IntPtr.Zero;
uint len = 0;
// Get the locale info from the version info:
if (!Win32Imports.VerQueryValue (buffer,
@"\VarFileInfo\Translation", out subBlock, out len))
{
Console.WriteLine("Failed to query version
information.");
return 1;
}
int p = (int)subBlock;
int i1 = Marshal.ReadInt16((IntPtr)p);
p+=2;
int i2 = Marshal.ReadInt16((IntPtr)p);
string sb = String.Format("{0:X4}{1:X4}",i1, i2);
string spv = @"\StringFileInfo\" + sb +
@"\ProductVersion";

// Get the ProductVersion value for this program:
string versionInfo;

if (!Win32Imports.VerQueryValue (buffer, spv, out
versionInfo, out len))
{
Console.WriteLine("Failed to query version
information.");
return 1;
}

Console.WriteLine ("ProductVersion == {0}", versionInfo);
}
catch (Exception e)
{
Console.WriteLine ("Caught unexpected exception " +
e.Message);
}

return 0;
}
}



Willy.

Dave said:
Hi guys, thanks for helping on this.
I have just found an MSDN tutorial at
http://msdn.microsoft.com/library/d.../en-us/csref/html/vcwlkunsafecodetutorial.asp
which explains how to do this. I can't say I fully understand how it gets
around the all the convolutions of pointers to pointers etc, but I've used
it
and it works. Thanks to you all for looking at it. Hopefully this thread
will
help someone else.
--
Dave


Willy Denoyette said:
..
'Fraid not! That gives "cannot convert from 'ref byte[]' to 'byte**'
--
Dave


:


Please show us your VerQueryValue function declaration as declared in C,
describe the function semantics, who's allocating the buffers C# or the
unmanaged function, why the double redirection?

Willy.
 
W

Willy Denoyette [MVP]

Dave,

All pointer stuff is taken care of by the interop layer in the CLR
(PInvoke), but rest assured they still exist, be it under the covers.

Willy.

Dave said:
Hi Willy.
yes, thanks for that. Once I got the code from the sample working I
started
taking out the unsafe constructs and eventually lo and behold they were
all
gone and it still worked. I'm an experienced C++ programmer but still new
to
C#. Actually I'm quite impressed that it can make all those calls without
resorting to pointers.
--
Dave


Willy Denoyette said:
Dave, the samples in the tutorial illustrates you how to use unsafe
constructs, but as I said before YOU don't need unsafe constructs to
achieve
the same if you don't want to. Use unsafe only when you realy need to
(IMO
never in C#).

Here is the same sample not using unsafe constructs:

...
public class Win32Imports
{
[DllImport("version.dll")]
public static extern bool GetFileVersionInfo (string sFileName,
int handle, int size, byte[] infoBuffer);
[DllImport("version.dll")]
public static extern int GetFileVersionInfoSize (string sFileName,
out int handle);
[DllImport("version.dll")]
public static extern bool VerQueryValue (byte[] pBlock,
string pSubBlock, out string pValue, out uint len);

[DllImport("version.dll")]
public static extern bool VerQueryValue (byte[] pBlock,
string pSubBlock, out IntPtr pValue, out uint len);
}

public class C
{
public static int Main ()
{
try
{
int handle = 0;
// Figure out how much version info there is:
int size =

Win32Imports.GetFileVersionInfoSize("printversion.exe",
out handle);

if (size == 0) return -1;

byte[] buffer = new byte[size];

if
(!Win32Imports.GetFileVersionInfo("printversion.exe",
handle, size, buffer))
{
Console.WriteLine("Failed to query file version
information.");
return 1;
}
IntPtr subBlock = IntPtr.Zero;
uint len = 0;
// Get the locale info from the version info:
if (!Win32Imports.VerQueryValue (buffer,
@"\VarFileInfo\Translation", out subBlock, out len))
{
Console.WriteLine("Failed to query version
information.");
return 1;
}
int p = (int)subBlock;
int i1 = Marshal.ReadInt16((IntPtr)p);
p+=2;
int i2 = Marshal.ReadInt16((IntPtr)p);
string sb = String.Format("{0:X4}{1:X4}",i1, i2);
string spv = @"\StringFileInfo\" + sb +
@"\ProductVersion";

// Get the ProductVersion value for this program:
string versionInfo;

if (!Win32Imports.VerQueryValue (buffer, spv, out
versionInfo, out len))
{
Console.WriteLine("Failed to query version
information.");
return 1;
}

Console.WriteLine ("ProductVersion == {0}",
versionInfo);
}
catch (Exception e)
{
Console.WriteLine ("Caught unexpected exception " +
e.Message);
}

return 0;
}
}



Willy.

Dave said:
Hi guys, thanks for helping on this.
I have just found an MSDN tutorial at
http://msdn.microsoft.com/library/d.../en-us/csref/html/vcwlkunsafecodetutorial.asp
which explains how to do this. I can't say I fully understand how it
gets
around the all the convolutions of pointers to pointers etc, but I've
used
it
and it works. Thanks to you all for looking at it. Hopefully this
thread
will
help someone else.
--
Dave


:


..
'Fraid not! That gives "cannot convert from 'ref byte[]' to 'byte**'
--
Dave


:


Please show us your VerQueryValue function declaration as declared in
C,
describe the function semantics, who's allocating the buffers C# or
the
unmanaged function, why the double redirection?

Willy.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top