?
Solved

Converting a long into a String in VB

Posted on 2008-06-20
20
Medium Priority
?
992 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
[X]
Welcome to Experts Exchange

Add your voice to the tech community where 5M+ people just like you are talking about what matters.

  • Help others & share knowledge
  • Earn cash & points
  • Learn & ask questions
  • 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
Industry Leaders: We Want Your Opinion!

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

 
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
 
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

Free Tool: IP Lookup

Get more info about an IP address or domain name, such as organization, abuse contacts and geolocation.

One of a set of tools we are providing to everyone as a way of saying thank you for being a part of the community.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

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 …
I was working on a PowerPoint add-in the other day and a client asked me "can you implement a feature which processes a chart when it's pasted into a slide from another deck?". It got me wondering how to hook into built-in ribbon events in Office.
Show developers how to use a criteria form to limit the data that appears on an Access report. It is a common requirement that users can specify the criteria for a report at runtime. The easiest way to accomplish this is using a criteria form that a…
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…
Suggested Courses
Course of the Month12 days, 3 hours left to enroll

752 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