Solved

Unmanged API's

Posted on 2004-08-05
7
434 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
IT, Stop Being Called Into Every Meeting

Highfive is so simple that setting up every meeting room takes just minutes and every employee will be able to start or join a call from any room with ease. Never be called into a meeting just to get it started again. This is how video conferencing should work!

 
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

What Is Threat Intelligence?

Threat intelligence is often discussed, but rarely understood. Starting with a precise definition, along with clear business goals, is essential.

Join & Write a Comment

This article describes a simple method to resize a control at runtime.  It includes ready-to-use source code and a complete sample demonstration application.  We'll also talk about C# Extension Methods. Introduction In one of my applications…
We all know that functional code is the leg that any good program stands on when it comes right down to it, however, if your program lacks a good user interface your product may not have the appeal needed to keep your customers happy. This issue can…
Internet Business Fax to Email Made Easy - With eFax Corporate (http://www.enterprise.efax.com), you'll receive a dedicated online fax number, which is used the same way as a typical analog fax number. You'll receive secure faxes in your email, fr…
This demo shows you how to set up the containerized NetScaler CPX with NetScaler Management and Analytics System in a non-routable Mesos/Marathon environment for use with Micro-Services applications.

746 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

Need Help in Real-Time?

Connect with top rated Experts

16 Experts available now in Live!

Get 1:1 Help Now