DOCUMENT:Q187912 22-JUN-1998 [vbwin] TITLE :HOWTO: Pass a String Between Visual Basic and Your C DLL PRODUCT :Microsoft Visual Basic for Windows PROD/VER:WINDOWS:5.0; WINNT:5.0 OPER/SYS:WINDOWS winnt KEYWORDS: ====================================================================== --------------------------------------------------------------------- The information in this article applies to: - Microsoft Visual Basic Learning, Professional, and Enterprise Editions for Windows, version 5.0 - Microsoft Visual C++, 32-bit Editions, version 5.0 --------------------------------------------------------------------- SUMMARY ======= When creating a C dynamic-link library (DLL) for use with Visual Basic, it is important to remember that C and Visual Basic treat strings differently. You must take every precaution to ensure that all strings are passed correctly; otherwise, a fatal error may occur. This article will show you how to write a C DLL that takes a string as a parameter to a function, and how to call the exported function from a Visual Basic application. MORE INFORMATION ================ In order to develop your C DLL, it is important to know how Visual Basic handles strings internally in order to know how they will be passed to your DLL functions. Most C functions expect a string to be a null-terminated, ASCII character array. But Visual Basic uses a type-safe Automation string called a BSTR. For the Win32 platform, a BSTR is a long pointer to an allocated memory structure containing a Unicode character string and a 32- bit integer prefix that stores the length of the string. You can ignored most of this difference, because Visual Basic will automatically convert any Unicode BSTRs to ASCII before passing them to an external function. The problem, however, is with the parameter itself. By default, Visual Basic passes all variables by reference, including strings. Because a BSTR variable is a pointer to a string, when Visual Basic passes it by reference it is actually passing a pointer to a pointer to a string. Most C functions simply expect a pointer to a string (such as LPSTR). Create Your C DLL: Step-by-Step Example --------------------------------------- 1. Open Visual C++ 5.0 and click New on the File menu. On the Projects tab, select "Win32 Dynamic-Link Library" and name the project "StrSamp." 2. Once again, click New on the File menu, and select "C++ Source File." On the Files tab, name the file "StrSamp.c," and press OK. 3. Repeat step 2 and this time choose "Text File" as the file type. Name the file "StrSamp.def," and press OK. 4. Next, add the following code to "StrSamp.c": #include void __stdcall DisplayStringByVal(LPCSTR pszString) { //pszString is a pointer to a string MessageBox(NULL, pszString, "Display String ByVal", MB_OK | MB_ICONINFORMATION); } void __stdcall DisplayStringByRef(LPCSTR* ppszString) { //ppszSting is a pointer to a pointer to a string MessageBox(NULL, *ppszString, "Display String ByRef", MB_OK | MB_ICONINFORMATION); } void __stdcall FillString(LPSTR pszString) { // Create a temp buffer with our string char buffer[] = "Hello from the C DLL!"; // Copy our temp string to pszString strcpy(pszString, buffer); } int __stdcall InStrRev(LPCSTR pszString, short iChar) { // This function is similar to Visual Basic's InStr function // except that it searches for the given ASCII character from // right to left, returning the character position of the // last occurrence (rather than the first) of the character // in the string. char* pszTmp; int nRet = 0; // Scan for iChar in pszString backwards pszTmp = strrchr(pszString, (int)iChar); if(pszTmp != NULL) nRet = pszTmp - pszString + 1; return nRet; } 5. To make the functions exportable, add the following to "StrSamp.def": LIBRARY StrSamp DESCRIPTION 'Microsoft KB Sample DLL' EXPORTS DisplayStringByVal DisplayStringByRef FillString InStrRev 6. Compile your DLL from the Build menu. When complete, copy the new DLL to your Visual Basic directory for testing. The VB Test Application: Step-by-Step Example --------------------------------------------- 1. Create a Standard Project in Visual Basic and name it "StrTest."Form1 is created by default. 2. Add three CommandButtons to Form1. 3. In the code window for Form1, add the following to the General Declarations section: Option Explicit Private Declare Sub DisplayStringByRef Lib "StrSamp.dll" _ (sMyString As String) Private Declare Sub DisplayStringByVal Lib "StrSamp.dll" _ (ByVal sMyString As String) Private Declare Sub FillString Lib "StrSamp.dll" _ (ByVal sMyString As String) Private Declare Function InStrRev Lib "StrSamp.dll" _ (ByVal sMyString As String, ByVal iChar As Integer) _ As Long Note that most of the strings are declared ByVal. This does not mean that you are passing these strings by value; rather, you are passing the value of the BSTR variable by value (remember that a BSTR variable is a pointer to a string). So the ByVal keyword has the effect of passing a long pointer to a string (LPSTR), just what the C functions expect. 4. Add the following code to the click events for each of the CommandButtons: Private Sub Command1_Click() Dim sTestString1 As String Dim sTestString2 As String sTestString1 = "This is my string passed to the dll by value." DisplayStringByVal sTestString1 sTestString2 = "This is my string passed to the dll by reference." DisplayStringByRef sTestString2 End Sub Private Sub Command2_Click() Dim sFillTest As String sFillTest = Space$(260) FillString sFillTest MsgBox Trim$(sFillTest), vbInformation, "Fill String" End Sub Private Sub Command3_Click() Dim sPathString As String Dim sMsg As String Dim lCharPosition As Long sPathString = "C:\My Documents\Temp\Item.txt" lCharPosition = InStrRev(sPathString, Asc("\")) If CBool(lCharPosition) Then sMsg = "The file '" & Mid$(sPathString, lCharPosition + 1) sMsg = sMsg & "' is at this location:" & vbCrLf & vbCrLf sMsg = sMsg & Left$(sPathString, lCharPosition - 1) MsgBox sMsg, vbInformation, "InStrRev" Else MsgBox "Cannot find '/' in " & sPathString, vbCritical End If End Sub 5. Press the F5 key to run the Visual Basic project in the IDE. NOTE: If you receive an error message, it may be because Visual Basic cannot find your DLL. Make sure you have copied it to the Visual Basic directory before you run your test application. REFERENCES ========== For detailed information on how to create a C DLL and use it in Visual Basic, please see the following article: "DLLs for Beginners" in the Microsoft Developer Network (MSDN) Library "VB5DLL.DOC" located on the Visual Basic 5.0 CD-ROM in the "Tools\Docs" directory. For additional information, please see the following article in the Microsoft Knowledge Base: ARTICLE-ID: Q142840 TITLE : Visual Basic Requirements for Exported DLL Functions (c) Microsoft Corporation 1998, All Rights Reserved. Contributions by Richard R. Taylor, Microsoft Corporation Additional query words: kbDSupport kbDSD kbDLL kbAPI kbVBp500 kbVBp ====================================================================== Version : WINDOWS:5.0; WINNT:5.0 Platform : WINDOWS winnt Issue type : kbhowto ============================================================================= THE INFORMATION PROVIDED IN THE MICROSOFT KNOWLEDGE BASE IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND. MICROSOFT DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR IMPLIED, INCLUDING THE WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL MICROSOFT CORPORATION OR ITS SUPPLIERS BE LIABLE FOR ANY DAMAGES WHATSOEVER INCLUDING DIRECT, INDIRECT, INCIDENTAL, CONSEQUENTIAL, LOSS OF BUSINESS PROFITS OR SPECIAL DAMAGES, EVEN IF MICROSOFT CORPORATION OR ITS SUPPLIERS HAVE BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. SOME STATES DO NOT ALLOW THE EXCLUSION OR LIMITATION OF LIABILITY FOR CONSEQUENTIAL OR INCIDENTAL DAMAGES SO THE FOREGOING LIMITATION MAY NOT APPLY. Copyright Microsoft Corporation 1998.