To the Ineffable All,

    Could someone tell me why StringCbVPrintf does not work in this simple example?  See attachment.  It works OK when I use wsprintf.

Ratch
Attachments:
Posted on 2010-12-24 22:54:41 by Ratch
what os are you using?
Posted on 2010-12-25 12:38:29 by roaknog
roaknog,

I am using Windows Vista.

Ratch
Posted on 2010-12-25 12:47:47 by Ratch
The last argument is a pointer.

wvsprintf ~~ StringCbVPrintf

wsprintf ~~ StringCbPrintf
Posted on 2010-12-26 13:49:46 by drizz
drizz,

The last argument is a pointer.


Yes, the last argument is a pointer to the text string, as shown in the listing.


Ratch
Posted on 2010-12-26 15:17:02 by Ratch
Pointer to arguments for formating...

push offset szText
INVOKE StringCbVPrintfA,@ szBuffer,50,@ szFormat,esp
add esp,4
Posted on 2010-12-26 16:14:12 by drizz
drizz,

push offset szText
INVOKE StringCbVPrintfA,@ szBuffer,50,@ szFormat,esp
add esp,4


What does that do?  Before it is pushed on the stack by INVOKE, ESP is one DWORD less than it was when the address of the szText string was PUSHed.  Anyway, as expected, that does not work either.  Can you provide a mimimal example showing a coding that works?

Ratch
Posted on 2010-12-26 16:41:21 by Ratch
I don't use masm32 but win32inc : http://www.japheth.de/Win32Inc.html
.686
.model flat,stdcall
option casemap:none
include windows.inc
include tchar.INC; comment out the "include wchar.inc" line
include stdio.inc

.data?
szBuffer _TCHAR 50 DUP (?)

.data
szText  _TCHAR 'A','B',0
szFormat _TCHAR 'X','Y','Z','%','s','1','2','3',13,10,0
 
.code
StringCbVPrintfW proto stdcall :dword, :dword, :dword, :dword
StringCbVPrintfA proto stdcall :dword, :dword, :dword, :dword

ifdef _UNICODE
StringCbVPrintf equ StringCbVPrintfW
else
StringCbVPrintf equ StringCbVPrintfA
endif

PrintIt proc c args:vararg
invoke StringCbVPrintf,addr szBuffer,sizeof szBuffer/sizeof _TCHAR,addr szFormat,addr args
invoke _tprintf,addr szBuffer
ret
PrintIt endp

main proc C uses esi edi ebx argc:dword,argv:ptr dword
LOCAL ArgArray[1]:DWORD

;1
push offset szText
invoke StringCbVPrintf,addr szBuffer,sizeof szBuffer/sizeof _TCHAR,addr szFormat,esp
invoke _tprintf,addr szBuffer
pop edx

;2
invoke PrintIt,addr szText

;3
mov ArgArray[0*DWORD],offset szText
invoke StringCbVPrintf,addr szBuffer,sizeof szBuffer/sizeof _TCHAR,addr szFormat,addr ArgArray
invoke _tprintf,addr szBuffer

invoke getchar
ret

main endp

end


Radasm output
D:\Dev\Masm\Bin\jwasm.EXE /D_UNICODE /c /coff /Cp /nologo /DWIN32_LEAN_AND_MEAN /I"D:\Dev\Masm\Include" "strsafetest.asm"
strsafetest.Asm: 53 lines, 2 passes, 78 ms, 0 warnings, 0 errors
D:\Dev\Masm\Bin\LINK.EXE @cmd.linker /RELEASE /LIBPATH:"D:\Dev\Masm\Lib" /LIBPATH:"D:\PSDK\Lib" /LIBPATH:"D:\MSVCT\Lib" "strsafetest.obj"
Executing:
"D:\Dev\Projects\Masm\strsafetest\strsafetest.exe"

Make finished.


PSDK  + MSVC Toolkit 2003 + win32inc + JWasm + Radasm



I'll leave "what does 'push esp' do?" for you to solve.



Attachments:
Posted on 2010-12-26 17:40:40 by drizz
Here is a summary of what you should do:

1) create a proper "main/WinMain" and do not override the libc entrypoint
;SUBSYSTEM CONSOLE
main proc C uses esi edi ebx argc:dword,argv:ptr dword
ret
main endp

end



;SUBSYSTEM:WINDOWS
WinMain proc stdcall hInstance:HINSTANCE, hPrevInstance:HINSTANCE, lpCmdLine:LPSTR, nCmdShow:DWORD
ret
WinMain endp

end


2) the last argument for StringCbVPrintf is a pointer to format arguments
look for ;1 ;2 ;3 in code of my previous post

important notice) there is a hidden var that must be defined for libc if dealing with floating point code or you will get "floating point not loaded r6002" error.
extern c _FPinit:dword
Posted on 2010-12-26 18:32:23 by drizz
drizz,

I thank you for the work you put in to make an example.  Unfortunately, the example is too complicated for me to assemble or understand, because I code using minimalistic techniques that do not use Procs or many of the other MASM artifices.  Let me share some of my experience.  The code snippet below executes just fine when I use wvsprintfA, but it errors within StringCbVPrintA itself when I use that call.  That tells me that StringCbVPrintA is not quite ready for prime time yet, because it cannot be trusted to run to completion.  I have used StringCbVPrintA and StringCbVPrintW in other programs, and it worked fine.  But this small example errors out for no reason I can discern.  If you have any enlightenment about this, I am all ears.

Ratch

START:
  PUSH @ szText
  INVOKE wvsprintfA,@ szBuffer,@ szFormat,ESP            ;WORKS JUST FINE
;  INVOKE StringCbVPrintfA,@ szBuffer,50,@ szFormat,ESP  ;NEVER RETURNS FROM StringCbVPrintA
  ADD ESP,1*DWORD
 
  INVOKE ExitProcess,0
  END START
Posted on 2010-12-27 00:24:46 by Ratch
The code for StringCbVPrintf is linked statically and since it relies on C-runtime library being initialized - it fails.

with:
start:
end start


You override the entrypoint labels defined in "CRTMT.LIB" (which are "mainCRTStartup" and "WinMainCRTStartup" - cui/gui)

If you replace CRTMT.LIB with dll runtime MSVCRT.LIB, I think that should  work even with entrypoint overridden (I do not recommend it).

The proper way is to let c-runtime initialize as i showed in my previous posts. If you do not use procs then make a label.



public main
main:
; main is called from c-runtime
retn

end;; <<<<<- nothing after end


Posted on 2010-12-27 07:41:12 by drizz
drizz,
  Good news, it works.  I don't understand what you are saying with regard to "mainCRTStartup", "WinMainCRTStartup", and  overiding with "start", but your explanation gave me inspiration to compare what my test program INCLUDELIB'ed with a program that works.  I found that I must INCLUDELIB \MASM32\LIB\CRT.LIB, or the program will not work.  Unfortunately neither Pelle's or Microsoft's linker will flag that omission, and instead will indicate that the executable is OK.  So my minimalistic code does if fact work as shown, if the correct libraries are included.  By the way, my MS Platform SKD XP documentation does not say that StringCbVPrintf needs or is part of the C runtime library. The code snippet below shows what is needed.  Thanks again.  Ratch



.NOLIST
  INCLUDE C:\PROJECTS\DEFINITIONS.INC
  INCLUDE \MASM32\INCLUDE\WINDOWS.INC
  INCLUDE \MASM32\INCLUDE\USER32.INC
  INCLUDE \MASM32\INCLUDE\KERNEL32.INC
  INCLUDE \MASM32\INCLUDE\GDI32.INC
  INCLUDE \MASM32\INCLUDE\STRSAFE.INC
 
.LIST
  INCLUDELIB \MASM32\LIB\USER32.LIB
  INCLUDELIB \MASM32\LIB\KERNEL32.LIB
  INCLUDELIB \MASM32\LIB\GDI32.LIB
  INCLUDELIB \MASM32\LIB\STRSAFE.LIB
  INCLUDELIB \MASM32\LIB\CRT.LIB                  ;THIS MUST BE INCLUDED
  INCLUDELIB \MASM32\LIB\CRTMT.LIB 
;  INCLUDELIB \MASM32\LIB\MSVCRT.LIB
Posted on 2010-12-27 09:28:42 by Ratch
By the way, my MS Platform SKD XP documentation does not say that StringCbVPrintf needs or is part of the C runtime library.

Then why the need for CRT.LIB or CRTMT.LIB or MSVCRT.LIB?
strsafe.lib(strsafe.obj) : error LNK2019: unresolved external symbol __vsnprintf referenced in function _StringVPrintfWorkerA@16
strsafe.lib(strsafe.obj) : error LNK2019: unresolved external symbol __vsnwprintf referenced in function _StringVPrintfWorkerW@16
Because it does use c-runtime!

I don't understand what you are saying with regard to "mainCRTStartup", "WinMainCRTStartup", and  overiding with "start"


Study this example and see what happens when you place "start" "end start" instead of "main". I don't what else to say.

.686
.model flat,stdcall
option casemap:none

INCLUDELIB \MASM32\LIB\CRTMT.LIB

puts proto c :dword
getchar proto c

INCLUDELIB \MASM32\LIB\STRSAFE.LIB

StringCbVPrintfA proto stdcall :dword,:dword,:dword,:dword

.DATA?
  szBuffer WORD 50 DUP (?)
 
.data
  szText  BYTE 'A','B',0
  szFormat BYTE 'X','Y','Z','%','s','1','2','3',0

.code

public main
main:
push offset szText
INVOKE StringCbVPrintfA,offset szBuffer,50,offset szFormat,esp
pop edx
INVOKE puts,offset szBuffer
INVOKE getchar
retn

end



I don't understand what you are saying with regard to "mainCRTStartup", "WinMainCRTStartup"

See what error do you get when you compile this:
.686
.model flat
option casemap:none
.code
end
Posted on 2010-12-27 11:20:30 by drizz
drizz,
Then why the need for CRT.LIB or CRTMT.LIB or MSVCRT.LIB?
Because it does use c-runtime!


No question, it is part of the C runtime library.  My wonderment is why the Platform SDK does not reveal that fact.  By the way, MSVCRT.LIB is not needed for my program, but CRT.LIB is needed.
Study this example and see what happens when you place "start" "end start" instead of "main". I don't what else to say.


I don't either.  No matter what name I use for the starting label, it runs just fine now.


See what error do you get when you compile this:

OK, but that is not what I am using.


The code for StringCbVPrintf is linked statically and since it relies on C-runtime library being initialized - it fails.
You override the entrypoint labels defined in "CRTMT.LIB" (which are "mainCRTStartup" and "WinMainCRTStartup" - cui/gui)
If you replace CRTMT.LIB with dll runtime MSVCRT.LIB, I think that should  work even with entrypoint overridden (I do not recommend it).

The proper way is to let c-runtime initialize as i showed in my previous posts. If you do not use procs then make a label.

I cannot leave CRTMT.LIB out or the linker will squawk even if I put in MSVCRT.LIB.
Ratch
Posted on 2010-12-27 20:58:51 by Ratch
StringCbVPrintf works in Xp and 2000.
Posted on 2010-12-28 21:22:43 by roaknog
roaknog,

StringCbVPrintf works in Xp and 2000.


Thanks, roaknog.  It works for me in Vista for ASCII, too.  But I discovered that when I try to output a UNICODE string, StringCbVPrintfW only outputs the first character of the string.  I am using '%s' for the format specification.

Ratch
Posted on 2010-12-30 09:48:00 by Ratch
Those whacky library files you use allow you to use either the szText as a WORD or BYTE variable.  However if you use a WORD you must use the full WORD with something other than null or you get null termination.  20h works nicely as a space.  See attached file...
Posted on 2011-01-08 08:35:35 by roaknog
roaknog,

Those whacky library files you use allow you to use either the szText as a WORD or BYTE variable.  However if you use a WORD you must use the full WORD with something other than null or you get null termination.  20h works nicely as a space.  See attached file...


Thanks for proving my point that StringCbVPrintfW is defective, and got by MS's quality assurance and control operation, whatever that is.  I don't want to put a space after every character in the text, or pad the UNICODE word with a space or something.  That is not the way UNICODE is specified.  One does not have to do that for the format string, right?  And the sister function wvsprintfW does not work wacky that way, does it?  So what can any rational person conclude about StringCbVPrintfW?

Ratch
Posted on 2011-01-08 19:37:47 by Ratch

The use of the TCHAR() and TEXT() macros for defining strings help when you are attempting to write portable code that will be used in either an ASCII or UNICODE defined Windows environment.  However, be careful when writing internationalized code as Windows wchar_t is 16 bit and internally Windows is UCS-2 ( not UTF-16 ).  There is a big difference if your end users native language contains characters outside the BMP plane ( eg: chr > 0xFFFF ).  It's been a while so I don't remember exactly if Windows handles surrogate pairs properly yet or not.  I do, however, remember that there are a lot of landmines when programming for UNICODE in Windows.

Posted on 2011-01-08 21:33:46 by p1ranha
piranha,

The use of the TCHAR() and TEXT() macros for defining strings help when you are attempting to write portable code that will be used in either an ASCII or UNICODE defined Windows environment.


I am programming in MASM, not C, so TCHAR() and TEXT() don't apply to me.  I did not use them in the example I posted.  I am just trying to call a UNICODE function in a program.  I don't have any probs with any UNICODE function except StringCbVPrintfW. I don't know what an ASCII or UNICODE Windows environment is.  As far as I know, the application program determines whether ASCII or UNICODE will be used. In other words, I am unaware of a ASCII Windows or a UNICODE Windows.

Ratch
Posted on 2011-01-08 22:38:41 by Ratch