Hi,
Below is a MACRO I created to add a string to a listbox a little bit as if it were manually typed in VB, and would like to be able to do it using a procedure instead of using a MACRO, anyone got an example of a procedure version of the below?


Here's the MACRO version:
LB_AddItem MACRO lbHandle, strItem
LOCAL txtItem

.data
txtItem db strItem, 0

.code
invoke SendMessage,lbHandle,LB_ADDSTRING,0,ADDR txtItem
ENDM

Here's how it's used:
LB_AddItem hLB1,"Text Item 1"


Note: The above MACRO can be changed easy to accept a pointer or a manually typed string...
Posted on 2003-03-05 00:27:19 by Knight Chat X
For passing strings from VB to asm, check out the links i have just posted in this thread.

As for the function to do it, it is almost the same as your macro. Something like this:



AddStringToListBox proc hListBox :HANDLE, pStr :DWORD

.IF pStr && hListBox
invoke SendMessage, hListBox, LB_ADDSTRING, 0, pStr
.ENDIF

ret
AddStringToListBox endp


The .IF statement just ensures that the handle and the string pointer are both non null. Check out the links i mentioned above to see how you get the pointer to the string. Then all you have to do is make the proc above public in your dll.
Posted on 2003-03-05 04:24:52 by sluggy
The problem with that is when that method is used, you must still pass the parameter off as a pointer to a string, which is the problem.

Example (Problem):
invoke AddStringToListBox,hLB,StringPointer ;String passed by pointer.

Instead of (Correct):
invoke AddStringToListBox,hLB,"String Text" ;Typed string (NOT Pointer).


If the answer to this question can be found, then a move could be made towards making it to where when possible, a person wouldn't have to worry about the pointers in cases where the text can be manually typed in, such as for a messagebox, exactly like in VB with less to think about, but right now any attempt in creating a function like that has resulted in compile error's, yet it all works fine when using a MACRO...
Posted on 2003-03-05 05:21:02 by Knight Chat X
Sorry if this sounds cynical, but the effect of your macro is to make the API call so high level that you might as well be doing it in VB. If new asm coders were made to take an oath before they start coding, that oath would incluse the phrase "i will love and cherish pointers, for they give me strength and power" ;)
Posted on 2003-03-05 05:56:02 by sluggy
Good thing I'm not a new coder, though I haven't been doing it for quiet a longtime and almost forgotten everything, I have a good reason for getting the answer to the question, "if I could teach 1 professor something that all professors could learn, it's that you never assume anything at all, especially someones intelligence", every programmer has their own style of programming, besides, I.

Most of what you have explained has nothing at all to do with the solution to the problem, the reason being is what you have explained is about asm DLL's and passing parameters in VB to functions and inbetween and properly using ByVal, ByRef back and forth etc..., and it has nothing to do with just High Level Language, as all of this is anyways, unless you're typing a bunch of 1's & 0's, native machine language, which I'm crazy enuff to do, as long as it's a language built on top, it's high, though assembler is the lowest readable/understandable language to work with.

If you really want to use API functions with asm in VB and pass parameters correctly, instead of using an asm DLL and worrying about all the formatting, just put the asm code directly inside a bas module, create a main window, uncheck all references to bypass the runtime files, and set the startup to Sub Main and use asm, you may need to turn off VB's syntax checking.

When I find the answer then I can add some extra code to handle checking of pointer vs. string, the end result being less lines of code to type, higher productivity, quicker coding, the ability to use either a string or pointer to a string, and not have to worry about anything because the rest will be handled by the function, simply put, weither you feel like manually typing string in or just wanna do it traditionally, atleast there's the choice.

;oP
Posted on 2003-03-05 07:08:14 by Knight Chat X
Good thing I'm not a new coder, though I haven't been doing it for quiet a longtime and almost forgotten everything, I have a good reason for getting the answer to the question, "if I could teach 1 professor something that all professors could learn, it's that you never assume anything at all, especially someones intelligence", every programmer has their own style of programming, besides, part of that macro is from MASM32, and I trust Steve Hutch's taste in code.

Most of what you have explained has nothing at all to do with the solution to the problem, the reason being is what you have explained is about asm DLL's and passing parameters in VB to functions and inbetween and properly using ByVal, ByRef back and forth etc..., and it has nothing to do with just High Level Language, as all of this is anyways, unless you're typing a bunch of 1's & 0's, native machine language, which I'm crazy enuff to do, as long as it's a language built on top, it's high, though assembler is the lowest readable/understandable language to work with.

If you really want to use API functions with asm in VB and pass parameters correctly, instead of using an asm DLL and worrying about all the formatting, just put the asm code directly inside a bas module, create a main window, uncheck all references to bypass the runtime files, and set the startup to Sub Main and use asm, you may need to turn off VB's syntax checking.

When I find the answer then I can add some extra code to handle checking of pointer vs. string, the end result being less lines of code to type, higher productivity, quicker coding, the ability to use either a string or pointer to a string, and not have to worry about anything because the rest will be handled by the function, simply put, weither you feel like manually typing string in or just wanna do it traditionally, atleast there's the choice.

;oP
Posted on 2003-03-05 07:11:41 by Knight Chat X
But that's what HLLs are for, to take care alot of the piddling little details for you. The reason you code in ASM is to give you a sort of line item veto over your code. An HLL is in essence a collection of ASM procedures, if you rewrite all of the procedures you have done nothing more than recreate that language. ALL STRINGS are passed as pointers in any language, the fact that the work of allocating the memory and getting and passing the pointer is done in the background is not always good. I would never use a macro like the one you demonstrated or a procedure that performed the function, why create a whole bunch of overhead (both in program size and speed) to execute a two line command ? But if you really want to do it you might try VARARG, but that would probably be more complicated than all the extra code you have to write in your lifetime.

Take this example, if you had a routine to do all the allocating and passing for you it would work by converting the string to an entry in the data section then passing the pointer. Problem is that each time you use it a new string has to be allocated even if that string already exists i.e.

LB_AddItem hLB1,"Test String" ; creates the first string
LB_AddItem hLB1,"Test String" ; creates a second string same as the first but using an extra 12 bytes
LB_AddItem hLB1,"Test String" ; creates a third string same as the first but we're up to 24 extra bytes

This can quickly add up in something like a database using a listbox to display data. You could end up with MBs of memory full of useless redundant data. While in the pointer/data method you just have to create the string once and pass the pointer. Most HLL's have garbage collection and such to get rid of these useless redundancies but none can decide what to do with that literal string so they leave it there, sitting in memory taking up space for nothing. ASM forces you to control this from the start and this leads to better programming practices. Thats why you hear alot of ASM programmers talk about memory size, they are more conscious of it than any other group because they deal with it at the lowest level every day.

Donkey
Posted on 2003-03-05 07:45:44 by donkey
I realised that a new string is created every time when it's in the .data section and saw that as a problem, that's why I'm looking for another way to do it.

When we invoke a function such as for a messagebox, depending on what that messagebox is to represent, the style, title, body etc.., we give it data to use, if that data doesn't change, using a pointer method would be best suited for that task, but if you expected each line of text to be totally different, and never the same, then there's no harm in using a method like that.

I might be wrong, but thought that when the variable was defined in a block of code as LOCAL like in the MACRO, the information was freed at the end during a return after it's used, kinda like when you close a program and the memory from the program that was currently in use was freed, or, like in visual basic where when you Dim a variable in a procedure, that variable is only in use during the execution of that procedure until it is finished, aka End Sub/End Function, am I wrong?
Posted on 2003-03-06 03:28:46 by Knight Chat X
No, the text will be included in your data section every time you call the macro. The example I gave you will add each instance of the text to your executable. Remember that a macro is expanded at compile time, therefore each time you use it the full macro is inserted in your code, including the text. You can use a hex editor to verify this.

You cannot define an initialized string in the LOCAL section of anything, how would the program know what data to put in it ? The data has to be stored somewhere. When HLL's do this they are creating an uninitialized string and copying the data from one that was stored in the executables .data section, even more overhead.

If you were to find a way to use a procedure to do it you would sacrifice speed, each time you call a procedure there is overhead to pay. Creating the stack frame, pushing the various registers onto the stack. These take time to execute and slow your program down. Not to mention that I doubt that it could be easily done within a procedure.

The fastest most memory efficient way to do it is with data in your data section and pointers. If you are using the macro for 100% totally unique data then it does essentially the same thing but the code is a little messy. Why not use string tables if you have alot of text data and want to avoid having it in a large chunk at the top of your program.

Donkey
Posted on 2003-03-06 08:53:59 by donkey
That makes sense. =o)

Since a new string is being created everytime in the .data section it keeps adding more & more everytime the MACRO is used.

The onlything I can think of is that maybe a temporary buffer could be used somehow, that way a new instance of string wouldn't be placed in data section everytime.

How would we set up a string variable/buffer where the buffer could be reused, like below:


.code
Use_StringBuffer Proc strBuffer$:DWORD,txtEditBoxText$:DWORD

;This is a VB based line that need's converted...
strBuffer$ = txtEditBoxText$

(Code to display strBuffer$'s current string...)

ret
endp


Each and everytime the function is used, a different string is placed in buffer and the buffer is re-used, the question is, how do you do it, how can you place a variable string from 1 buffer to another buffer, and/or change the string inside the a buffer after it has already been filled?
Posted on 2003-03-06 20:06:33 by Knight Chat X
I don't know if this is what you are after, but I threw this together quickly:
Contains asm dll source and vb5 project

pass the handle of the text box, and the dll creates a temporary buffer and shows the text in a message box...

Modify it from there....
Posted on 2003-03-06 20:40:46 by Gunner
Hi KnightChatX,

You cannot use the buffer method to save memory. What are you going to fill the buffer with, that information has to come from somewhere. Maybe it would help if you explained what exactly where the string is coming from. Are you using ASM as a DLL for VB and it supplies the string or is the string coming from user input. If it is neither of these two things then you are just wasting memory and CPU clocks creating a buffer that already exists. No matter what you use to pass the string, unless that string is acquired outside your program the data to fill it must exist inside your program. Remember that the source code with the "This is my string" nicely identified is not available to your program. To copy it into a buffer it has to be copied from somewhere and that somewhere is either the .data section or a string table. I don't know any other way to say this - There is NO way around it, to copy something you have to have an original.

Use the lstrcpy API function to copy strings

invoke lstrcpy,ADDR buffer,ADDR string

Donkey
Posted on 2003-03-06 21:22:40 by donkey
Thx Gunner, going to look at that code in a bit.
Posted on 2003-03-06 21:40:05 by Knight Chat X
Hi Donkey,

Question 1:
What are you going to fill the buffer with?

Answer 1:
Data from user input, editbox, another buffer, or even a string that may be in the .data section as initialised, etc...

Question 2:
Are you using ASM as a DLL for VB?

Answer 2:
No, I'm not using VB at all in this, and not creating any ASM DLL for work in VB, I'm trying to take the knowlege of VB language I know and try and cross over to ASM and create programs in ASM converting stuff I previously developed in VB and porting it to ASM.

1 of the main things I do in VB constantly is working with variables, array's, and array objects, currently I'm finding it difficult to find information explaining how to accomplish creating and simple usage of those type of things in ASM.

Though there's plenty of information on how to use API's and pre-created objects, and the proper way to use the mov instruction, what about information on variables, arrays, some of the simple yet important items to logic blocks in any language, like basic counter FOR loops???
Posted on 2003-03-06 22:14:03 by Knight Chat X
I would suggest in that case that you really stop trying to imitate the VB treatment of variables exactly, you're going to drive yourself batty. There is a level of disassociation from the reality of the machine in VB and most HLLs. I was lucky, I came to ASM directly without bothering with HLLs at all. I'm not suggesting that anything you learned in VB is useless in ASM, but in some cases you may be forced to adjust your thinking a bit. But if you want a scenario that will explain in VB terms how to look at variables, take this.

I believe that in VB there is the directive OPTION EXPLICIT, in ASM that is always on. In other words everything must be previously declared in order to be used in your program. You cannot create variables "on the fly" so to speak. And even though in VB you can use a literal string, that is essentially creating a new variable and is not allowed in ASM. However there are ways around this using buffers and the .data? uninitialized data section. In .data? the space is set aside at run time for values not know at compile time.

So given that everything must be declared, you can look at a string as the contents of a variable and that variables identifier is it's offset or address. You can either store this address in a named tag (usually beginning with lp or p to indicate a pointer) or use the ADDR or OFFSET prefix directly. There is also a mnemonic LEA that will load the effective address of the text.

Now, for your specific problem, if you don't know the source of your input at the time you are writing the program you're probably forced to use a buffer. For instance to get the text from almost any control...

invoke SendMessage,hControl,WM_GETTEXT,cchTextMax,ADDR buffer

to copy a string from the data section to your buffer use lstrcpy as I explained in another post.

Loops like FOR/NEXT and WHILE/ENDW are offered as part of MASM and function essentially the same way as in VB (with some differences to accomodate the limitations of the language). You usually use registers as your counter (ecx is a good choice as that is it's stated purpose). In some cases the incrementing or decrementing is handled by the CPU as with the LOOP mnemonic, if not you must manually adjust your loop counter using inc or dec.

If you downloaded Hutch's MASM32 package there is a help file called ASMINTRO.HLP included that will explain all of these basic elements of the language. If you haven't got it I suggest that you get Hutch's package and read through that file. It has a good section on loop design as well as an extensive explanation of working with strings. For further information on specific mnemonics see the OPCODES.HLP file.

Donkey
Posted on 2003-03-06 23:54:18 by donkey
Well, so far the treatment of ASM like VB and the research has been pretty successful, with the understanding that the higher level languages were built ontop of these lower concepts, I'm finding the answers slowly but surely and so the programming is becoming a bit easier for me now...

For any language the basic logic is most important, without that, deciphering and porting between code is very difficult but not impossible.

Like in the answers to my first question here on this board, Donkey gave answer for how to return specific value, string or number, then Gunner's example and understanding of the question of VB lead to a complete conversion of that exact code in ASM, that opened the door for me because I saw how to create and implement a wider range of logic blocks in the same manner as an IF statement, except a converted version of it and produce it in the same manner as in VB. To make it simple, the conversion was successful.

This time Gunner's asm DLL code answered a big portion of this question, leaving the only remaining questions for this problem being, now we've got the buffer, and can put data in it, how can we make it global, and not just local to a procedure so we can store the data until we need to change it, so the variable is still useable for other procedures etc. in the program. and lastly, how could we copy the data in that variable to another variable.

Donkey, lookin through the help file now thanks...
Posted on 2003-03-07 01:03:45 by Knight Chat X
To make it global declare it in the .data? section:

.data?
buffer db 256 DUP(?)

Donkey
Posted on 2003-03-07 01:10:44 by donkey
Gunner, in that ASM DLL, where eax is incremented, that's to add the null terminated charactor to the charactor count correct?

Or, is it for the heap so the process can use the entire amount when the number is higher?
Posted on 2003-03-07 03:47:28 by Knight Chat X
I used the dll cause I thought you were going to use it from vb. Anyway,
1, yes to grab the null

2, to make the buffer "global", create a dword in the .data? section then when you create the buffer with heapalloc, just put the return to that buffer. Instead of destroying the heap allocated buffer when the proc is done, be sure to heapfree when the program terminates...
Posted on 2003-03-07 05:39:58 by Gunner
If you really want to use API functions with asm in VB and pass parameters correctly, instead of using an asm DLL and worrying about all the formatting, just put the asm code directly inside a bas module, create a main window, uncheck all references to bypass the runtime files, and set the startup to Sub Main and use asm, you may need to turn off VB's syntax checking.
Sorry, but that is the funniest thing i have heard in a long time, who told it to you? :rolleyes: This is so wrong i'm surprised they didn't try to sell you the Statue of Liberty at the same time ;)

Yes, i did misinterpret your question initially, which is why i talked about asm dlls. Anyway, i think donkey and gunner have you sorted out nicely now.
Posted on 2003-03-07 15:22:18 by sluggy