Click to See Complete Forum and Search --> : C# PInvoke Question
jjones7947
March 9th, 2010, 11:26 AM
Have a function as follows once I forage and translate everything into basic types:
unsigned int DAOpenDocument(HANDLE lphDoc, unsigned int dwSpecType, void* pSpec, unsigned int dwFlags);
The documentation says that lphDoc is "a Pointer to a handle that will be filled with a value uniquely identifying the document to data access. The developer uses this handle in subsequent calls to data access to identify this particular input file. This is not an operating system file handle.
Once I plugged this into P/Invoke Iterop Assistant I get:
public partial class NativeMethods {
///Return type: unsigned int
///lphDoc: HANDLE->void*
///dwSpecType: unsigned int
///pSpec: void*
///dwFlags: unsigned int
{System.Runtime.InteropServices.DllImportAttribute("sccda.dll", EntryPoint="DAOpenDocument")]
public static extern uint DAOpenDocument(System.IntPtr lphDoc, uint dwSpecType, System.IntPtr pSpec, uint dwFlags);
}
I use lphDoc = (System.IntPtr)GCHandle.Alloc(new Object(), GCHandlerType.Pinned);
I know this allocates memory the sizeof Object, since I don't know what is going in there and I want it to be long lived, this seemed like a reasonable assumption. Is it?
pSpec contains a file path which I've done before using System.IntPtr path = Marshal.StringToHGlobalAnsi(String filepath);
Any better alternatives?
Jim
darwen
March 9th, 2010, 04:12 PM
If you're talking about the Oracle API, then your signature is slightly wrong.
DAERR DAOpenDocument(
VTLPHDOC lphDoc,
VTDWORD dwSpecType,
VTLPVOID pSpec,
VTDWORD dwFlags);
VTLPHDOC is typedeffed as
typedef VTSYSPARAM VTHDOC, * VTLPHDOC;
where VTSYSPARAM is
typedef DWORD_PTR VTSYSPARAM;
Therefore your definition should be
[DllImport("sccda.dll",
CallingConvention = CallingConvention.Winapi)]
public extern static int DAOpenDocument(
ref int phDoc,
int dwSpecType,
IntPtr pSpec,
int dwFlags);
Darwen.
Mutant_Fruit
March 9th, 2010, 06:10 PM
I use lphDoc = (System.IntPtr)GCHandle.Alloc(new Object(), GCHandlerType.Pinned);
If you just need a unique IntPtr, why not use an auto-incrementing integer?
public static class Id
{
static int value;
public static IntPtr Next ()
{
int v = Interlocked.Increment (ref value);
return new IntPtr (v);
}
}
EDIT: I just looked at the docs and it's slightly confusing. There are two options that might be valid:
1) You're supposed to generate the unique handle - in this case the above code is perfect.
2) The library generates the unique handle in which case neither my code or your code will work.
If option 2 is what's supposed to happen, you should probably be passing in something like:
IntPtr handle = IntPtr.Zero;
DAOpenDocument(ref IntPtr phDoc, int dwSpecType, IntPtr pSpec, int dwFlags);
Then when the call is finished, 'handle' will contain the unique identifier. The use of the word 'handle' and the declaration of the typedefs above make me suspect that it would be incorrect to treat it as a "ref int" as it's expecting a 'pointer to a handle' and handle generally means an IntPtr. So it wants a pointer to an IntPtr. You'd have to run your code on both a 32bit and 64bit system to be sure, or at least find the relevant typedefs in the documentation and paste them all here (just in case the above ones are incorrect).
jjones7947
March 10th, 2010, 08:10 AM
First, I am talking about the Oracle Outside In API. Specifically, I'm working on the Image Export (ix) implimentation.
I originally did the reduction walk that darwen did (which is correct), but couldn't reconcile using an int with the documentation. Also I couldn't figure out what value to assign to it. MSDN says that a ref parameter must be initialized before use.
BTW the new Object() thing didn't work. Got an error about non-blittable/non-primitive. Was reading this morning that GCHandle.Alloc is looking for an unmanaged object, not a class.
I think that Mutant_Fruit is correct and that if I pass in a empty IntPtr the app will load it with an address of an appropriately sized buffer.
In general, isn't it safe to assume that if the API doesn't tell you specifically the structure or at least the size of thing that is going to be at the other end of a pointer that the API itself is going to create the "thing" and give you a valid pointer?
Well anyway I'll give it a try and get back. Thanks to both of you.
jjones7947
March 10th, 2010, 10:57 AM
Hey, Mutant_Fruit we owe darwen an apology. Tried it with a IntPtr and got a 961 error from the API which I could not find in the header files. So I passed in an int initialized to 0 and got a success msg from DAOpenDocument.
Looks like the API just wants an int to play with.
Thanks,
Jim
Mutant_Fruit
March 10th, 2010, 12:39 PM
Did you use "ref IntPtr" or just "IntPtr" ? Also, did you use "ref int" or "int"?
I'm fairly sure it's "ref something" the only question is whether or not that something is an int or IntPtr. If you have a 32bit OS and 32bit software, then it doesn't matter. If it's a 64bit os with 64bit software, it will matter :)
jjones7947
March 11th, 2010, 06:12 AM
Did use "ref int". It is 32 libraries on 64 bit os. Developing on the machine it will run on.
Jim
Mutant_Fruit
March 11th, 2010, 11:49 AM
As it's 32bit software, both "ref int" and "ref IntPtr" should work fine in this context. If the software were 64bit, that'd be another story ;)
If you do plan on using the 64bit software, do log this somewhere as a potential issue. Alternatively, get in touch with oracle/the oracle forums and ask people what you should be passing to that function.
I suspect that it wants a pointer to a block of memory which is the size of a pointer.
codeguru.com
Copyright Internet.com Inc., All Rights Reserved.