PC Review


Reply
Thread Tools Rate Thread

consuming unmanaged DLL from managed C#

 
 
Tremendo
Guest
Posts: n/a
 
      15th Jan 2007
[I posted this in ...dotnet.framework.interop last week, with no luck. The question seems long, but
I think that the answer should be easy and quick for someone who knows it.]

Hi,

I need to consume an unmanaged DLL from managed C#. The DLL is "ae766.dll". I have problems with one
function in it. Who developed the DLL, provided the following information, regarding that function:

-----------------------------
Declaration
-----------------------------

extern "C" long __stdcall GetAnalyzerTraceData(LPSAFEARRAY FAR *);

-----------------------------
Description of the function
-----------------------------

GetAnalyzerTraceData(LPSAFEARRAY FAR *);

A call to this routine will result in one trace of data being returned. A pointer to an array of
BYTE type (in Visual Basic) should be passed in. This array

will be allocated, initialized, and the data from the unit will be located in it as binary data.


The structure of the data is as follows:

Struct Data
{
char freq[7]; //center frequency (ascii characters) in units of kHz
char span; //Decimal index indicating the current span
char ref_level; //Decimal index indicating the current reference level
char RBW[7]; //ascii characters indicating the current RBW
unsigned char data[1000];
unsigned char checksum; //checksum of the bytes
unsigned char reserved; //unused
}

The total length of the data is 1018 bytes. The “data” portion of the structure is the actual trace
data.

A return value of 1 indicates success. A return value of 0 indicates a failure while attempting to
read from the GSA-810.

-----------------------------


What C# code do I need to write, to "translate" the struct and to import the function? You don't
need to write the whole code for me, because there are repeated data types (inside the struct, for
instance). A hint about how to do it should be enough.

Thank you very much.

 
Reply With Quote
 
 
 
 
Willy Denoyette [MVP]
Guest
Posts: n/a
 
      15th Jan 2007
"Tremendo" <(E-Mail Removed)> wrote in message
news:(E-Mail Removed)...
> [I posted this in ...dotnet.framework.interop last week, with no luck. The question seems
> long, but
> I think that the answer should be easy and quick for someone who knows it.]
>
> Hi,
>
> I need to consume an unmanaged DLL from managed C#. The DLL is "ae766.dll". I have
> problems with one
> function in it. Who developed the DLL, provided the following information, regarding that
> function:
>
> -----------------------------
> Declaration
> -----------------------------
>
> extern "C" long __stdcall GetAnalyzerTraceData(LPSAFEARRAY FAR *);
>
> -----------------------------
> Description of the function
> -----------------------------
>
> GetAnalyzerTraceData(LPSAFEARRAY FAR *);
>
> A call to this routine will result in one trace of data being returned. A pointer to an
> array of
> BYTE type (in Visual Basic) should be passed in. This array
>
> will be allocated, initialized, and the data from the unit will be located in it as binary
> data.
>
>
> The structure of the data is as follows:
>
> Struct Data
> {
> char freq[7]; //center frequency (ascii characters) in units of kHz
> char span; //Decimal index indicating the current span
> char ref_level; //Decimal index indicating the current reference level
> char RBW[7]; //ascii characters indicating the current RBW
> unsigned char data[1000];
> unsigned char checksum; //checksum of the bytes
> unsigned char reserved; //unused
> }
>
> The total length of the data is 1018 bytes. The "data" portion of the structure is the
> actual trace
> data.
>
> A return value of 1 indicates success. A return value of 0 indicates a failure while
> attempting to
> read from the GSA-810.
>
> -----------------------------
>
>
> What C# code do I need to write, to "translate" the struct and to import the function? You
> don't
> need to write the whole code for me, because there are repeated data types (inside the
> struct, for
> instance). A hint about how to do it should be enough.
>
> Thank you very much.
>



The function takes a pointer to a safearray pointer (LPSAFEARRAY FAR *), the safearray being
a BYTE array. But in reality the BYTE[] is a flat structure of type Data. It's weird that a
record (UDT) is flatten-out like this, if you are sure about this, then the following is
how you could handle the marshaling:


[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
struct Data
{
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 7)]
internal char[] freq; //center frequency (ascii characters) in units of kHz
internal char span; //Decimal index indicating the current span
internal char ref_level; //Decimal index indicating the current reference level
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 7)]
internal char[] RBW; //ascii characters indicating the current RBW
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 1000)]
internal byte[] data;
internal byte checksum; //checksum of the bytes
internal byte reserved; //unused
}

[DllImport("yourDll"), SuppressUnmanagedCodeSecurity]
static extern int GetAnalyzerTraceData
([Out, MarshalAs( UnmanagedType.SafeArray )] out byte[] sa);

IntPtr pnt = IntPtr.Zero;
try {
byte[] buffer = null;
if(GetAnalyzerTraceData(out buffer) == 0)
{
throw....
}
pnt = Marshal.AllocHGlobal(Marshal.SizeOf(data));
Marshal.Copy(buffer, 0, pnt, buffer.Length);
Data data = (Data)Marshal.PtrToStructure(pnt, typeof(Data));
// process data...
}
finally {
Marshal.FreeHGlobal(pnt);
}


Willy.

 
Reply With Quote
 
Tremendo
Guest
Posts: n/a
 
      18th Jan 2007
Willy,

Thank you very much for your time and effort. I haven't had time to try what you wrote until today.

Comments:
1) I have been unable to use the parameter "SuppressUnmanagedCodeSecurity" that you proposed. It
said something like that it is not a valid parameter for DllImport. I ended up not specifying that
parameter, and everything compiled ok.
2) All functions in "ae766.dll" except "GetAnalyzerTraceData" work ok in run time. I communicate
correctly with the spectrum analyzer. It looks like, therefore, that I can live without
"SuppressUnmanagedCodeSecurity", at least regarding those functions.
3) The only function that does not work ok is "GetAnalyzerTraceData". I get a run time error saying
something like (I have it in Spanish (against my will)) "Entry point 'GetAnalyzerTraceData' could
not be found in DLL file 'ae766.dll'". This error message points to line marked as "RUN TIME ERROR"
in the following code:

------------------
[DllImport("ae766.dll")] private static extern int GetSerialNum();
[DllImport("ae766.dll")] private static extern int SetFreq(int freq);
....
[DllImport("ae766.dll")] private static extern int
GetAnalyzerTraceData([Out,MarshalAs(UnmanagedType.SafeArray)] out byte[] buffer);

....

try
{
if (1!=GetAnalyzerTraceData(out buffer)) // <--- RUN TIME ERROR
{
// throw an exception.
return(false);
}
pnt =Marshal.AllocHGlobal(Marshal.SizeOf(data));
Marshal.Copy(buffer,0,pnt,buffer.Length);
data =(TraceData)Marshal.PtrToStructure(pnt,typeof(TraceData));
...
}
finally
{
Marshal.FreeHGlobal(pnt);
}
------------------

It is strange that the entry points of all the other functions in the DLL are found, but this one is
not. Unfortunately, this is the most important function, and I really need to call it. I've opened
the DLL with an hex viewer, and I do see a string named 'GETANALYZERTRACEDATA'.


Do you think that the error is in something that I'm coding, or in something in the DLL?

Is there any software tool that I can use to analyze what's inside a DLL, and what valid entry
points it "shows"?


Again, thank you very much.
Tremendo


 
Reply With Quote
 
Willy Denoyette [MVP]
Guest
Posts: n/a
 
      18th Jan 2007
"Tremendo" <(E-Mail Removed)> wrote in message
news:(E-Mail Removed)...
> Willy,
>
> Thank you very much for your time and effort. I haven't had time to try what you wrote
> until today.
>
> Comments:
> 1) I have been unable to use the parameter "SuppressUnmanagedCodeSecurity" that you
> proposed. It
> said something like that it is not a valid parameter for DllImport. I ended up not
> specifying that
> parameter, and everything compiled ok.


You have to include the System.Security namespace for this, this attribute is a great help
when interop performance is important, it save some µsec per call.

> 2) All functions in "ae766.dll" except "GetAnalyzerTraceData" work ok in run time. I
> communicate
> correctly with the spectrum analyzer. It looks like, therefore, that I can live without
> "SuppressUnmanagedCodeSecurity", at least regarding those functions.


> 3) The only function that does not work ok is "GetAnalyzerTraceData". I get a run time
> error saying
> something like (I have it in Spanish (against my will)) "Entry point
> 'GetAnalyzerTraceData' could
> not be found in DLL file 'ae766.dll'". This error message points to line marked as "RUN
> TIME ERROR"
> in the following code:
>
> ------------------
> [DllImport("ae766.dll")] private static extern int GetSerialNum();
> [DllImport("ae766.dll")] private static extern int SetFreq(int freq);
> ...
> [DllImport("ae766.dll")] private static extern int
> GetAnalyzerTraceData([Out,MarshalAs(UnmanagedType.SafeArray)] out byte[] buffer);
>
> ...
>
> try
> {
> if (1!=GetAnalyzerTraceData(out buffer)) // <--- RUN TIME ERROR
> {
> // throw an exception.
> return(false);
> }
> pnt =Marshal.AllocHGlobal(Marshal.SizeOf(data));
> Marshal.Copy(buffer,0,pnt,buffer.Length);
> data =(TraceData)Marshal.PtrToStructure(pnt,typeof(TraceData));
> ...
> }
> finally
> {
> Marshal.FreeHGlobal(pnt);
> }
> ------------------
>
> It is strange that the entry points of all the other functions in the DLL are found, but
> this one is
> not. Unfortunately, this is the most important function, and I really need to call it.
> I've opened
> the DLL with an hex viewer, and I do see a string named 'GETANALYZERTRACEDATA'.
>
>


> Do you think that the error is in something that I'm coding, or in something in the DLL?
>
> Is there any software tool that I can use to analyze what's inside a DLL, and what valid
> entry
> points it "shows"?
>



Try dumpbin.exe with the option /exports, another tool you can use is depends.exe.
Note that none of the COM interface methods are exported functions, so you have to make sure
the DLL is not a COM server DLL.

Willy.


 
Reply With Quote
 
Tremendo
Guest
Posts: n/a
 
      19th Jan 2007
On Thu, 18 Jan 2007 17:30:19 +0100, "Willy Denoyette [MVP]" <(E-Mail Removed)> wrote:

>"Tremendo" <(E-Mail Removed)> wrote in message
>news:(E-Mail Removed)...
>> Willy,
>>
>> Thank you very much for your time and effort. I haven't had time to try what you wrote
>> until today.
>>
>> Comments:
>> 1) I have been unable to use the parameter "SuppressUnmanagedCodeSecurity" that you
>> proposed. It
>> said something like that it is not a valid parameter for DllImport. I ended up not
>> specifying that
>> parameter, and everything compiled ok.

>
>You have to include the System.Security namespace for this, this attribute is a great help
>when interop performance is important, it save some µsec per call.


Ok, now it accepts that parameter.

I'll try with the DLL inspecting tools you mentioned.

Thanks.

 
Reply With Quote
 
Tremendo
Guest
Posts: n/a
 
      19th Jan 2007
On Thu, 18 Jan 2007 17:30:19 +0100, "Willy Denoyette [MVP]" <(E-Mail Removed)> wrote:

>Try dumpbin.exe with the option /exports, another tool you can use is depends.exe.
>Note that none of the COM interface methods are exported functions, so you have to make sure
>the DLL is not a COM server DLL.


Sorry about so many questions, but how do I know that the DLL is not a COM server DLL?

"dumpbin.exe /exports ae766.dll" returns the text below. It looks like GETANALYZERTRACEDATA is as
valid an entry point as other functions that are working for me.

Thank you.

--------------------
Microsoft (R) COFF/PE Dumper Version 8.00.50727.42
Copyright (C) Microsoft Corporation. All rights reserved.


Dump of file \tmp\ae766.dll

File Type: DLL

Section contains the following exports for ate_dll.dll

00000000 characteristics
38075C19 time date stamp Fri Oct 15 18:53:45 1999
0.00 version
1 ordinal base
29 number of functions
29 number of names

ordinal hint RVA name

1 0 00002560 CHANGECOMPORT
24 1 00002560 ChangeComPort
2 2 00002220 ECHOOFF
3 3 000022D0 ECHOON
4 4 00001870 EXITTG
5 5 00001D70 EXTREF
6 6 00002040 FPGAVERSION
7 7 00002380 GETANALYZERTRACEDATA
8 8 00001450 GETMARKERLEVEL
9 9 00002940 GETSERIALNUM
25 A 00002940 GetSerialNum
10 B 00001700 MARKERTOCENTER
11 C 00001640 MARKERTOPEAK
12 D 00001930 NORMALIZETG
13 E 000027A0 SETFREQ
14 F 000026E0 SETRBW
15 10 00002670 SETREFLVL
16 11 000025D0 SETSPAN
17 12 000029F0 STARTSTREAMING
18 13 000017B0 STARTTG
19 14 00002B00 STOPSTREAMING
20 15 00001E60 SWVERSION
26 16 000027A0 SetFreq
27 17 000026E0 SetRBW
28 18 00002670 SetReflvl
29 19 000025D0 SetSpan
21 1A 00001B00 TGLEVEL
22 1B 00001C30 TGOFFSET
23 1C 000019E0 TGONOFF

Summary

2000 .data
1000 .idata
1000 .rdata
1000 .reloc
1000 .rsrc
3000 .text
 
Reply With Quote
 
Tremendo
Guest
Posts: n/a
 
      19th Jan 2007
Solved! :-)

All other functions have two entry points, one with text all in uppercase, and another one with text
in upper and lowercase. However, this specific function has only one entry point, with text all in
uppercase. My call was in upper and lower case because the documentation shows it that way (and only
that way). I changed it to all upper case and it works.

Thanks !!

 
Reply With Quote
 
Willy Denoyette [MVP]
Guest
Posts: n/a
 
      19th Jan 2007
"Tremendo" <(E-Mail Removed)> wrote in message
news:(E-Mail Removed)...
> Solved! :-)
>
> All other functions have two entry points, one with text all in uppercase, and another one
> with text
> in upper and lowercase. However, this specific function has only one entry point, with
> text all in
> uppercase. My call was in upper and lower case because the documentation shows it that way
> (and only
> that way). I changed it to all upper case and it works.
>
> Thanks !!
>


Yep, function names are case sensitive. If in doubt you can always use the EntryPoint
attribute and fill it with the ordinal number.

// GETANALYZERTRACEDATA has ordinal 7 (see dumpbin).
[DllImport("xxxx.dll", EntryPoint = "#7")]
...... GetAnaylizerTraceData(...)

Willy.


 
Reply With Quote
 
 
 
Reply

Thread Tools
Rate This Thread
Rate This Thread:

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Trackbacks are On
Pingbacks are On
Refbacks are Off


Similar Threads
Thread Thread Starter Forum Replies Last Post
Managed/Unmanaged code and #pragma managed/unmanaged ajtaylor@hushmail.com Microsoft VC .NET 6 18th Feb 2008 09:33 AM
Access violation in unmanaged code: Linking managed with unmanaged static libs Pixel.to.life Microsoft VC .NET 3 23rd Jul 2007 04:16 AM
consuming managed C# DLL from unmanaged VB6 Tremendo Microsoft C# .NET 5 28th Jan 2007 04:16 PM
Consuming visual managed controls from unmanaged apps (i.e. VB6) Brett Microsoft Dot NET Framework 1 2nd Dec 2004 04:11 PM
Consuming visual managed controls from unmanaged apps (i.e. VB6) Brett Microsoft VB .NET 1 2nd Dec 2004 04:11 PM


Features
 

Advertising
 

Newsgroups
 


All times are GMT +1. The time now is 12:51 PM.