views:

258

answers:

4

I'm using a DLL with the following function in C# Visual Studio 2008:

[DllImport("slpapi62", EntryPoint = "_SlpGetPrinterName@12")]
public static extern int SlpGetPrinterName(int nIndex, string strPrinterName, int nMaxChars);

Calling this function, strPrinterName is suppose to return a string.

string name = "";
SlpGetPrinterName(0, name, 128);

How can i get this parameter to pass by reference?

A: 

Can you use the ref keyword?

string name = "";
SlpGetPrinterName(0, ref name, 128);

There is a detail explanation of passing variables by reference here http://www.yoda.arachsys.com/csharp/parameters.html

Roberto Sebestyen
doesn't seem to work with the ref keyword
Justin Tanner
+1  A: 

Use a StringBuilder object for the string parameter.

Timbo
A: 

It sounds like you need the name value to be set by the external code. It has been some time since I have done any pInvoke, but I believe the following is the correct signature:

[DllImport("slpapi62", EntryPoint = "_SlpGetPrinterName@12")]
public static extern int SlpGetPrinterName(int nIndex, out string strPrinterName, int nMaxChars);

Note the 'out' keyword before 'string strPrinterName'. You would then call it like so:

string name;
SlpGetPrinterName(0, out name, 128);
jrista
+2  A: 

Pass a StringBuilder object instead of a string:

[DllImport("slpapi62", EntryPoint = "_SlpGetPrinterName@12")]
public static extern int SlpGetPrinterName(int nIndex, StringBuilder strPrinterName, int nMaxChars);

Calling it:

StringBuilder name = new StringBuilder(128);
int value = SlpGetPrinterName(0, name, name.Capacity);
280Z28
That worked! Can anybody tell me why I needed to use the StringBuilder class vs a regular string?
Justin Tanner
Actually, a string is a reference type, but it is immutable. Therefore, when the marshaler calls unmanaged code with a `string`, it makes a copy of its buffer so the original remains unchanged. Techncially, it would have to do this anyway because 1) the string is not pinned (the GC can move its data) and 2) it has to convert it to ANSI or whatever is requested. Basically, it means that even if the method you call alters the buffer, the changes are simply discarded. StringBuilder's buffer is mutable, which means if the function alters its buffer, it's copied back to the StringBuilder's buffer.
280Z28
Its case of Value vs Reference types. Although string is technically a Reference type it behaves like a value type: http://stackoverflow.com/questions/636932/in-c-why-is-string-a-reference-type-that-behaves-like-a-value-type
Roberto Sebestyen
@Roberto: It doesn't behave like a value type. It behaves like an immutable reference type. Other commonly used examples are the `Regex` class and empty arrays (length 0), like `Type.EmptyTypes`. It's passed between managed methods by reference without making a copy, which is fundamentally different from value types.
280Z28