0

I'm calling calling a C/C++ function from a dll within my C# application. I can't for the life of me figure out how to properly Marshall the data.

Here's the information on the API function I am trying to call:

LONG LoginDialog(HWND hWndParent, LPCWSTR lpctstrTitle, ULONG ulFlags, LPWSTR lptstrDataSource, LONG lDSLength, LPCWSTR lpctstrUsername, LPCWSTR lpctstrPassword, LPCWSTR lpctstrSchema);

Parameters:
[in] hWndParent Specifies parent window handle for the Login dialog to display.
[in] lpctstrTitle Pointer to the null-terminated string specifying title for the Login dialog to display. Specify NULL pointer to use the default Login dialog title.
[in] ulFlags Specifies login operation and dialog style mask. It can be 0 or a bit-wise OR combination of flags listed in Login Dialog Style Flags.
[in,out] lptstrDataSource Pointer to the null-terminated string buffer specifying name of the datasource to log into. On output this buffer receives name of the datasource the user was logged into (in case datasource name was changed within the Login dialog).
[in] lDSLength Specifies length of the string buffer specified by lptstrDataSource.
[in] lpctstrUsername Pointer to the null-terminated string specifying user name.
[in] lpctstrPassword Pointer to the null-terminated string specifying password.
[in] lpctstrSchema Pointer to the null-terminated string specifying full path of the schema file. Specify NULL pointer if schema is not needed.

Here's my code:

[DllImport("dmawin.dll", CharSet = CharSet.Unicode)] 
private static extern int LoginDialog(IntPtr pWndParent, string pStrTitle, 
uint pFlags, [MarshalAs(UnmanagedType.LPWStr)] ref StringBuilder pStrDataSource, 
int pDSLength, string pStrUsername, string pStrPassword, string pStrSchema);


private bool Login(string pDataSource, string pLoginName, 
string pPassword, string pScheme)
{
    private const int MAX_DB_NAME = 256;
    IntPtr handle = ParentForm.Handle;
    var sb = new StringBuilder(pDataSource, MAX_DB_NAME);

    //function call
    LoginDialog(handle, null, flags, ref sb, MAX_DB_NAME, pLoginName, 
    pPassword, pScheme);
}

I'm pretty sure that I am marshaling the 4th parameter wrong (LPWSTR lptstrDataSource). I've tried different answers I've found online but none have worked so far for me.

I'm also getting this warning first. Sorry for not clarifying:

Managed Debugging Assistant 'LoadFromContext' has detected a problem ..

Additional information: The assembly was loaded from 'the dll location' using the LoadFrom context. The use of this context can result in unexpected behavior for serialization, casting and dependency resolution. In almost all cases, it is recommended that the LoadFrom context be avoided. This can be done by installing assemblies in the Global Assembly Cache or in the ApplicationBase directory and using Assembly.Load when explicitly loading assemblies.

user2481095
  • 2,024
  • 7
  • 22
  • 32
  • 1
    Try to pass a StringBuilder initialized to some size (the size specified on the documentation when you use it as out). Take a look at this: https://msdn.microsoft.com/en-us/library/s9ts558h%28v=vs.110%29.aspx – Gusman May 03 '16 at 20:01
  • I tried what you suggested but it's still not working for me. I edited the question to reflect the changes I made. – user2481095 May 03 '16 at 21:36
  • But what is the exact problem you have? any exception? some parameters null? other? – Gusman May 03 '16 at 21:40
  • I edited the question to include the warning I am getting. I created a separate question about this warning and it sounds like it's nothing of concern. However, when I continue, the login dialog pops up with the loginName correctly filled in but the data source field is filled in with gibberish. That's why I think I am incorrectly marshaling the datasource string. Ideally if I made the call correctly, I should automatically be logged in. – user2481095 May 03 '16 at 23:22
  • 1
    Well, good reason to not completely hate Hungarian. You are passing LPWSTR*, not LPWSTR. Remove the *ref* keyword from the StringBuilder argument. And since it uses W strings, you must use CharSet = CharSet.Unicode so all passed strings are Wide. Do *not* ignore the return value, it ought to give you some kind of "failed" error code. – Hans Passant May 03 '16 at 23:42
  • Thank you so much. I realized right before you posted the answer as well. It's working now. – user2481095 May 03 '16 at 23:44

0 Answers0