Sign in to follow this  
Main

[.net] How to PInvoke function within a dll

Recommended Posts

Hello Everyone, I need to PInvoke function within a dll, the function signature is (for example): BOOL Foo( PVOID inA, DWORD inB, PVOID outC, DWORD outD, PDWORD outE ); I tried this (C#), with no success : [DllImport("aa.dll")] static extern bool Foo( IntPtr inA, UIntPtr inB, [Out] byte[] outC, UIntPtr outD, IntPtr outE ); Where did I go wrong ? Thanks ! [Edited by - LessBread on June 7, 2006 3:06:51 PM]

Share this post


Link to post
Share on other sites
I'm getting access violation while trying to execute (P-Invoke) this function.
It may be the way I set up values to the parameters,
But first I would like to know if I wrote the "static extern ..." signature currectly..

Share this post


Link to post
Share on other sites
I haven't used PInvoke using C# yet (only VB.NET) so I can't tell you if the signature is right. But you might want to check out PInvoke.NET. It's a wiki dedicated to PInvoke. I'm sure you'll find what you need there

Share this post


Link to post
Share on other sites
Try this:

static extern Int32 Foo(
IntPtr inA,
Int32 inB,
out IntPtr outC,
Int32 outD,
out Int32 outE
);


A BOOL is really an integer, not a bool (although it might still work with a bool instead of Int32). If you know the actual types of inA and outC, you should be able to define sequential layout structures for those and pass them directly, rather than using IntPtr. Note that "outD" implies an output parameter, but it's signature isn't a pointer, so it can't be a pointer.

Without the "real" signature (what do the parameters represent and how are they used) it's hard to provide a useful declaration. For example, if outD specifies how many DWORD values outE can hold, then you have a completely different ballgame than if outE is just a pointer to a single DWORD...

Share this post


Link to post
Share on other sites
Hi Dave,

1.What do you mean by "Real signature" ?
isn't it the real signature ?

BOOL Foo(
PVOID inA,
DWORD inB,
PVOID outC,
DWORD outD,
PDWORD outE
);

BTW: I'm trying to invoke the function LmPrinterIoControl
fro here :
http://www.swecoin.se/CustomFiles/TTP%20Language%20Monitor%20Implementation.pdf


2. What's the difference between "out" and "ref" ?

Thanks again !

Share this post


Link to post
Share on other sites
By "real signature" I meant "what do the parameters represent." With the document you provided, I now have what I need.

You'll need to do something like this:

// declaration
public static extern int LmPrinterIoControl([In] byte[] inBuffer,Int32 inBufferSize,[In,Out] byte[] outBuffer,Int32 outBufferSize,ref Int32 bytesReturned);

// usage

byte[] inBuffer = new byte[inBufferSize];
// don't know where data in inBuffer comes from, assume it's filled at this point.

byte[] outBuffer = new byte[outBufferSize];

LmPrinterIoControl(inBuffer,inBufferSize,outBuffer,outBufferSize,ref bytesReturned);





I don't have any way of verifying this, but it looks ok.

edit:
To answer question #2, "out" says I'm not going to initialize this variable, so don't read it, just set it. "ref" says the variable can be both read and written.

Note that this is different from In,Out in brackets, which has to do with how the PInvoke marshals the variables between the caller and the called.

Share this post


Link to post
Share on other sites
Thanks Dave, I will check it out !

btw: This function needs to send block of data to the printer,
and get a block of data (the answer).

For example, the block that been sent may ask for the printer status,
and the received block may contain and answer (out of paper, hot printer, etc.)

I read the pdf file, but I couldn't figure out the protocol,
which bytes array I need to send, in order get the answer ?

can you understand it from the document ?

Thanks !!

Share this post


Link to post
Share on other sites
It looks to me like you need to set the inBuffer to the sequence of bytes shown in the TTPKEY structure. For example, to get the "General Status", you would set inBuffer to the sequence of bytes corresponding to


"\x1b\x05\x01", 3, 2, REG_BINARY, TEXT("Status General")


I don't know how the TTPKEY structure is defined, so I have no idea how long each field is. If you've got a header file for the API, you should be able to figure that out. You could write a C program that outputs the sequence of bytes for each command. That way you could see exactly what bytes you need for a particular command.

The return buffer (outBuffer) will contain a series of bytes corresponding to the values shown in the table under "Remarks". Again, I don't know exactly how those will appear, so you might write a C program to check that out as well.

Share this post


Link to post
Share on other sites
Hi,

I don't have the header file, and I don't know C,
So I guess I will have to try handle only with the DLL and documentation.

You wrote about the "Status General", white belongs to the "getPrinterData" function, but the only function I can use is "LmPrinterIoControl" function,
And I can't understand from this function table which data I need to send,
In order to get relevant data...

It's just me, or you also can't understand from the "LmPrinterIoControl" documentation which data to send ? :-)


btw: If it can help, I uploaded the DLL file to :
http://www.yousendit.com/transfer.php?action=download&ufid=A77115DA124F063F

Thanks again !

Share this post


Link to post
Share on other sites
According to the document, getPrinterData is just a wrapper around LmPrinterIoControl that sends the appropriate bytes from the table. So, calling getPrinterData with a TTPCommand of TTPKEY_STATUS_GENERL would send the bytes in the table that I showed in my previous post.

There is a download available on their site that contains sample C++ source code. In that download are the TTP.H and TTP.CPP files that define all of the TTPKEY stuff. The TTPKEY structure is defined as:

typedef struct _TTPKEY {
BYTE cmd[4];
DWORD inLen;
DWORD outLen;
DWORD type;
TCHAR name[256];
} TTPKEY, *PTTPKEY;


So, to send the command to get the general status you would need to send the bytes I showed as they are defined above.

cmd inLen outLen type (REG_BINARY)
0x1b,0x05,0x01,0x00, 0x03,0x00,0x00,0x00, 0x02,0x00,0x00,0x00, 0x08,0x00,0x00,0x00,
name
'S','a','t','u','s',' ','G','e','n','e','r','a','l' (followed by enough zeros to make this field 256 bytes long)




That's about all the help I can offer.

Share this post


Link to post
Share on other sites
Thanks Dave,

But the documentation says about the "GetPrinterData" function :
"This function should currently only be used with parallel printer."

For this reason (and some more),
I need to work directly with the "LmPrinterIoControl" function.

The problem is not the code, but the table understanding :-)
Can you figure out from the "LmPrinterIoControl" table (parameters and values),
what should I send inside the bytes array, in order to get the information ?

Share this post


Link to post
Share on other sites
As near as I can tell, the bytes I gave in my previous post are what you would send to LmPrinterIoControl as the inBuffer parameter. Whether this works with anything other than a parallel printer is unclear from the documentation. But I get the impression that the command bytes are the same.

Share this post


Link to post
Share on other sites
I just read through the sample code and I think I've got it now.

You only need to send the bytes from the cmd field. So, to send the general status request, you would send the following bytes in inBuffer:

0x1b,0x05,0x01

and specify 3 for the inBufferLen parameter.

Then you will get back a sequence of bytes in the outBuffer representing the status. The PDF document didn't display correctly for me, so I couldn't figure out how to interpret the return bytes.

At any rate, that should get you going.

Share this post


Link to post
Share on other sites
Thanks Dave !

Just a little remark :
when you said "from the cmd field", what excatly did you mean ?
Is there a cmd field/column in the table ?

Maybe you refer to this line (in your example) ? :
{ "\x1b\x05\x01", 3, 2, REG_BINARY, TEXT("Status General")},

But this example is not of the "LmPrinterIoControl" function..
DO you think is doesn't matter, and I should send thie sequence of bytes while using the "LmPrinterIoControl" function ?

Thanks.

Share this post


Link to post
Share on other sites
From the sample app in the download I mentioned, the table shows what will be sent to LmPrinterIoControl by GetPrinterData based on the command id.

The cmd field is the first field in the TTPKEY command structure. Those are the bytes that need to be sent to LmPrinterIoControl in the inBuffer field.

inLen is the second field in the TTPKEY command structure. That field is the value that needs to be sent to LmPrinterIoControl in the inBufferLen field (it specifies how many bytes are in the inBuffer field).

The third field in the TTPKEY command structure is outLen. It specifies how many bytes will be returned for that command in the outBuffer field. So you would pass that to LmPrinterIoControl in the outBufferLen field and make sure that your outBuffer was at least that big.

The fourth and fifth fields in the TTPKEY command structure (type and name) are informational and give the type of the returned data (REG_BINARY) and a textual description of the command.

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this