Day 045 - A DbgView digression

With my memory refreshed on WinDev's testing capabilities, I created a test class as follows:

MyClass is class
END

PROCEDURE Constructor()

PROCEDURE Destructor()

PROCEDURE MethodA(intValue is int)
RESULT intValue

PROCEDURE MethodA(strValue is string)
RESULT strValue

PROCEDURE MethodB(value)
RESULT value

I started with MethodB, which takes a parameter of undefined type. 

Here's my test data - the first iteration passes a number, the second a string.

In both cases I get back the expected value, but am I really passing a string? I hadn't put it in quotes. I tried setting a breakpoint in the class, but the break point never triggered. 

So I thought I'd do what I often do in Clarion when I can't rely on the debugger: use OutputDebugString. This is a Windows API call that writes a string to the system log, which you can view with the DbgView utility. 

But how to call OutputDebugString?

It turns out there's a utility program included with WinDev called WDAPI, and it will write the WinDev code you need for various API calls:

The code I needed was:

lpOutputString is int système // C Type:LPCSTR, is a string address, you can also specify a string directly

API("KERNEL32","OutputDebugStringA",lpOutputString)

but it would be silly to add that to every method. Much easier to create a global procedure, right? 

In the project explorer I found the Procedures node and right-clicked. I got options to create a subfolder and create a global procedure set. The latter seemed like it would get me a little closer; I guess a procedure set is a way of grouping global procedures. But how to create the procedure?

I found that option on the main menu under Insert. But nothing happened when I exercised that menu option. I was still in the procedure set with no procedure. 

So I closed the procedure set without saving and then I tried again, this time without creating the procedure set first. I got a window to save a new procedure set:

and then a prompt asking me for the name of my procedure, which I called Debug. When I saved I got the procedure declaration, and I pasted in the code from WDAPI:

 

As you can see I had a syntax error, which I wasn't sure how to handle. 

But first I updated my MethodB code to call Debug():

PROCEDURE MethodB(value)
Debug(value)
RESULT value

The help seemed to indicate that I could specify a string directly instead of using the suspect definition for a long pointer. That didn't seem right to me, first because sMsg is a WinDev string and second because the API call really is expecting a pointer. But what the heck - maybe WinDev was working some magic with the API call. So I tried:

PROCEDURE Debug(sMsg is string)
// lpOutputString is int système // C Type:LPCSTR, is a string address, you can also specify a string directly
API("KERNEL32","OutputDebugStringA",sMsg)

but that crashed the test. So I declared the pointer this way:

nLpOutputString is system int

and then I dug around until I discovered that the address operator is the ampersand. So I assigned the string address

nLpOutputString = &sMsg

which compiled fine. When I ran the test, however, I got a runtime error on the API call and the test failed. 

Clearly I needed to find a way to change my string to a cstring and feed the cstring pointer to the API call. 

Eventually I came across a page that indicated I needed to use the ASCIIZ string type in this situation. Only one problem: there is no ASCIIZ string type in WinDev 17, at least not that I can see. But there is an ANSI string type. 

Here's the code I ended up using:

PROCEDURE Debug(sMsg is string)
nLpOutputString is system int// C Type:LPCSTR, is a string address, you can also specify a string directly
sDebugMsg is ANSI string
sDebugMsg = sMsg
nLpOutputString = &sDebugMsg
API("KERNEL32","OutputDebugStringA",nLpOutputString)

Now my unit test ran, and more importantly I could see the log statements in DbgView's window. 

[4520] abc
[4520] 35

And I was out of time. More tomorrow!