I am trying to write a program that interfaces with a BlackBerry device plugged in via USB (utilizing the Desktop Manager API). The only exampes I can find for doing this are in C++, but I only know how to write/interpret VB .NET (I'm a novice, really), so I decided the easiest way to do this would be to just pass a string to and from the device.

To accomplish this, I thought the easiest thing to do would be to adapt the sample C++ application that comes with the BlackBerry JDE (which demonstrates passing a string to an app on the device using the DM API) to a MFC DLL which I would then call from my VB .NET app.

The main problem I am having is figuring out how to accept or return a string between the DLL and the VB .NET app. Every time I try to pass a string it gives me an error. Research has lead me to understand that this is because of "incompatibility" between the string types of the C++ std::string and the VB .NET String variable types.

Here is my code:
C++

// InterfaceStack.cpp : Defines the initialization routines for the DLL.
//

#include "stdafx.h"
#include "InterfaceStack.h"
#include <string>
#include <cstring>

#ifdef _DEBUG
#define new DEBUG_NEW
#endif


// CInterfaceStackApp

BEGIN_MESSAGE_MAP(CInterfaceStackApp, CWinApp)
END_MESSAGE_MAP()


// CInterfaceStackApp construction

CInterfaceStackApp::CInterfaceStackApp()
{
	// TODO: add construction code here,
	// Place all significant initialization in InitInstance
}


// The one and only CInterfaceStackApp object

CInterfaceStackApp theApp;


// CInterfaceStackApp initialization

BOOL CInterfaceStackApp::InitInstance()
{
	CWinApp::InitInstance();

	return TRUE;
}


std::string SendStringToDevice(std::string _StringToSend)
{
	// Code which attempts to seng _StringToSend to the device
	std::string _SendAttemptStatus;

	_SendAttemptStatus = "0";
	return _SendAttemptStatus;
}

std::string ReceivedFromDevice()
{
	std::string _TextReceived;
	_TextReceived = "StringFromDevice";
	return _TextReceived;
}

And here is a sample VB .NET app that imports the MFC DLL functions (for some reason "Add Reference" wouldn't work, but this does if I make the C++ use int/integer instead of std::string/String), then tries to pass a string to the SendStringToDevice function.
VB .NET

Public Class form_Main

    Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
        Try
            Dim x As String
            ' Send a string
            x = SendStringToDevice("Hello world")
            MsgBox(x.ToString)

            ' The response
            x = ReceivedFromDevice()
            MsgBox(x.ToString)
        Catch ex As Exception
            MsgBox(ex.ToString)
        End Try
    End Sub

    <System.Runtime.InteropServices.DllImport("InterfaceStack.dll", SetLastError:=False)> _
    Public Shared Function SendStringToDevice(ByVal _StringToSend As String) As String

    End Function

    <System.Runtime.InteropServices.DllImport("InterfaceStack.dll", SetLastError:=False)> _
    Public Shared Function ReceivedFromDevice() As String

    End Function

End Class

I believe that I have the Java-based on-device app working fine (it listens for a string via USB) because I adapted the program from the JDE sample.

Dani AI

Generated

Short summary and a practical path forward for (and thanks to for pointing toward the Microsoft guidance): std::string will not marshal across P/Invoke as a System.String. The reliable approach is to expose simple C-style exports that use char*/wchar_t* (or return status codes) and let the CLR do the conversion, or use a small managed wrapper. Returning native-allocated memory needs explicit ownership rules. (learn.microsoft.com)

A few concrete, safe patterns to implement in your DLL and call from VB.NET:

  • Send a string (native takes a wide string, managed calls with CharSet=Unicode):
// native (C++)
extern "C" __declspec(dllexport) int __stdcall SendStringToDevice(const wchar_t* message);
' managed (VB.NET)
<DllImport("InterfaceStack.dll", CharSet:=CharSet.Unicode, CallingConvention:=CallingConvention.StdCall)>
Public Shared Function SendStringToDevice(ByVal message As String) As Integer
End Function
  • Receive into a caller buffer (use StringBuilder on the VB side, native fills the buffer):
// native
extern "C" __declspec(dllexport) int __stdcall GetStringFromDevice(wchar_t* outBuf, int bufChars);
' VB.NET: pass a StringBuilder with capacity and read its ToString()

Set the DllImport CharSet to match the native representation so the runtime marshals correctly. (learn.microsoft.com)

Notes on returning strings from native code: do NOT return a pointer to a local (stack) buffer. If you return an allocated pointer, allocate with CoTaskMemAlloc (or return a BSTR if you declare/unmarshall as BStr) so the runtime or your caller can free it predictably. A safer pattern is to return an IntPtr, call Marshal.PtrToStringUni/PtrToStringAnsi in VB, then free with Marshal.FreeCoTaskMem when done. This avoids mismatched free routines and crashes. (learn.microsoft.com)

If you prefer less P/Invoke hassle when you have a lot of C++ code (std::string, classes), write a thin C++/CLI mixed-mode wrapper that converts between std::string and System::String^ (msclr::interop::marshal_as) and exposes a managed assembly your VB.NET app can reference directly. Also always export with extern "C" for simple names, match calling conventions, and ensure DLL bitness matches the process. (learn.microsoft.com)

Recommended Answers

All 2 Replies

Read about how to pass strings between VB and c++

Read about how to pass strings between VB and c++

Thanks! Problem solved. :D

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.