Solved

Converting a long into a String in VB

Posted on 2008-06-20
20
980 Views
Last Modified: 2008-07-02
Hi guys,

I'm writing a windows DLL in VB6 using vbAdvance. This DLL is then having it's functions called by an external program.

I've noticed that the arguments for strings are coming through as longs.

For example:

An argument called sDefaultText, which must be textual, is coming through as 1936287828.

Is there a way to convert it to a VB string?
0
Comment
Question by:Bobeo
  • 7
  • 5
  • 5
  • +1
20 Comments
 
LVL 4

Expert Comment

by:512Thz
ID: 21833483
You probably mean the argument address which is passed as a VB long (32 bits address)

What happens? You expect a string to get modified by you call but the variable is unchanged???

Please give more details, since you r questionis somewhat vague.
0
 
LVL 25

Expert Comment

by:SStory
ID: 21833513
Visit:
http://vb.mvps.org/hardcore/

Open "Chapter 2", "Dealing with Strings"

See the section on "Getting Strings from the Windows API"

This should explain it to you.  Most APis are C style... they pass a pointer to the first Char... vb sees that as a long.  Vb stores strings differently.  Read this section to understand...actually the whole chapter is worth reading.
0
 
LVL 25

Expert Comment

by:SStory
ID: 21833520
Also with many APIs' you must declare a string and create it with enough space reserved already.
Many just make a string with X number of spaces in it already and pass that.
0
 
LVL 3

Author Comment

by:Bobeo
ID: 21833674
Cheers SStory. I think I understand a little better the differences now, but am still stumped as to how to convert from one to another. Basically, I have the following pseudo code that I need to build a VB function from:

int CM_MSGS_ExecsExpiryWarning( IN MSGSBLOCK *Msgs, IN char *DefaultText, int NumExecsLeft ){
MessageBox( NULL, "Your program will stop working after a few more executions", "", MB_OK )
}

And my VB code in my DLL currently looks like this:

Sub CM_MSGS_ExecsExpiryWarning(MSGS As MsgsBlock, sDefaultText As Long, lNumExecsLeft As Long)
MsgBox CStr(sDefaultText)
End Sub

The message box is showing the number I mentioned before, 1936287828. I stumped as to how to convert it to a VB string.
0
 
LVL 4

Expert Comment

by:512Thz
ID: 21834009
Did you try to just define sDefaultText as String in the VB function signature ?
0
 
LVL 4

Expert Comment

by:512Thz
ID: 21834148
The following should do the conversion.
' put this in the common area

 Declare Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" (pDest As Any, pSource As Any, ByVal ByteLen As Long)
 

'

Sub CM_MSGS_ExecsExpiryWarning(MSGS As MsgsBlock, sDefaultText As Long, lNumExecsLeft As Long)

  Dim buffer(32000) As Byte ' put the maximum here

  Dim len   As Integer

  Dim index As Long

  Dim ptr   As Long

  Dim sText As String
 

  Ptr = sDefaultText 

  Index =

  Do

    CopyMemory buffer(Index), Ptr, 1

    Index = Index +1

    Ptr = Ptr + 1

    If buffer(Index) = 0 Then

       Exit Loop

    End If

  Loop
 

  ReDim Preserve buffer(Index)

  sText = StrConv(buffer, vbUnicode)

  MsgBox CStr(sText)
 

End Sub

Open in new window

0
 
LVL 29

Expert Comment

by:nffvrxqgrcfqvvc
ID: 21834252
' When passing the strings you must pass them byval and convert them.


' Try
Private declare sub lib "yourdll" ( MSGS as MsgBlock, Byval sDefaultText As String, Byval  lNumExecsLeft As Long)

Sub CM_MSGS_ExecsExpiryWarning(MSGS As MsgsBlock, Byval sDefaultText As String, Byval  lNumExecsLeft As Long)
MsgBox StrConv(sDefaultText, vbUnicode)
End Sub
0
 
LVL 25

Expert Comment

by:SStory
ID: 21834732
Both of the above are correct that you do need a declare when calling from vb.net into a DLL from something like C++ which appears to be what you are doing.

I think what egl1044 says should work except if lNumExecsLeft is supposed to be an int in C then it would be a short in VB.NET and not a long....this may or may not matter.
0
 
LVL 4

Expert Comment

by:512Thz
ID: 21835079
The C type "Char *" is a byte array not a String (which is in Unicode that is 2 bytes per character)
0
 
LVL 29

Expert Comment

by:nffvrxqgrcfqvvc
ID: 21835175
I think the OP is trying to re-create the function to use in his own DLL in vb6. I don't think he is trying to call the function already exported in a DLL from another language
0
Highfive Gives IT Their Time Back

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 3

Author Comment

by:Bobeo
ID: 21835576
It makes sense that char is a byte array. Based on that, how would I write the VB function to handle that? Can VB handle byte arrays as arguments?

egl1044 is correct that I'm writing my own DLL, which I'm then saving as a Windows DLL and a third party program is calling on.
0
 
LVL 4

Expert Comment

by:512Thz
ID: 21836034
Look at the code I just posted (I left blank the initilization on Index because I don't know if you have base 0 or Base 1)

Did you try it?

Note that is has to loop in order to find the NULL (char(0)) which denotes the end of a string in C

If you can provide the length to the VB function ( from C function strlen(DefaultText)  ) than the loop can be avoided (And the code be more elegant)
0
 
LVL 4

Expert Comment

by:512Thz
ID: 21836104
I forgot to answer your question. No you can not just specify the argument "ByVal sDefaulText as Byte()" because VB adds control fields to arrays (and Strings) therefore you need the "CopyMemory" API to bring the data to a valid array.
0
 
LVL 3

Author Comment

by:Bobeo
ID: 21836949
I did try your code 512, but when I try to compile it using vbAdvance it says "Array already dimensioned" on the ReDim Preserve line.

The plot does thicken a little though. I've found s C++ example of the sub I'm trying to create.

Does this help?
void _stdcall CM_MSGS_ExecsExpiryWarning( MSGSBLOCK *Msgs, char *DefaultText, int ExecsToGo ) 

	{

	char buffer[100];
 

	wsprintf( buffer, "This program will only run %d times more\n", ExecsToGo );

	MessageBox(NULL,buffer,"CopyMinder Message DLL",MB_OK);
 

	}

Open in new window

0
 
LVL 29

Expert Comment

by:nffvrxqgrcfqvvc
ID: 21837084
Private Declare sub CM_MSGS_ExecsExpiryWarning ( byval msgs as long, byval DefaultText as long, byval ExecsTogo as long)


Sub CallAPI(ByVal mSgs As Long, ByVal DefaultText As String, ByVal ExecsTogo As Long)
   
    Dim b()     As Byte
    b = StrConv(DefaultText, vbFromUnicode)
    Call CM_MSGS_ExecsExpiryWarning(VarPtr(mSgs), VarPtr(b(0)), 0)

End Sub
0
 
LVL 3

Author Comment

by:Bobeo
ID: 21837178
Thanks egl, but your code tells me how to call the function, not how to write the function. It's my third party program that will be calling the function, I need to write a function to tell it what to do when it calls it.

In other words, I basically need the code on my above post converting to VB6.
0
 
LVL 4

Expert Comment

by:512Thz
ID: 21837292
Then we can first calculate the required length, and then copy the data.
' put this in the common area

 Declare Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" (pDest As Any, pSource As Any, ByVal ByteLen As Long)

 

'

Sub CM_MSGS_ExecsExpiryWarning(MSGS As MsgsBlock, sDefaultText As Long, lNumExecsLeft As Long)

  Dim buffer() As Byte 

  Dim len   As Integer

  Dim index As Long

  Dim sText As String

 

  Index = 0

  Do

    If buffer(Index) = 0 Then

       Exit Loop

    End If

    Index = Index +1

  Loop

 

  ReDim buffer(Index)

  CopyMemory buffer(0), sDefaultText, Index

  sText = StrConv(buffer, vbUnicode)

  MsgBox CStr(sText)

 

End Sub

Open in new window

0
 
LVL 29

Expert Comment

by:nffvrxqgrcfqvvc
ID: 21838223
I think you should explain what it is your trying to do. Your trying to pass a string value to a long value which im not sure why it didn't crash. If you want to pass a string by using a long value then you need to pass it by its string pointer using StrPtr(). Otherwise you can just pass it as a String. In order to make any correlation to your function we need to know what it is your doing and how the clients is setup. The function below is the the simple conversion, now the question is what are you doing inside this function and what are you passing as values from the client. Then we could change the procedure around to relate to what it is your doing.

Public Sub CM_MSGS_ExecsExpiryWarning(msgs As MSGBLOCK, ByVal DefaultText As String, ByVal ExecsTogo As Long)


End Sub
0
 
LVL 29

Expert Comment

by:nffvrxqgrcfqvvc
ID: 21838329
' This should work as an example to pass a string pointer to your dll

Option Explicit

Public Type MSGBLOCK    'Sample
    StructLength    As Long
    Data            As Long
End Type

Private Declare Function lstrlenW Lib "kernel32" ( _
        ByVal lpString As Long) As Long

Private Declare Sub push Lib "kernel32" Alias "RtlMoveMemory" ( _
    Destination As Any, _
    ByVal Source As Long, _
    ByVal Length As Long)

Private Function Wrapper(ByVal lPtr As Long) As String
' should add some error checking but for example
    Dim lLen As Long
    Dim bytes() As Byte
    lLen = lstrlenW(lPtr)
    lLen = (lLen * 2)
    ReDim bytes(lLen) As Byte
    push bytes(0), lPtr, lLen
    Wrapper = bytes
End Function

Public Sub CM_MSGS_ExecsExpiryWarning(msgs As MSGBLOCK, ByVal DefaultText As Long, ByVal ExecsTogo As Long)
' note: probrably not wise to use msgbox's because it's not safe
 MsgBox (DefaultText)           'before
 MsgBox Wrapper(DefaultText)    'after
 MsgBox msgs.StructLength       ' passed
 
End Sub



' To call it in VB6

Option Explicit

Private Type MSGBLOCK    'Sample (8 bytes)
    StructLength    As Long
    Data            As Long
End Type

Private Declare Sub CM_MSGS_ExecsExpiryWarning Lib "e:\test.dll" (msgs As MSGBLOCK, ByVal DefaultText As Long, ByVal ExecsTogo As Long)

Dim msgs As MSGBLOCK

Private Sub Command1_Click()
   
    msgs.StructLength = Len(msgs)   '// sample
   
    Call CM_MSGS_ExecsExpiryWarning(msgs, StrPtr("hello world"), 1)
   
End Sub
0
 
LVL 3

Accepted Solution

by:
Bobeo earned 0 total points
ID: 21856403
Thanks for your help guys Unfortunately, with vbAdvance not supporting the ReDim function, and VB not really supporting the proper sending of Byte Arrays via arguments, I concluded that I'm just gonna learn C and create my DLL from there.

Thanks for your time
0

Featured Post

Threat Intelligence Starter Resources

Integrating threat intelligence can be challenging, and not all companies are ready. These resources can help you build awareness and prepare for defense.

Join & Write a Comment

The debugging module of the VB 6 IDE can be accessed by way of the Debug menu item. That menu item can normally be found in the IDE's main menu line as shown in this picture.   There is also a companion Debug Toolbar that looks like the followin…
Have you ever wanted to restrict the users input in a textbox to numbers, and while doing that make sure that they can't 'cheat' by pasting in non-numeric text? Of course you can do that with code you write yourself but it's tedious and error-prone …
Get people started with the process of using Access VBA to control Excel using automation, Microsoft Access can control other applications. An example is the ability to programmatically talk to Excel. Using automation, an Access application can laun…
This lesson covers basic error handling code in Microsoft Excel using VBA. This is the first lesson in a 3-part series that uses code to loop through an Excel spreadsheet in VBA and then fix errors, taking advantage of error handling code. This l…

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

12 Experts available now in Live!

Get 1:1 Help Now