Solved

Unmanged API's

Posted on 2004-08-05
7
441 Views
Last Modified: 2008-01-09
I been having issues with a 3rd party unmanaged DLL which I use to access a database via an api. I am trying to pass in a string value which the documentation states as a pointer (char*). I have next to no C++ experience so it could be a real obvious one !

the C++ api declaration reads as follows

// Assume TM1V is an int
TM1IMPORT TM1V TM1API TM1SystemServerHandle( TM1U hUser, CHAR * szName );

and is called in the demo client C++ app like so

LPSTR sServerName="testA";
TM1U hUser="1";

TM1SystemServerHandle( hUser, sServerName );

I found that using a C# string value for the second paramter was causing issues so I changed the API call to Marshal the value as LPSTR as follows

[DllImport("tm1api.dll")]  private static extern  int TM1SystemServerHandle  (int hUser ,[MarshalAs(UnmanagedType.LPStr)] string ipntName );

and called like follows

//assume huser is a valid handle
string mySting="testA"
StringBuilder sb=new StringBuilder(myString,255);
int ihTest = TM1SystemServerHandle(hUser, sb.ToString());

this produces the same issues (occasional null return) as when I passed the string in as of type string. I have also changing the api to accept a Stringbuilder and also IntPnt generated from Marshal.StringToHGlobalAnsi.

I sed to have similar issues when returning strings from the api but after some help I found that by returning an IntPnt and using Marshal.PtrToStringAnsi and it all worked fine.

Not sure what else to try. Is there any other was to handle pointers ?

thanks in advances

Graham
0
Comment
Question by:GillyTheTaffy
  • 4
  • 3
7 Comments
 
LVL 37

Expert Comment

by:gregoryyoung
ID: 11731504
sorry I missed this in your other question...

from  the previous link I gave you http://msdn.microsoft.com/library/default.asp?url=/library/en-us/cpguide/html/cpcondefaultmarshalingforstrings.asp

In some circumstances, a fixed-length character buffer must be passed into unmanaged code to be manipulated. Simply passing a string does not work in this case because the callee cannot modify the contents of the passed buffer. Even if the string is passed by reference, there is no way to initialize the buffer to a given size.

The solution is to pass a StringBuilder buffer as the argument instead of a string. A StringBuilder can be dereferenced and modified by the callee, provided it does not exceed the capacity of the StringBuilder. It can also be initialized to a fixed length. For example, if you initialize a StringBuilder buffer to a capacity of N, the marshaler provides a buffer of size (N+1) characters. The +1 accounts for the fact that the unmanaged string has a null terminator while StringBuilder does not.

For example, the Microsoft Win32 API GetWindowText function (defined in Windows.h) is a fixed-length character buffer that must be passed into unmanaged code to be manipulated. LpString points to a caller-allocated buffer of size nMaxCount. The caller is expected to allocate the buffer and set the nMaxCount argument to the size of the allocated buffer. The following code shows the GetWindowText function declaration as defined in Windows.h.

int GetWindowText(
HWND hWnd,        // Handle to window or control.
LPTStr lpString,  // Text buffer.
int nMaxCount     // Maximum number of characters to copy.
);
A StringBuilder can be dereferenced and modified by the callee, provided it does not exceed the capacity of the StringBuilder. The following code example demonstrates how StringBuilder can be initialized to a fixed length.

[Visual Basic]
Public Class Win32API
Public Declare Auto Sub GetWindowText Lib "User32.Dll" _
(h As Integer, s As StringBuilder, nMaxCount As Integer)
End Class
Public Class Window
   Friend h As Integer ' Friend handle to Window.
   Public Function GetText() As String
      Dim sb As New StringBuilder(256)
      Win32API.GetWindowText(h, sb, sb.Capacity + 1)
   Return sb.ToString()
   End Function
End Class
[C#]
public class Win32API {
[DllImport("User32.Dll")]
public static extern void GetWindowText(int h, StringBuilder s,
int nMaxCount);
}
public class Window {
   internal int h;        // Internal handle to Window.
   public String GetText() {
      StringBuilder sb = new StringBuilder(256);
      Win32API.GetWindowText(h, sb, sb.Capacity + 1);
   return sb.ToString();
   }
}

notice the different ... you are still passing a string here, not the stringbuilder ... you are passing sb.ToString() instead of just sb.

Cheers,

Greg
0
 
LVL 1

Author Comment

by:GillyTheTaffy
ID: 11731765
thanks again Greg, I tried passing the Stringbuilder, Stringbuilder.ToString() and string (also String) but all still produce the same problem.

The api call in question doesn't ask for a length or populate the Stringbuilder - it just returns a handle if successful or 0 if it ain't

see below
[DllImport("tm1api.dll")]  private static extern  int TM1SystemServerHandle  (int hUser ,StringBuilder sbName );
            
StringBuilder sb=new StringBuilder(sCatalog,256);
ihCatalog = TM1SystemServerHandle(hUser, sb);

I've tried the above with and without the MarshalAs..... paramters and still no joy. Pulling what little hair I have left out here as I've spent nearly a whole day on this on thing!

Could this possilby be an issue with the provider or is it definately just a .net issue.

thanks again (and again)

Graham
0
 
LVL 37

Expert Comment

by:gregoryyoung
ID: 11731771
is it modifying the string ?
0
Active Directory Webinar

We all know we need to protect and secure our privileges, but where to start? Join Experts Exchange and ManageEngine on Tuesday, April 11, 2017 10:00 AM PDT to learn how to track and secure privileged users in Active Directory.

 
LVL 1

Author Comment

by:GillyTheTaffy
ID: 11731805
nope (nor should it)
0
 
LVL 37

Accepted Solution

by:
gregoryyoung earned 125 total points
ID: 11731820
it should be of this form class StringLibAPI {
[DllImport("StringLib.Dll")]
public static extern void PassLPStr([MarshalAs(UnmanagedType.LPStr)]
String s);


my guess is that another error is occurring occasionally ...

0
 
LVL 1

Author Comment

by:GillyTheTaffy
ID: 11731849
yeah thats what I tried last night and was pretty confident it would work. However it still produces the same problem.

I'll contact the vendors and see if they have any .net doco rather than C++

thanks for all your help
0
 
LVL 37

Expert Comment

by:gregoryyoung
ID: 11731915
eh I think it may be some sort of error in their .dll if the problem is inconsitant, I might ask them "can this method return null and why ?"
0

Featured Post

Free Tool: Site Down Detector

Helpful to verify reports of your own downtime, or to double check a downed website you are trying to access.

One of a set of tools we are providing to everyone as a way of saying thank you for being a part of the community.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Article by: Ivo
C# And Nullable Types Since 2.0 C# has Nullable(T) Generic Structure. The idea behind is to allow value type objects to have null values just like reference types have. This concerns scenarios where not all data sources have values (like a databa…
This article introduced a TextBox that supports transparent background.   Introduction TextBox is the most widely used control component in GUI design. Most GUI controls do not support transparent background and more or less do not have the…
With Secure Portal Encryption, the recipient is sent a link to their email address directing them to the email laundry delivery page. From there, the recipient will be required to enter a user name and password to enter the page. Once the recipient …
A short tutorial showing how to set up an email signature in Outlook on the Web (previously known as OWA). For free email signatures designs, visit https://www.mail-signatures.com/articles/signature-templates/?sts=6651 If you want to manage em…

828 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question