Mattias, Thank you very much! I was able to sort out these and other marshaling issues (a ton of credit to be given to your post).
To everyone on this list: Sorry for the RTFM posting. I locked myself in a room and read the entire marshaling documentation stack last night. I feel much more enlightened now. Does anyone know of a managed Kerberos library (other than sun.security.krb5.*)? ;-) ;-) John > -----Original Message----- > From: Mattias Sjögren [mailto:[EMAIL PROTECTED]] > Sent: Friday, 26 April 2002 7:10 PM > To: [EMAIL PROTECTED] > Subject: Re: [DOTNET] Marshalling Issue > > > John, > > > > In > > > particular, I'm having trouble trying to figure out how > to marshal > > > the following struct: > > > > > > public struct KERB_QUERY_TKT_CACHE_RESPONSE > > > { > > > public KERB_PROTOCOL_MESSAGE_TYPE MessageType; > > > public ulong CountOfTickets; > > > public KERB_TICKET_CACHE_INFO[] Tickets; > > > } > > > > > > The marshaller bombs each and every time, stating that > the Tickets > > > array couldn't be marshalled as a struct. > > The marhalling layer can't handle variable length arrays in a > struct. The > best workaround is usually to remove the array member, and > then manually > calculate the offset of the array and read it. > > > > public struct LARGE_INTEGER > > { > > public uint LowPart; > > public int HighPart; > > public struct u > > { > > public uint LowPart; > > public int HighPart; > > } > > public long QuadPart; > > } > > This isn't right. LARGE_INTEGER is a union that you either > can treat as a > single 64 bit integer, or two 32 bit parts. Since .NET has a > native 64 bit > integer, it's easier to remove this type entirely, and > replace it with a > long everywhere. > > > > [StructLayout(LayoutKind.Sequential)] > > public struct KERB_QUERY_TKT_CACHE_RESPONSE > > { > > public KERB_PROTOCOL_MESSAGE_TYPE MessageType; > > public uint CountOfTickets; > > public KERB_TICKET_CACHE_INFO[] Tickets; > > } > > I suggest you change it to > > public struct KERB_QUERY_TKT_CACHE_RESPONSE > { > public KERB_PROTOCOL_MESSAGE_TYPE MessageType; > public uint CountOfTickets; > // public KERB_TICKET_CACHE_INFO[] Tickets; > } > > > > public class AccessTktCacheExample > > { > > [DllImport("secur32.dll")] > > static extern void LsaConnectUntrusted(out IntPtr > > LsaHandle); > > According to the docs, this function returns an NTSTATUS > value you might > want to check for success, not void. > > > > > [DllImport("secur32.dll")] > > static extern int LsaCallAuthenticationPackage( > > IntPtr LsaHandle, > > ulong AuthenticationPackage, > > ref KERB_QUERY_TKT_CACHE_REQUEST[] > > ProtocolSubmitBuffer, > > ref int SubmitBufferLength, > > ref KERB_QUERY_TKT_CACHE_RESPONSE[] > > ProtocolReturnBuffer, > > ref ulong ReturnBufferLength, > > ref int ProtocolStatus); > > AuthenticationPackage and ReturnBufferLength should have the > type (u)int, > not ulong. ProtocolSubmitBuffer shouldn't be an array, just ref > KERB_QUERY_TKT_CACHE_REQUEST should work. ProtocolReturnBuffer should > recieve a pointer to memory allocated by the function, you > shouldn't supply > your own buffer. Therefore, the type should be out IntPtr. > Don't forget to > free the buffer with LsaFreeReturnBuffer. > > You can use Marshal.PtrToStructure to retrieve a > KERB_QUERY_TKT_CACHE_RESPONSE structure from the returned > pointer. You then > add an 8 byte offset > (Marshal.Sizeof(typeof(KERB_QUERY_TKT_CACHE_RESPONSE))) to > the pointer and > start reading KERB_TICKET_CACHE_INFO array, item by item. This can be > easier to do in an unsafe code block, where you can just > increment a "real" > pointer (not IntPtr). > > > Mattias > > === > Mattias Sjögren > [EMAIL PROTECTED] You can read messages from the DOTNET archive, unsubscribe from DOTNET, or subscribe to other DevelopMentor lists at http://discuss.develop.com.