|
Comments and Discussions
|
|
To tell you the truth man, I only know as much as you, maybe it just won't work cause the API is so old, you might consider opening a case with microsoft on this or look more closely at word first and why its overwriting the setting.
Sorry,
Kyle
|
|
|
|
|
I am getting the below error while calling Marshal.PtrToStructure
System.MissingMethodException: No parameterless constructor defined for this object
pls look into my code.
[StructLayout(LayoutKind.Sequential)]
private struct POINT
{
public long x;
public long y;
}
nRes = DeviceCapabilities(strDeviceName, strPort, DeviceCapabilitiesFlags.DC_PAPERSIZE, (IntPtr)null, (IntPtr)null);
pAddr = Marshal.AllocHGlobal((int)nRes * 128);
nRes = DeviceCapabilities(strDeviceName, strPort, DeviceCapabilitiesFlags.DC_PAPERSIZE, pAddr, (IntPtr)null);
if(nRes < 0)
{
strError = new Win32Exception(Marshal.GetLastWin32Error()).Message + "["+ strDeviceName +": "+ strPort +"]";
return false;
}
offset = pAddr.ToInt32();
POINT[] paperSize = new POINT[nRes];
paperSize = (POINT[]) Marshal.PtrToStructure(pAddr, typeof(POINT[]));
// I am getting this error at this point
karthik
|
|
|
|
|
Here are some links on how to use DeviceCapabilities
http://www.msusenet.com/archive/index.php/t-1869411790.html
http://www.planetsourcecode.com/vb/scripts/ShowCode.asp?txtCodeId=3687&lngWId=10
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/gdi/prntspol_21bn.asp
try changing typeof(POINT[]) to typeof(POINT)
or you might have to loop through the pointer and get on POINT structure back at a time if the function is suppose to return an array of points. Look at a segment of code from a function I wrote below for another program how I increase the pointer and keep marshalling out the structures.
Int32 pointer = oBackup.Instance.ToInt32(); //Pointer to the instances of storage groups
//Initalize array to hold Storage groups
INSTANCE_BACKUP_INFO[] aInstanceBackupInfo = new INSTANCE_BACKUP_INFO[oBackup.GroupCount];
//Fill them
for (int i = 0; i < oBackup.GroupCount; i++)
{
aInstanceBackupInfo[i] = (INSTANCE_BACKUP_INFO)Marshal.PtrToStructure(new IntPtr (pointer), typeof(INSTANCE_BACKUP_INFO));
pointer += Marshal.SizeOf(aInstanceBackupInfo[i]);
}
hopefully this should solve your problem
|
|
|
|
|
Hi kbrryder
It works fine.
Thanks
Regards
karthik
|
|
|
|
|
|
|
Hello all,
I've managed to call API's from .NET without much trouble, however I'm now trying to use a particular method of an API that requires a pointer to be passed to it. I have tried all sorts of syntax and combinations, however the expected result set (contained in a buffer) that is returned from it is unreadable. In the past I have never had to pass pointers to API's, so I'm sure there must be something that I'm doing wrong in the way that I'm dealing with pointers - perhaps I need some sort of marshalling? - but I can't work it out. Any help is greatly appreciated!
Here's a cutdown version of the class that I'm writing with a method BdGetMeet() that calls the API method that should in turn return a buffer full of data:
unsafe class RaceData
{
//The API that I'm trying to use - note that
//I can call other methods of this API without any problem
//lpBuffer should return a buffer of chars,
//also nSize should return the new size of the buffer - which it does no problem.
[DllImport("cdbdapi.dll", EntryPoint = "GetMeet", ExactSpelling = false,
SetLastError = true)]
static extern int GetMeet(
char* lpBuffer,
int* nSize);
/// <summary>
/// Populates a buffer with the current "Meet" data
///
public static void BdGetMeet()
{
int x = 16384; //A reasonable amount of memory to allocate
char* BdBuffer = stackalloc char[x]; //Allocate the memory to a buffer of char*
int* bufferLen = &x; //BufferLen is the size of the buffer.
//Now call the API to populate the buffer
//note that this exectutes successfully without throwing any errors.
if (GetMeet(BdBuffer, bufferLen) != Constants.CDBDE_COMMAND_COMPLETED)
{
throw (new Exception("Error getting Race Meet!"));
}
//Now print the contents of the buffer
//Note that it does print characters but they aren't
//human readable! Also note that the bufferLen has been
//successfully changed as expected
for (int i = 1; i <= *bufferLen; i++)
Console.WriteLine("buffer[{0}]: {1:G}", i, BdBuffer[i]);
//Expected output is "buffer[1]: 'M'
// buffer[2]: 'E'" etc.
//however the output I'm getting replaces the characters ('M' and 'E')
//with square symbols that can't be read.
}
}
I have tried assigning characters to the buffer before calling the API and printing the contents out before making the API call. This works fine and I get the expected characters printed out, but after I've called the API the buffer is full of garbage characters again that can't be read!
|
|
|
|
|
Here is a link I found, but it looks like you already found this from looking at your code.
http://www.subscriptiondata.com/apidef.html
The characters you get back might be there but farther down in the buffer array, sometimes managed code can add extra characters to the buffer.
//here are some possible managed api definition solutions
[DllImport("cdbdapi.dll", EntryPoint = "GetMeet", ExactSpelling = false,
SetLastError = true)]
static extern int GetMeet( ref string lpBuffer, ref int nSize);
[DllImport("cdbdapi.dll", EntryPoint = "GetMeet", ExactSpelling = false,
SetLastError = true)]
static extern int GetMeet( ref IntPtr lpBuffer, ref IntPtr nSize);
[DllImport("cdbdapi.dll", EntryPoint = "GetMeet", ExactSpelling = false,
SetLastError = true)]
static extern int GetMeet( string lpBuffer, ref int nSize);
//or some other combination of the above or you can just use your unmanaged one
if this doesn't help you send me your project or a project where I can actually run this program and I will look at it more.
Thanks,
Kyle (gburmark@comcast.net)
|
|
|
|
|
Thanks very much for the suggestions Kyle... I've tried them all but unfortunately they don't seem to work.
I'm going to try a couple of other things and if I don't have any luck I might have to take you up on your generous offer and send you through my project!
Thanks again.
James
p.s. apologies for the delayed reply.. been extremely busy lately.
|
|
|
|
|
Hi James,
Can you remember what you did to fix this code.I am also working with same API(from www.subscriptiondata.com)and also getting empty array of char* returned. I have tried using the code exactly as your but no success so far
I have wasted my three days on it and I don't know what to do.
Any suggestions will be highly appreciated.
Thanks,
Raghav
|
|
|
|
|
I have no idea how to fix it, what I said in my comments to him is all I know, he'd be the one with the answer prob. I'm working on a huge project of my own and don't have time to help you right now. Thanks.
|
|
|
|
|
I have the found the fix. I turns out that 'char*' maps 'StringBuilder' class in C#.
I am posting the solution here so that it can help someone in future.
The Original Declaration in UnManaged C++ code is
int GetMeet(char *buffer,int *nSize)
Any one of the following two C# declarations should do the trick.
/**********Declaration 1 in C#**********/
[DllImport("cdbdapi.dll")]
static extern int GetMeet(StringBuilder lpBuffer,int * nSize);
/**********Declaration 2 in C#**********/
[DllImport("cdbdapi.dll")]
static extern int GetMeet(StringBuilder lpBuffer,IntPtr nSize);
/**Sample Wrapper Function for Declartion No 1**/
public unsafe void WrapperGetMeet()
{
int x = 16384; //A reasonable amount of memory to allocate
int* bufferLen=&x;
//Must Specify Capacity for StringBuilder
//otherwise an Exception may occur during function call
StringBuilder BdBuffer=new StringBuilder(x);
int res=GetMeet(BdBuffer,bufferLen);
if (res!= Constants.CDBDE_COMMAND_COMPLETED)
{
throw (new Exception("Error getting Race Meet!"));
}
Console.WriteLine(BdBuffer.ToString());
}
/**Sample Wrapper Function for Declartion No 2**/
public unsafe void WrapperGetMeet()
{
int x = 16384; //A reasonable amount of memory to allocate
IntPtr ptr=new IntPtr(&x);
//Must Specify Capacity for StringBuilder
//otherwise an Exception may occur during function call
StringBuilder BdBuffer=new StringBuilder(x);
int res=GetMeet(BdBuffer,ptr);
if (res!= Constants.CDBDE_COMMAND_COMPLETED)
{
throw (new Exception("Error getting Race Meet!"));
}
Console.WriteLine(BdBuffer.ToString());
}
|
|
|
|
|
Many of the DirectShow calls arguments use variations of three constructs:
(VOID**)&obj
(LPVOID*)&obj
void ** obj -- reference only as: obj
such as in:
CoCreateInstance(CLSID_FilterGraph, NULL, CLSCTX_INPROC_SERVER, IID_IGraphBuilder, (void **)&pGB)
What would the correct C# translation be?
|
|
|
|
|
I found some info at this link
http://www.codeguru.com/Csharp/Csharp/cs_misc/com/article.php/c9065/[^]
Here is how they say to do the decleration
[DllImport("ole32.Dll")]
static public extern uint CoCreateInstance(
ref Guid clsid,
[MarshalAs(UnmanagedType.IUnknown)] object inner,
uint context,
ref Guid uuid,
[MarshalAs(UnmanagedType.IUnknown)] out object rReturnedComObject);
I found this information on google by searching for "CoCreateInstance c#"
|
|
|
|
|
Hi there. I'm trying to get a HDD serial number using
DeviceIoControl (
handlePhysicalDrive,
IOCTL_STORAGE_GET_MEDIA_SERIAL_NUMBER, //0x00074080
IntPtr.Zero,
0,
ref mediaData,
(uint)Marshal.SizeOf(mediaData),
ref l_nBytesReturned,
System.IntPtr.Zero);
I cant correctly convert the C struct to C#
//C struct
typedef struct _MEDIA_SERIAL_NUMBER_DATA {
ULONG SerialNumberLength;
ULONG Result;
ULONG Reserved[2];
UCHAR SerialNumberData[];
} ;
//my convertion
[StructLayout(LayoutKind.Sequential)]
public struct MEDIA_SERIAL_NUMBER_DATA{
public uint SerialNumberLength;
public uint Result;
public uint Reserved_0;
public uint Reserved_1
public System.IntPtr SerialNumberData;
}
Please, can somebody help me?
|
|
|
|
|
here is how I would declare the function first in c#
[DllImport ~]
public static extern bool DeviceIoControl(
IntPtr hDevice,
uint dwIoControlCode,
IntPtr lpInBuffer,
uint nInBufferSize,
ref IntPtr lpOutBuffer,
ref uint nOutBufferSize,
ref IntPtr lpBytesReturned,
IntPtr lpOverlapped
);
Here is how I would do the struct
//C struct
typedef struct _MEDIA_SERIAL_NUMBER_DATA {
ULONG SerialNumberLength;
ULONG Result;
ULONG Reserved[2];
UCHAR SerialNumberData[];
} ;
c#
[StructLayout(LayoutKind.Sequential)]
public struct MEDIA_SERIAL_NUMBER_DATA
{
public uint SerialNumberLength;
public uint Result;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 2)] //or possibly, SafeArray, LPArray, or IntPtr maybe
public uint [] Reserved;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 0)] //same as above, may need to change SizeConst
public char [] SerialNumberData;
}
|
|
|
|
|
I am a little confused. I am still thinking that the problem is in struct conversion, but not really sure ...
That's my code. When I execute it, the drive handle is created but DeviceIoControl return false (I get no data).
for (int l_nDrive = 0; l_nDrive < MAX_IDE_DRIVES; l_nDrive ++)
{
string l_nDriveName = System.String.Format("\\\\.\\PHYSICALDRIVE{0}", l_nDrive);
//create drive handle
this.m_handle = CreateFile
(
l_nDriveName,
GENERIC_READ, //0x80000000
FILE_SHARE_READ | FILE_SHARE_WRITE, //0x00000001 | 0x00000002
IntPtr.Zero,
OPEN_EXISTING, //3
0,
IntPtr.Zero
);
if ( ((int)m_handle != -1) && ((int)m_handle != 0) )
{
uint l_usBytesReturned = 0;
System.IntPtr buffer = System.IntPtr.Zero;
uint bufferSize = 0;
if (Win32Functions.DeviceIoControl
(
this.m_handle,
IOCTL_STORAGE_GET_MEDIA_SERIAL_NUMBER,
System.IntPtr.Zero,
0,
ref buffer,
ref bufferSize,
ref l_usBytesReturned,
System.IntPtr.Zero
))
{
//get the data from the buffer...
}
}
CloseHandle();
}
|
|
|
|
|
Here is how I would declare the function first
c#
[DllImport(~)]
public static extern bool DeviceIoControl
(
IntPtr hDevice,
uint dwIoControlCode,
IntPtr lpInBuffer,
uint nInBufferSize,
ref IntPtr lpOutBuffer,
ref uint nOutBufferSize,
ref IntPtr lpBytesReturned, //or ref uint lpBytesReturned
IntPtr lpOverlapped
);
here is how i would do the struct
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
public struct MEDIA_SERIAL_NUMBER_DATA
{
public uint SerialNumberLength;
public uint Result;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 2)] //or SafeArray, LPArray or maybe IntPtr to array
public uint [] Reserved;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 0)] //same as above, or maybe string
public char [] SerialNumberData;
}
|
|
|
|
|
I am a little confused. I am still thinking that the problem is in struct conversion, but not really sure ...
That's my code. When I execute it, the drive handle is created but DeviceIoControl return false (I get no data).
for (int l_nDrive = 0; l_nDrive < MAX_IDE_DRIVES; l_nDrive ++)
{
string l_nDriveName = System.String.Format("\\\\.\\PHYSICALDRIVE{0}", l_nDrive);
//create drive handle
this.m_handle = CreateFile
(
l_nDriveName,
GENERIC_READ, //0x80000000
FILE_SHARE_READ | FILE_SHARE_WRITE, //0x00000001 | 0x00000002
IntPtr.Zero,
OPEN_EXISTING, //3
0,
IntPtr.Zero
);
if ( ((int)m_handle != -1) && ((int)m_handle != 0) )
{
uint l_usBytesReturned = 0;
System.IntPtr buffer = System.IntPtr.Zero;
uint bufferSize = 0;
if (Win32Functions.DeviceIoControl
(
this.m_handle,
IOCTL_STORAGE_GET_MEDIA_SERIAL_NUMBER,
System.IntPtr.Zero,
0,
ref buffer,
ref bufferSize,
ref l_usBytesReturned,
System.IntPtr.Zero
);
)
{
//get the data from the buffer...
}
}
CloseHandle();
}
|
|
|
|
|
Did you see how I changed the struct format from what you had? Look at where I changed the reserved variables. Maybe I could help you better if you sent me the whole project and I could see if I could get it to work on my computer. (kyle@lucid8.com)
|
|
|
|
|
Sorry I guess I didn't need your example, I tried to use what you gave me and tried to make it work, but I couldn't. I looked up "DeviceIoControl c#" on google and I got a bunch of results and I tried all these different declarations of DeviceIoControl and nothing seemed to work. Are you using this on normal Windows or Windows CE?
|
|
|
|
|
here is the project i made but it doesn't work, I'm not sure if the function is returning true or false, but mine returns 0. I got this code from a bunch of differnt sources so I don't know who is correct. The function declerations can be done multiple ways I think.
class Program
{
[DllImport("kernel32.dll", SetLastError = true)]
static extern IntPtr CreateFile(
string lpFileName,
uint dwDesiredAccess,
uint dwShareMode,
IntPtr lpSecurityAttributes,
uint dwCreationDisposition,
uint dwFlagsAndAttributes,
IntPtr hTemplateFile);
[DllImport("kernel32.dll", SetLastError = true)]
static extern int CloseHandle(IntPtr hObject);
[DllImport("kernel32.dll", SetLastError = true)]
static extern int DeviceIoControl(int hDevice, int dwIoControlCode, ref object lpInBuffer,
int nInBufferSize, ref object lpOutBuffer, int nOutBufferSize, ref int lpBytesReturned,
ref OVERLAPPED lpOverlapped);
[StructLayout(LayoutKind.Sequential)]
public struct MEDIA_SERIAL_NUMBER_DATA
{
public uint SerialNumberLength;
public uint Result;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 2)] //or SafeArray, LPArray or maybe IntPtr to array
public uint[] Reserved;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 0)] //same as above, or maybe string
public char[] SerialNumberData;
}
[StructLayout(LayoutKind.Sequential)]
public struct OVERLAPPED
{
IntPtr Internal;
IntPtr InternalHigh;
uint Offset;
uint OffsetHigh;
IntPtr hEvent;
}
const uint GENERIC_READ = 0x80000000;
const uint FILE_SHARE_READ = 0x00000001;
const uint FILE_SHARE_WRITE = 0x00000002;
const uint OPEN_EXISTING = 3;
const int IOCTL_STORAGE_GET_MEDIA_SERIAL_NUMBER = 0x0304;
static void Main(string[] args)
{
string l_nDriveName = "";
IntPtr hand = IntPtr.Zero;
int l_usBytesReturned = 0;
IntPtr buffer = IntPtr.Zero;
uint bufferSize = 0;
// SecurityAttributes att = null;
for (int l_nDrive = 0; l_nDrive < 3; l_nDrive ++)
{
l_nDriveName = String.Format("\\\\.\\PHYSICALDRIVE{0}", l_nDrive);
//create drive handle
hand = CreateFile(l_nDriveName, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE,
IntPtr.Zero, OPEN_EXISTING, 0, IntPtr.Zero);
if (hand.ToInt32() != -1 && hand.ToInt32() != 0)
{
l_usBytesReturned = 0;
buffer = IntPtr.Zero;
bufferSize = 0;
object o = 0;
object o2 = 0;
OVERLAPPED lap = new OVERLAPPED();
Int64 i64 = 0;
if (0 == DeviceIoControl(hand.ToInt32(), IOCTL_STORAGE_GET_MEDIA_SERIAL_NUMBER, ref o, Marshal.SizeOf(i64),
ref o2, 0, ref l_usBytesReturned, ref lap))
{
Console.WriteLine(l_usBytesReturned);
}
else
Console.WriteLine(Marshal.GetLastWin32Error());
}
CloseHandle(hand);
hand = IntPtr.Zero;
}
}
}
|
|
|
|
|
Hi,
I have got the same result as you, but I notice something strange: when you compile the project as Console application and as Windows application the CreateFile function returns a different result.
|
|
|
|
|
I have no idea whats going on there can't help ya. Probably not a big deal, but first ya gotta focus on getting DeviceIoControl working.
-Kyle
|
|
|
|
|
Hi,
You should avoid marshalling non-CLS-compliant types such as uint.
uint is 32 bits, but is not CLS-compliant.
int is also 32-bits and IS CLS-compliant.
As far as the Win32 Api is concerned, all it cares about is receiving 32bits. It doesn't care if this is a C# uint or int.
Therefore always marshal using CLS-compliant types only.
e.g. DWORD should be int NOT uint
|
|
|
|
|
|
General News Suggestion Question Bug Answer Joke Praise Rant Admin
Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.
|
|