Need Help declaring parameter variables for DllImport for c-dll fu

G

Guest

Hi, I'm using vs2005, .net 2, C# for Windows application. I use DllImport so
I can call up a function written in C++ as unmanaged code and compiled as a
dll us vs2005. My application is able to call the function, EncodeAsnUser.
And it's returning OK but when I display the decoded data in another part of
my application it shows no data has been decoded, all fiedls are either null
or blanks. For some reason, I am not able to step through this function's
code. However, I can see the userContextData does hold all the data that I
assigned and that it's passing.
I think the pbroblems is with my declaration of the parameters(blob and the
userdata structure) .
1. Am I passing the userContextData as a pointer to the function?
2. Am I allocating memory correctly for the Blob?
3. Am I passing the Blob** correctly?
Can someone see what I need to correct here to make it work? Thank you.

[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
public class CUserContextData
{
public int bWinLogOn = 0;
public int bUnifiedID = 0;

[MarshalAs(UnmanagedType.ByValTStr, SizeConst =
MAX_ADSPATH_CHARS)]
public String shell = null;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst =
MAX_ADSPATH_CHARS)]
public String homeDir = null;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst =
MAX_ADSPATH_CHARS)]
public String primaryGroupSID = null;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst =
MAX_ADSPATH_CHARS)]
public String LoginName = null;

public int symarkUID = 0; //Unified User ID
public int IID = 0; //Independant ID
public int Revision = 0;
}

public struct Blob
{
public IntPtr pData;
public int nLength;
public int nSize;
}

public class LibWrap
{
[DllImport("UnityDecodeAsnUser.dll", CharSet = CharSet.Unicode)]
public static extern DE_ERRORS EncodeAsnUser(ref Blob blob,
[In, Out]CUserContextData m);
}

// create an instance of the Blob structure
CUnityDS.Blob blob = new CUnityDS.Blob();
//Encode the user data into a blob
int nBytes = Marshal.SizeOf(typeof(CUnityDS.Blob));
IntPtr ptr = Marshal.AllocHGlobal(nBytes);


// copy and pin the structure to that location
Marshal.StructureToPtr(blob, ptr, true);

// Pass it by reference
// OK, now it's time to "reconsitute" the structure
blob = (CUnityDS.Blob)Marshal.PtrToStructure(ptr,
typeof(CUnityDS.Blob));


CUnityDS.DE_ERRORS errcode =
CUnityDS.DE_ERRORS.DE_MEMORY_ALLOCATION_FAILURE;
errcode = CUnityDS.LibWrap.EncodeAsnUser(ref blob,
userContextData);

//Convert from IntPtr data to byte[] which is needed
for adding as meetingBlob
int size = Marshal.SizeOf(blob);
byte[] meetingBlob = new byte[size];

System.Runtime.InteropServices.Marshal.Copy(blob.pData, meetingBlob, 0,
size);
//add the blob

deNewContextObject.Properties["meetingBlob"].Add((object)meetingBlob);

deNewContextObject.CommitChanges();

//This is the C++ function that I'm calling
extern "C" DE_ERRORS __declspec(dllexport)EncodeAsnUser(Blob** ppBlob,
CUserContextData *userData)
{
_bstr_t temp;
AsnData* pAsn;
std::wstring wsUID;
int REVISION=0;
const char* EMPTY_STRING;
EMPTY_STRING = "";

if ( ( pAsn = AsnAlloc( NULL ) ) == NULL )
{
DbgLog( DL_ERROR, "Unable to allocate ASN.1 buffer" );
return DE_MEMORY_ALLOCATION_FAILURE;
}
if ( !AsnPushTag(pAsn, (ASN_TAG$APPLICATION_START) ) )
goto failed;

if (!AsnWriteInteger( pAsn, REVISION))
goto failed;

if(userData->bUnifiedID)//use UID
{
if (!AsnWriteInteger( pAsn, True) )
goto failed;
}
else //use indep ID
{
if (!AsnWriteInteger( pAsn, False) )
goto failed;
}
if(userData->IID == NULL)
{
if ( !AsnWriteGeneralString( pAsn, EMPTY_STRING))
goto failed;
}
else
{
_bstr_t bstrtUID = L"0"; //initilize the bstr
_itow(userData->IID, bstrtUID, 10);

if ( !AsnWriteGeneralString( pAsn, (char*)bstrtUID))
goto failed;
}

//WinUser name
if(userData->bWinLogOn)
{
if (!AsnWriteInteger( pAsn, True) )
goto failed;

}
else//use indep User Name
{
if (!AsnWriteInteger( pAsn, False) )
goto failed;
}

//Geco
if ( !AsnWriteGeneralString( pAsn, EMPTY_STRING))
goto failed;

//Shell
temp = userData->shell;
if ( !AsnWriteGeneralString( pAsn, (char*)temp))
goto failed;

//Home Driectory
temp = userData->homeDir;
if ( !AsnWriteGeneralString( pAsn, (char*)temp))
goto failed;

//Primary Group SID
temp = userData->primaryGroupSID;
if (!AsnWriteGeneralString( pAsn, (char*)temp))
goto failed;

if ( !AsnPopTag( pAsn ) )
goto failed;
*ppBlob = AsnExtractData( pAsn );
AsnFree( pAsn );
return DE_SUCCESS;

failed:
DbgLog(DL_ERROR, "Failed to encode ASN.1 message packet" );
AsnFree( pAsn );
return DE_ENCODE_MESSAGE_PACKET_FAILURE;
 
W

Willy Denoyette [MVP]

Pucca said:
Hi, I'm using vs2005, .net 2, C# for Windows application. I use DllImport
so
I can call up a function written in C++ as unmanaged code and compiled as
a
dll us vs2005. My application is able to call the function,
EncodeAsnUser.
And it's returning OK but when I display the decoded data in another part
of
my application it shows no data has been decoded, all fiedls are either
null
or blanks. For some reason, I am not able to step through this function's
code. However, I can see the userContextData does hold all the data that
I
assigned and that it's passing.
I think the pbroblems is with my declaration of the parameters(blob and
the
userdata structure) .
1. Am I passing the userContextData as a pointer to the function?
2. Am I allocating memory correctly for the Blob?
3. Am I passing the Blob** correctly?
Can someone see what I need to correct here to make it work? Thank you.

[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
public class CUserContextData
{
public int bWinLogOn = 0;
public int bUnifiedID = 0;

[MarshalAs(UnmanagedType.ByValTStr, SizeConst =
MAX_ADSPATH_CHARS)]
public String shell = null;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst =
MAX_ADSPATH_CHARS)]
public String homeDir = null;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst =
MAX_ADSPATH_CHARS)]
public String primaryGroupSID = null;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst =
MAX_ADSPATH_CHARS)]
public String LoginName = null;

public int symarkUID = 0; //Unified User ID
public int IID = 0; //Independant ID
public int Revision = 0;
}

public struct Blob
{
public IntPtr pData;
public int nLength;
public int nSize;
}

public class LibWrap
{
[DllImport("UnityDecodeAsnUser.dll", CharSet =
CharSet.Unicode)]
public static extern DE_ERRORS EncodeAsnUser(ref Blob blob,
[In, Out]CUserContextData m);
}

// create an instance of the Blob structure
CUnityDS.Blob blob = new CUnityDS.Blob();
//Encode the user data into a blob
int nBytes = Marshal.SizeOf(typeof(CUnityDS.Blob));
IntPtr ptr = Marshal.AllocHGlobal(nBytes);


// copy and pin the structure to that location
Marshal.StructureToPtr(blob, ptr, true);

// Pass it by reference
// OK, now it's time to "reconsitute" the structure
blob = (CUnityDS.Blob)Marshal.PtrToStructure(ptr,
typeof(CUnityDS.Blob));


CUnityDS.DE_ERRORS errcode =
CUnityDS.DE_ERRORS.DE_MEMORY_ALLOCATION_FAILURE;
errcode = CUnityDS.LibWrap.EncodeAsnUser(ref blob,
userContextData);

//Convert from IntPtr data to byte[] which is
needed
for adding as meetingBlob
int size = Marshal.SizeOf(blob);
byte[] meetingBlob = new byte[size];

System.Runtime.InteropServices.Marshal.Copy(blob.pData, meetingBlob, 0,
size);
//add the blob

deNewContextObject.Properties["meetingBlob"].Add((object)meetingBlob);

deNewContextObject.CommitChanges();

//This is the C++ function that I'm calling
extern "C" DE_ERRORS __declspec(dllexport)EncodeAsnUser(Blob** ppBlob,
CUserContextData *userData)
{
_bstr_t temp;
AsnData* pAsn;
std::wstring wsUID;
int REVISION=0;
const char* EMPTY_STRING;
EMPTY_STRING = "";

if ( ( pAsn = AsnAlloc( NULL ) ) == NULL )
{
DbgLog( DL_ERROR, "Unable to allocate ASN.1 buffer" );
return DE_MEMORY_ALLOCATION_FAILURE;
}
if ( !AsnPushTag(pAsn, (ASN_TAG$APPLICATION_START) ) )
goto failed;

if (!AsnWriteInteger( pAsn, REVISION))
goto failed;

if(userData->bUnifiedID)//use UID
{
if (!AsnWriteInteger( pAsn, True) )
goto failed;
}
else //use indep ID
{
if (!AsnWriteInteger( pAsn, False) )
goto failed;
}
if(userData->IID == NULL)
{
if ( !AsnWriteGeneralString( pAsn, EMPTY_STRING))
goto failed;
}
else
{
_bstr_t bstrtUID = L"0"; //initilize the bstr
_itow(userData->IID, bstrtUID, 10);

if ( !AsnWriteGeneralString( pAsn, (char*)bstrtUID))
goto failed;
}

//WinUser name
if(userData->bWinLogOn)
{
if (!AsnWriteInteger( pAsn, True) )
goto failed;

}
else//use indep User Name
{
if (!AsnWriteInteger( pAsn, False) )
goto failed;
}

//Geco
if ( !AsnWriteGeneralString( pAsn, EMPTY_STRING))
goto failed;

//Shell
temp = userData->shell;
if ( !AsnWriteGeneralString( pAsn, (char*)temp))
goto failed;

//Home Driectory
temp = userData->homeDir;
if ( !AsnWriteGeneralString( pAsn, (char*)temp))
goto failed;

//Primary Group SID
temp = userData->primaryGroupSID;
if (!AsnWriteGeneralString( pAsn, (char*)temp))
goto failed;

if ( !AsnPopTag( pAsn ) )
goto failed;
*ppBlob = AsnExtractData( pAsn );
AsnFree( pAsn );
return DE_SUCCESS;

failed:
DbgLog(DL_ERROR, "Failed to encode ASN.1 message packet" );
AsnFree( pAsn );
return DE_ENCODE_MESSAGE_PACKET_FAILURE;



Pucca, You have a wrong idea abut how the Blob structure looks like.
This struct holds a pointer and two integers, that means it's length is 12
bytes (in a 32 bit application), while you think that this struct holds the
actual data of the blob on return, it just holds a pointer to the data and
(I assume) the length of the actual data in nLength and the length of the
buffer for the data in nSize.

Note that here I assume that the "AsnExtractData" function called in the
EncodeAsnUser function effectively fills the Blob with the data pointer and
the size of the data in the buffer and the size of buffer .

One way to get at the Blob and the Data is shown in the followin:

[DllImport(...]
public static extern DE_ERRORS EncodeAsnUser(ref IntPtr blob, ...
...
// allocate memry for the blob
IntPtr pBlob = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(Blob)));
// call the function passing the pointer to the blob byref
EncodeAsnUser(ref pBlob, userContextData);
// copy the unmanaged blob to managed struct Blob
Blob blob = (Blob)Marshal.PtrToStructure(pBlob, typeof(Blob));
// allocate byte array with size of blob.nLength
byte[] meetingBlob = new byte[blob.nLength];
// marshal the data pointed to by pData into the byte array
System.Runtime.InteropServices.Marshal.Copy(blob.pData, meetingBlob, 0,
blob.nLength);
// use the byate array


Willy.
 
W

Willy Denoyette [MVP]

Willy Denoyette said:
Pucca said:
Hi, I'm using vs2005, .net 2, C# for Windows application. I use
DllImport so
I can call up a function written in C++ as unmanaged code and compiled as
a
dll us vs2005. My application is able to call the function,
EncodeAsnUser.
And it's returning OK but when I display the decoded data in another part
of
my application it shows no data has been decoded, all fiedls are either
null
or blanks. For some reason, I am not able to step through this
function's
code. However, I can see the userContextData does hold all the data that
I
assigned and that it's passing.
I think the pbroblems is with my declaration of the parameters(blob and
the
userdata structure) .
1. Am I passing the userContextData as a pointer to the function?
2. Am I allocating memory correctly for the Blob?
3. Am I passing the Blob** correctly?
Can someone see what I need to correct here to make it work? Thank you.

[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
public class CUserContextData
{
public int bWinLogOn = 0;
public int bUnifiedID = 0;

[MarshalAs(UnmanagedType.ByValTStr, SizeConst =
MAX_ADSPATH_CHARS)]
public String shell = null;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst =
MAX_ADSPATH_CHARS)]
public String homeDir = null;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst =
MAX_ADSPATH_CHARS)]
public String primaryGroupSID = null;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst =
MAX_ADSPATH_CHARS)]
public String LoginName = null;

public int symarkUID = 0; //Unified User ID
public int IID = 0; //Independant ID
public int Revision = 0;
}

public struct Blob
{
public IntPtr pData;
public int nLength;
public int nSize;
}

public class LibWrap
{
[DllImport("UnityDecodeAsnUser.dll", CharSet =
CharSet.Unicode)]
public static extern DE_ERRORS EncodeAsnUser(ref Blob blob,
[In, Out]CUserContextData m);
}

// create an instance of the Blob structure
CUnityDS.Blob blob = new CUnityDS.Blob();
//Encode the user data into a blob
int nBytes =
Marshal.SizeOf(typeof(CUnityDS.Blob));
IntPtr ptr = Marshal.AllocHGlobal(nBytes);


// copy and pin the structure to that location
Marshal.StructureToPtr(blob, ptr, true);

// Pass it by reference
// OK, now it's time to "reconsitute" the
structure
blob = (CUnityDS.Blob)Marshal.PtrToStructure(ptr,
typeof(CUnityDS.Blob));


CUnityDS.DE_ERRORS errcode =
CUnityDS.DE_ERRORS.DE_MEMORY_ALLOCATION_FAILURE;
errcode = CUnityDS.LibWrap.EncodeAsnUser(ref blob,
userContextData);

//Convert from IntPtr data to byte[] which is
needed
for adding as meetingBlob
int size = Marshal.SizeOf(blob);
byte[] meetingBlob = new byte[size];

System.Runtime.InteropServices.Marshal.Copy(blob.pData, meetingBlob, 0,
size);
//add the blob

deNewContextObject.Properties["meetingBlob"].Add((object)meetingBlob);

deNewContextObject.CommitChanges();

//This is the C++ function that I'm calling
extern "C" DE_ERRORS __declspec(dllexport)EncodeAsnUser(Blob** ppBlob,
CUserContextData *userData)
{
_bstr_t temp;
AsnData* pAsn;
std::wstring wsUID;
int REVISION=0;
const char* EMPTY_STRING;
EMPTY_STRING = "";

if ( ( pAsn = AsnAlloc( NULL ) ) == NULL )
{
DbgLog( DL_ERROR, "Unable to allocate ASN.1 buffer" );
return DE_MEMORY_ALLOCATION_FAILURE;
}
if ( !AsnPushTag(pAsn, (ASN_TAG$APPLICATION_START) ) )
goto failed;

if (!AsnWriteInteger( pAsn, REVISION))
goto failed;

if(userData->bUnifiedID)//use UID
{
if (!AsnWriteInteger( pAsn, True) )
goto failed;
}
else //use indep ID
{
if (!AsnWriteInteger( pAsn, False) )
goto failed;
}
if(userData->IID == NULL)
{
if ( !AsnWriteGeneralString( pAsn, EMPTY_STRING))
goto failed;
}
else
{
_bstr_t bstrtUID = L"0"; //initilize the bstr
_itow(userData->IID, bstrtUID, 10);

if ( !AsnWriteGeneralString( pAsn, (char*)bstrtUID))
goto failed;
}

//WinUser name
if(userData->bWinLogOn)
{
if (!AsnWriteInteger( pAsn, True) )
goto failed;

}
else//use indep User Name
{
if (!AsnWriteInteger( pAsn, False) )
goto failed;
}

//Geco
if ( !AsnWriteGeneralString( pAsn, EMPTY_STRING))
goto failed;

//Shell
temp = userData->shell;
if ( !AsnWriteGeneralString( pAsn, (char*)temp))
goto failed;

//Home Driectory
temp = userData->homeDir;
if ( !AsnWriteGeneralString( pAsn, (char*)temp))
goto failed;

//Primary Group SID
temp = userData->primaryGroupSID;
if (!AsnWriteGeneralString( pAsn, (char*)temp))
goto failed;

if ( !AsnPopTag( pAsn ) )
goto failed;
*ppBlob = AsnExtractData( pAsn );
AsnFree( pAsn );
return DE_SUCCESS;

failed:
DbgLog(DL_ERROR, "Failed to encode ASN.1 message packet" );
AsnFree( pAsn );
return DE_ENCODE_MESSAGE_PACKET_FAILURE;



Pucca, You have a wrong idea abut how the Blob structure looks like.
This struct holds a pointer and two integers, that means it's length is 12
bytes (in a 32 bit application), while you think that this struct holds
the actual data of the blob on return, it just holds a pointer to the data
and (I assume) the length of the actual data in nLength and the length of
the buffer for the data in nSize.

Note that here I assume that the "AsnExtractData" function called in the
EncodeAsnUser function effectively fills the Blob with the data pointer
and the size of the data in the buffer and the size of buffer .

One way to get at the Blob and the Data is shown in the followin:

[DllImport(...]
public static extern DE_ERRORS EncodeAsnUser(ref IntPtr blob, ...
...
// allocate memry for the blob
IntPtr pBlob = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(Blob)));
// call the function passing the pointer to the blob byref
EncodeAsnUser(ref pBlob, userContextData);
// copy the unmanaged blob to managed struct Blob
Blob blob = (Blob)Marshal.PtrToStructure(pBlob, typeof(Blob));
// allocate byte array with size of blob.nLength
byte[] meetingBlob = new byte[blob.nLength];
// marshal the data pointed to by pData into the byte array
System.Runtime.InteropServices.Marshal.Copy(blob.pData, meetingBlob, 0,
blob.nLength);
// use the byate array


Willy.



Note that when the callee requires the caller to allocate the buffer for the
Data (which I assume is the case), then you need to change to code into
something like:

....
int dataSize = 512; // assume 512 byte buffer
IntPtr pBlob = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(Blob)));
IntPtr pData = Marshal.AllocHGlobal(dataSize );
Blob blob = new Blob();
blob.nSize = dataSize ;
blob.pData = pData;
Marshal.StructureToPtr(blob, pBlob, true);
EncodeAsnUser(ref pBlob);
// check return value from function
// and proceed is success...
blob = (Blob)Marshal.PtrToStructure(pBlob, typeof(Blob));
// assuming nLength is the size in bytes returned in the buffer pointed
to by pData!!
byte[] meetingBlob = new byte[blob.nLength];
Marshal.Copy(blob.pData, meetingBlob, 0, blob.nLength);
// use data in meetingBlob here...
// Free allocated memory!
Marshal.FreeHGlobal(pBlob);
Marshal.FreeHGlobal(pData);


Willy.
 
G

Guest

Hi Willy ,
What you said about the nSize and nLength makes a lot of sense. You're also
right about the pointer to the encoded data pointed by a pointer in the Blob
struc. However, the length of the data is not return by AsnExtractData(code
listed below).
I am getting compliation error with my current code below. I'm getting
error message below. Can you see what I need to correct here? Thank you.

- cannot convert from 'ref System.IntPtr' to 'ref UnityLib.CUnityDS.Blob'
- The best overloaded method match for
UnityLib.CUnityDS.LibWrap.EncodeAsnUser(ref UnityLib.CUnityDS.Blob,
UnityLib.CUnityDS.CUserContextData)' has some invalid arguments

int dataSize = 512; // assume 512 byte buffer
IntPtr pBlob = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(CUnityDS.Blob)));
IntPtr pData = Marshal.AllocHGlobal(dataSize );
//CUnityDS.Blob blob = new CUnityDS.Blob();
blob.nSize = dataSize ;
blob.pData = pData;
Marshal.StructureToPtr(blob, pBlob, true);
CUnityDS.LibWrap.EncodeAsnUser(ref pBlob, userContextData);
// check return value from function
// and proceed is success...
blob = (CUnityDS.Blob)Marshal.PtrToStructure(pBlob, typeof(CUnityDS.Blob));
// assuming nLength is the size in bytes returned in the buffer pointed to
by pData!!
byte[] meetingBlob = new byte[blob.nLength];
Marshal.Copy(blob.pData, meetingBlob, 0, blob.nLength);
// use data in meetingBlob here...
// Free allocated memory!
Marshal.FreeHGlobal(pBlob);
Marshal.FreeHGlobal(pData);

-- Blob *
AsnExtractData( AsnData *pAsn )
{
Blob *p;

if ( pAsn == NULL )
return NULL;

p = pAsn->pBlob;
pAsn->pBlob = NULL;

return p;
}
Thanks.


Willy Denoyette said:
Pucca said:
Hi, I'm using vs2005, .net 2, C# for Windows application. I use DllImport
so
I can call up a function written in C++ as unmanaged code and compiled as
a
dll us vs2005. My application is able to call the function,
EncodeAsnUser.
And it's returning OK but when I display the decoded data in another part
of
my application it shows no data has been decoded, all fiedls are either
null
or blanks. For some reason, I am not able to step through this function's
code. However, I can see the userContextData does hold all the data that
I
assigned and that it's passing.
I think the pbroblems is with my declaration of the parameters(blob and
the
userdata structure) .
1. Am I passing the userContextData as a pointer to the function?
2. Am I allocating memory correctly for the Blob?
3. Am I passing the Blob** correctly?
Can someone see what I need to correct here to make it work? Thank you.

[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
public class CUserContextData
{
public int bWinLogOn = 0;
public int bUnifiedID = 0;

[MarshalAs(UnmanagedType.ByValTStr, SizeConst =
MAX_ADSPATH_CHARS)]
public String shell = null;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst =
MAX_ADSPATH_CHARS)]
public String homeDir = null;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst =
MAX_ADSPATH_CHARS)]
public String primaryGroupSID = null;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst =
MAX_ADSPATH_CHARS)]
public String LoginName = null;

public int symarkUID = 0; //Unified User ID
public int IID = 0; //Independant ID
public int Revision = 0;
}

public struct Blob
{
public IntPtr pData;
public int nLength;
public int nSize;
}

public class LibWrap
{
[DllImport("UnityDecodeAsnUser.dll", CharSet =
CharSet.Unicode)]
public static extern DE_ERRORS EncodeAsnUser(ref Blob blob,
[In, Out]CUserContextData m);
}

// create an instance of the Blob structure
CUnityDS.Blob blob = new CUnityDS.Blob();
//Encode the user data into a blob
int nBytes = Marshal.SizeOf(typeof(CUnityDS.Blob));
IntPtr ptr = Marshal.AllocHGlobal(nBytes);


// copy and pin the structure to that location
Marshal.StructureToPtr(blob, ptr, true);

// Pass it by reference
// OK, now it's time to "reconsitute" the structure
blob = (CUnityDS.Blob)Marshal.PtrToStructure(ptr,
typeof(CUnityDS.Blob));


CUnityDS.DE_ERRORS errcode =
CUnityDS.DE_ERRORS.DE_MEMORY_ALLOCATION_FAILURE;
errcode = CUnityDS.LibWrap.EncodeAsnUser(ref blob,
userContextData);

//Convert from IntPtr data to byte[] which is
needed
for adding as meetingBlob
int size = Marshal.SizeOf(blob);
byte[] meetingBlob = new byte[size];

System.Runtime.InteropServices.Marshal.Copy(blob.pData, meetingBlob, 0,
size);
//add the blob

deNewContextObject.Properties["meetingBlob"].Add((object)meetingBlob);

deNewContextObject.CommitChanges();

//This is the C++ function that I'm calling
extern "C" DE_ERRORS __declspec(dllexport)EncodeAsnUser(Blob** ppBlob,
CUserContextData *userData)
{
_bstr_t temp;
AsnData* pAsn;
std::wstring wsUID;
int REVISION=0;
const char* EMPTY_STRING;
EMPTY_STRING = "";

if ( ( pAsn = AsnAlloc( NULL ) ) == NULL )
{
DbgLog( DL_ERROR, "Unable to allocate ASN.1 buffer" );
return DE_MEMORY_ALLOCATION_FAILURE;
}
if ( !AsnPushTag(pAsn, (ASN_TAG$APPLICATION_START) ) )
goto failed;

if (!AsnWriteInteger( pAsn, REVISION))
goto failed;

if(userData->bUnifiedID)//use UID
{
if (!AsnWriteInteger( pAsn, True) )
goto failed;
}
else //use indep ID
{
if (!AsnWriteInteger( pAsn, False) )
goto failed;
}
if(userData->IID == NULL)
{
if ( !AsnWriteGeneralString( pAsn, EMPTY_STRING))
goto failed;
}
else
{
_bstr_t bstrtUID = L"0"; //initilize the bstr
_itow(userData->IID, bstrtUID, 10);

if ( !AsnWriteGeneralString( pAsn, (char*)bstrtUID))
goto failed;
}

//WinUser name
if(userData->bWinLogOn)
{
if (!AsnWriteInteger( pAsn, True) )
goto failed;

}
else//use indep User Name
{
if (!AsnWriteInteger( pAsn, False) )
goto failed;
}

//Geco
if ( !AsnWriteGeneralString( pAsn, EMPTY_STRING))
goto failed;

//Shell
temp = userData->shell;
if ( !AsnWriteGeneralString( pAsn, (char*)temp))
goto failed;

//Home Driectory
temp = userData->homeDir;
if ( !AsnWriteGeneralString( pAsn, (char*)temp))
goto failed;

//Primary Group SID
temp = userData->primaryGroupSID;
if (!AsnWriteGeneralString( pAsn, (char*)temp))
goto failed;

if ( !AsnPopTag( pAsn ) )
goto failed;
*ppBlob = AsnExtractData( pAsn );
AsnFree( pAsn );
return DE_SUCCESS;

failed:
DbgLog(DL_ERROR, "Failed to encode ASN.1 message packet" );
AsnFree( pAsn );
return DE_ENCODE_MESSAGE_PACKET_FAILURE;



Pucca, You have a wrong idea abut how the Blob structure looks like.
This struct holds a pointer and two integers, that means it's length is 12
bytes (in a 32 bit application), while you think that this struct holds the
actual data of the blob on return, it just holds a pointer to the data and
(I assume) the length of the actual data in nLength and the length of the
buffer for the data in nSize.

Note that here I assume that the "AsnExtractData" function called in the
EncodeAsnUser function effectively fills the Blob with the data pointer and
the size of the data in the buffer and the size of buffer .

One way to get at the Blob and the Data is shown in the followin:

[DllImport(...]
public static extern DE_ERRORS EncodeAsnUser(ref IntPtr blob, ...
...
// allocate memry for the blob
IntPtr pBlob = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(Blob)));
// call the function passing the pointer to the blob byref
EncodeAsnUser(ref pBlob, userContextData);
// copy the unmanaged blob to managed struct Blob
Blob blob = (Blob)Marshal.PtrToStructure(pBlob, typeof(Blob));
// allocate byte array with size of blob.nLength
byte[] meetingBlob = new byte[blob.nLength];
// marshal the data pointed to by pData into the byte array
System.Runtime.InteropServices.Marshal.Copy(blob.pData, meetingBlob, 0,
blob.nLength);
// use the byate array


Willy.
 
W

Willy Denoyette [MVP]

Pucca said:
Hi Willy ,
What you said about the nSize and nLength makes a lot of sense. You're
also
right about the pointer to the encoded data pointed by a pointer in the
Blob
struc. However, the length of the data is not return by
AsnExtractData(code
listed below).
I am getting compliation error with my current code below. I'm getting
error message below. Can you see what I need to correct here? Thank you.

- cannot convert from 'ref System.IntPtr' to 'ref
UnityLib.CUnityDS.Blob'
- The best overloaded method match for
UnityLib.CUnityDS.LibWrap.EncodeAsnUser(ref UnityLib.CUnityDS.Blob,
UnityLib.CUnityDS.CUserContextData)' has some invalid arguments

int dataSize = 512; // assume 512 byte buffer
IntPtr pBlob =
Marshal.AllocHGlobal(Marshal.SizeOf(typeof(CUnityDS.Blob)));
IntPtr pData = Marshal.AllocHGlobal(dataSize );
//CUnityDS.Blob blob = new CUnityDS.Blob();
blob.nSize = dataSize ;
blob.pData = pData;
Marshal.StructureToPtr(blob, pBlob, true);
CUnityDS.LibWrap.EncodeAsnUser(ref pBlob, userContextData);
// check return value from function
// and proceed is success...
blob = (CUnityDS.Blob)Marshal.PtrToStructure(pBlob,
typeof(CUnityDS.Blob));
// assuming nLength is the size in bytes returned in the buffer pointed to
by pData!!
byte[] meetingBlob = new byte[blob.nLength];
Marshal.Copy(blob.pData, meetingBlob, 0, blob.nLength);
// use data in meetingBlob here...
// Free allocated memory!
Marshal.FreeHGlobal(pBlob);
Marshal.FreeHGlobal(pData);

-- Blob *
AsnExtractData( AsnData *pAsn )
{
Blob *p;

if ( pAsn == NULL )
return NULL;

p = pAsn->pBlob;
pAsn->pBlob = NULL;

return p;
}
Thanks.


UnityLib.CUnityDS.LibWrap.EncodeAsnUser(ref UnityLib.CUnityDS.Blob,
UnityLib.CUnityDS.CUserContextData)' has some invalid arguments

should read:

UnityLib.CUnityDS.LibWrap.EncodeAsnUser(ref IntPtr,
UnityLib.CUnityDS.CUserContextData)' has some invalid arguments

Don't know who has written the C++ function, I would definitely ask for a
rewrite, anyway it needs to return the length of the Data in the blob,
otherwise there is no way to correctly marshal the data back at the caller
side.

Willy.
 
G

Guest

Hi Willy,
I step through my C++ program that calls the same function, EncodeAsnUser,
and it does returns the nLength, data length when it returns encoding data
into the blob. I think if I am passing in the correct parameters then the
nLength will be set.
Sorry that i copy the error message incorrectly but you got it right there.
It doesn't like the pBlob that I'm declaring and passing. How should I
correct this? Thank you.
--
Thanks.


Willy Denoyette said:
Pucca said:
Hi Willy ,
What you said about the nSize and nLength makes a lot of sense. You're
also
right about the pointer to the encoded data pointed by a pointer in the
Blob
struc. However, the length of the data is not return by
AsnExtractData(code
listed below).
I am getting compliation error with my current code below. I'm getting
error message below. Can you see what I need to correct here? Thank you.

- cannot convert from 'ref System.IntPtr' to 'ref
UnityLib.CUnityDS.Blob'
- The best overloaded method match for
UnityLib.CUnityDS.LibWrap.EncodeAsnUser(ref UnityLib.CUnityDS.Blob,
UnityLib.CUnityDS.CUserContextData)' has some invalid arguments

int dataSize = 512; // assume 512 byte buffer
IntPtr pBlob =
Marshal.AllocHGlobal(Marshal.SizeOf(typeof(CUnityDS.Blob)));
IntPtr pData = Marshal.AllocHGlobal(dataSize );
//CUnityDS.Blob blob = new CUnityDS.Blob();
blob.nSize = dataSize ;
blob.pData = pData;
Marshal.StructureToPtr(blob, pBlob, true);
CUnityDS.LibWrap.EncodeAsnUser(ref pBlob, userContextData);
// check return value from function
// and proceed is success...
blob = (CUnityDS.Blob)Marshal.PtrToStructure(pBlob,
typeof(CUnityDS.Blob));
// assuming nLength is the size in bytes returned in the buffer pointed to
by pData!!
byte[] meetingBlob = new byte[blob.nLength];
Marshal.Copy(blob.pData, meetingBlob, 0, blob.nLength);
// use data in meetingBlob here...
// Free allocated memory!
Marshal.FreeHGlobal(pBlob);
Marshal.FreeHGlobal(pData);

-- Blob *
AsnExtractData( AsnData *pAsn )
{
Blob *p;

if ( pAsn == NULL )
return NULL;

p = pAsn->pBlob;
pAsn->pBlob = NULL;

return p;
}
Thanks.


UnityLib.CUnityDS.LibWrap.EncodeAsnUser(ref UnityLib.CUnityDS.Blob,
UnityLib.CUnityDS.CUserContextData)' has some invalid arguments

should read:

UnityLib.CUnityDS.LibWrap.EncodeAsnUser(ref IntPtr,
UnityLib.CUnityDS.CUserContextData)' has some invalid arguments

Don't know who has written the C++ function, I would definitely ask for a
rewrite, anyway it needs to return the length of the Data in the blob,
otherwise there is no way to correctly marshal the data back at the caller
side.

Willy.
 
W

Willy Denoyette [MVP]

Pucca said:
Hi Willy,
I step through my C++ program that calls the same function, EncodeAsnUser,
and it does returns the nLength, data length when it returns encoding data
into the blob. I think if I am passing in the correct parameters then the
nLength will be set.
Sorry that i copy the error message incorrectly but you got it right
there.
It doesn't like the pBlob that I'm declaring and passing. How should I
correct this? Thank you.
--

I can't help you if you don't post *all* of the relevant part of the code,
together with the DllImport declaration of the function you call.
Also you need to tell us what exactly is the error, after you have changed
the first argument into a "ref IntPtr" !!.


Willy.
 
G

Guest

Very sorry Willy. Sometimes I wonder how much code should I post. It just
seems like a lot but I'll post them all in the future. Here are all the C++
functions called by the AsnEncodeUser function. Also, here is my current
code. I modify to pass only the blob as the parameter. It gets rid of the
compiling error but I'm still getting back 0 nlength after Encode. thank
you.
errcode = CUnityDS.LibWrap.EncodeAsnUser(ref blob, userContextData);

//current code
int dataSize = 512; // assume 512 byte buffer
IntPtr pBlob =
Marshal.AllocHGlobal(Marshal.SizeOf(typeof (CUnityDS.Blob)));
IntPtr pData = Marshal.AllocHGlobal(dataSize );
//CUnityDS.Blob blob = new CUnityDS.Blob();
blob.nSize = dataSize ;
blob.pData = pData;
Marshal.StructureToPtr(blob, pBlob, true);
// check return value from function
CUnityDS.DE_ERRORS errcode =
CUnityDS.DE_ERRORS.DE_MEMORY_ALLOCATION_FAILURE;
errcode = CUnityDS.LibWrap.EncodeAsnUser(ref blob,
userContextData);
if (errcode != CUnityDS.DE_ERRORS.DE_SUCCESS)
result = false;
else
{
blob =
(CUnityDS.Blob)Marshal.PtrToStructure(pBlob, typeof(CUnityDS.Blob));
// nLength is the size in bytes returned in the
buffer pointed to by pData!!
// use data in meetingBlob
byte[] meetingBlob = new byte[blob.nLength];
Marshal.Copy(blob.pData, meetingBlob, 0,
blob.nLength);
// Free allocated memory!
Marshal.FreeHGlobal(pBlob);
Marshal.FreeHGlobal(pData);


//add the blob

deNewContextObject.Properties["meetingBlob"].Add((object)meetingBlob);

deNewContextObject.CommitChanges();


//Additional C++ fucnctions called by AsnEncodeUser
AsnData *
AsnAlloc( Blob * pBlob )
{
AsnData * pAsn;

pAsn = (AsnData *)calloc(1, sizeof(AsnData));
if ( pAsn == NULL )
return NULL;

if ( pBlob )
pAsn->pBlob = BlobClone( pBlob );
else
pAsn->pBlob = BlobAlloc( NULL, 256 );

if ( pAsn->pBlob == NULL )
{
free( pAsn );
return NULL;
}

return pAsn;
}

Bool
AsnPushTag(AsnData *pAsn, ASN_TAG tag)
{
AsnNode *pNode;

if (!AsnWriteByte(pAsn, tag))
return False;

pNode = (AsnNode*)calloc(1, sizeof(AsnNode));
if (!pNode)
return False;

pNode->nStart = BlobGetLength(pAsn->pBlob);
pNode->pNext = pAsn->pNode;
pAsn->pNode = pNode;

return AsnWriteByte(pAsn, 0); /* placeholder for length */
}

Bool
AsnWriteInteger(AsnData *pAsn, int nValue)
{
int i = 0;
Bit8 szBuf[sizeof(nValue)];

if (!AsnPushTag(pAsn, ASN_TAG$INTEGER))
return False;

/* Make sure we store the integer in an endian neutral form */
do
{
szBuf[i++] = nValue & 0xFF;
nValue >>= 8;
} while ( nValue );

do
{
if (!AsnWriteByte(pAsn, szBuf[--i]))
return False;
} while ( i );

return AsnPopTag(pAsn);
}


Bool
AsnWriteGeneralString(AsnData *pAsn, const char *p)
{
return (((AsnPushTag(pAsn, ASN_TAG$GENERAL_STRING)==True) &&
(AsnWrite(pAsn, p, strlen(p))==True) &&
(AsnPopTag(pAsn)==True)
)==True) ? True : False;
}


Bool
AsnPopTag(AsnData *pAsn)
{
AsnNode *pNode;
Bit32 nLength;

pNode = pAsn->pNode;

if (!pNode)
return False;

nLength = BlobGetLength(pAsn->pBlob) - (pNode->nStart + 1);

/* Now we can go back and write the actual length of the node */
if ( nLength <= 127 )
pAsn->pBlob->pData[pNode->nStart] = nLength;
else if ( nLength <= 255 )
{
/* We need to write a two-byte length - make sure we have room */
if (!AsnWriteByte(pAsn, 0))
return False;

/* Move data down one byte */
memmove(pAsn->pBlob->pData + pNode->nStart + 2,
pAsn->pBlob->pData + pNode->nStart + 1,
nLength);

pAsn->pBlob->pData[pNode->nStart ] = 0x81;
pAsn->pBlob->pData[pNode->nStart + 1] = nLength;
}
else
{
/* We need to write a three-byte length - make sure we have room */
if (!AsnWriteByte(pAsn, 0))
return False;
if (!AsnWriteByte(pAsn, 0))
return False;

/* Move data down two bytes */
memmove(pAsn->pBlob->pData + pNode->nStart + 3,
pAsn->pBlob->pData + pNode->nStart + 1,
nLength);

pAsn->pBlob->pData[pNode->nStart ] = 0x82;
pAsn->pBlob->pData[pNode->nStart + 1] = nLength >> 8;
pAsn->pBlob->pData[pNode->nStart + 2] = nLength & 0xff;
}

pAsn->pNode = pNode->pNext;
free(pNode);

return True;
}


Blob *
AsnExtractData( AsnData *pAsn )
{
Blob *p;

if ( pAsn == NULL )
return NULL;

p = pAsn->pBlob;
pAsn->pBlob = NULL;

return p;
}
 
G

Guest

Hi Willy,
I can't thank you enough for helping me with this difficult problem. It is
now working! You were right from the very 1st posting. The function takes
care of allocating all the memory for the data so I don't need to allocating
any memory except for the pointer that I'm passing as you have it in your
first example. It didn't work the 1st time because, 1, I used your 2nd
example where we allocate all the memory. And 2, I missed the change in the
declaration of "ref IntPtr blob" as shown below. That made all the
difference. Now all my data are showing up correctly. Thank you and thank
you again!

DllImport(...]
public static extern DE_ERRORS EncodeAsnUser(ref IntPtr blob, ...
 

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