Solved Exe crashing

Discussion forum about all things Team Developer 5.x and 6.x
wilhelm
Germany
Posts: 191
Joined: 22 Mar 2017, 08:49
Location: Cologne

Exe crashing

Post by wilhelm » 28 Jun 2017, 13:10

Hi everyone it's me again,

after successfully converting a 4.2 application to 6.0 SP8 I finally complied an exe file from it.
Guess what: When I start that exe file, it crashes.
The eventlog states:
Name des fehlerhaften Moduls: USER32.dll, Version: 6.1.7601.23594, Zeitstempel: 0x58249e1c
Ausnahmecode: 0xc0000005
Fehleroffset: 0x00018fcb

So I am a bit at a loss here. The application runs normally in the IDE but cashes when started as an exe file.

Does anybody have any pointers on how I could try to debug that problem?
Is there anything that comes to mind what could cause such strange behaviour?
Are there any tools I could use to find the cause?

I would appreciate any help you could give.
TIA
Wilhelm

EwaldP
Austria
Posts: 117
Joined: 07 Mar 2017, 08:00
Location: Austria

Exe crashing

Post by EwaldP » 28 Jun 2017, 14:17

Hi Wilhelm,
- same behaviour when you run the exe as administrator?
- what about uac (Benutzerkontensteuerung)
- what about dep (Datenausführungsverhinderung)
- from where do you run the exe? TD6.x dir or a deploy dir --> do you installed the deploy?
- Process Monitor from Sysinternals (Procmon.exe) is a good way to see what happened
- if the problem is inside your app, you can trace your application --> look at here: http://wiki.tdcommunity.net/index.ph ... nal_viewer
- maybe the TDAppTool from Dave could help you, but I have no experience


Regards
Ewald
Ewald P. Palmetshofer
EDV-Hausleitner GmbH
4020 Linz
www.edv-hausleitner.at

Dave Rabelink
Founder/Site Admin
Founder/Site Admin
Netherlands
Posts: 1137
Joined: 24 Feb 2017, 09:12
Location: Gouda, The Netherlands

Exe crashing

Post by Dave Rabelink » 28 Jun 2017, 14:36

I also recommend to profile the application using TDProfiler:

http://wiki.tdcommunity.net/index.ph ... _Profiling

Nice way to run application, let it crash and then use the log to see what has been executed and the last function called.
Regards,
Dave Rabelink

Image
Articles and information on Team Developer Tips & Tricks Wiki
Download samples, documents and resources from TD Sample Vault
Videos on TDWiki YouTube Channel

wilhelm
Germany
Posts: 191
Joined: 22 Mar 2017, 08:49
Location: Cologne

Exe crashing

Post by wilhelm » 29 Jun 2017, 14:21

Thanks guys for all your tipps.

Unfortunately the app simply crashes, before I can do anything with it, meaning it crashes even before the SAM_Createcomplete message is finished.
So using the TDApptools isn't really an option.
The profiler log just shows a few messages and then the log stops, no clue there.

What I am suspecting is a problem with the CStruct library and tons of SalStrSetBufferLenght that I have to check.
Frankly I don't want to use Unicode as some of the dlls cannot handle it. It seems that TD converts the internal Unicode properly before handing them to the dlls.
What I don't quite understand is, how using SalStrSetBufferLenght() should be converted to SalSetBufferLength()
If I use a Struct that I want to hand to the Windows API when does the conversion to 8Bit take place?

For example I have a function that copies a string to memory and returns a pointer to that.

Code: Select all

Function: CStructPutStringCustom
	Description: Allocates space for sString in Memory und inserts a pointer to that string in
			String sBufferDest at the position nAddrDest.
			
			nAddrString = CStructPutStringCustom( sBufferDest, nAddrDest, sString )
			
			ATTENTION! The allocated stringbuffer needs to be freed after use.
				 CStructFreeFarMem( nAddrString )
	Returns
		Number:
	Parameters
		Receive String: sBufferDest
		Number: nAddrDest
		String: sString
	Static Variables
		Number: nAddrString
		String: sBufferString
	Local variables
	Actions
		If SalStrSetBufferLength( sBufferString, SalStrLength(sString)+1 )
			Call CStructPutString( sBufferString, 0, SalStrLength(sString)+ 1, sString )
			Set nAddrString = CStructAllocFarMem( SalStrLength(sString)+1 )
			If nAddrString
				Call CStructCopyToFarMem( nAddrString, sBufferString, SalStrLength(sString)+1)
				Call CStructPutLong( sBufferDest, nAddrDest,  nAddrString )
		Return nAddrString
How would I convert that to the SalSetBufferLenght() version?
Whould CStructCopyToFarMem() result in 8 or 16 bit characters in the buffer?

The examples in the Gupta documentation confuse me more than it would help.
Maybe an example of that would clarify things for me.

TIA
Wilhelm

Jeff Luther
Site Admin
Site Admin
United States of America
Posts: 2166
Joined: 04 Mar 2017, 18:34
Location: Palm Springs, California

Exe crashing

Post by Jeff Luther » 29 Jun 2017, 17:04

Let me jump in with a couple questions based on what you wrote, Wilhelm:
4.2 application to 6.0 SP8 I finally complied an exe file from it.
> Does that mean that running the converted source with TD runs OK, no crash?

> Are you running your test EXE from the same development folder where your source code is?

> One of the big changes from 4.x --> 5.2 and later was the Unicode feature. Any external libs. with String LPSTR declarations needs to be changed to LPWSTR, etc. Here's an old Unicode overview set of links on my TD web site area if you are not familiar with Unicode issues in later TDs: http://www.jeffluther.net/TD/#UNICODE_INFORMATION

> Another possibility might be that your EXE is (somehow) picking up runtime DLLs from the old v4.2 TD, and not the correct TD v6.0 DLLs.
it crashes even before the SAM_Createcomplete message is finished
> That msg. is sent to toplevel windows, so it's a form, dlg., table window SAM_CreateComplete msg. you are referring to? How far into the msg. does the code get? (You can't single-step in an EXE, but for a test put a SalMsgBox with title = <previous code line> after each line of code in the SAM msg. to see how far the code works before the crash. Primitive but it can work.)
You could also use event logging instead of the msg. box. See my sample titled EVENT LOGGING among my samples: http://www.jeffluther.net/TD/#Code_Samples
What I am suspecting is a problem with the CStruct library...
> That function comes from the SalExtensions library many of us have contributed to, cstructlExt.apl, I see, and not from TD's cstructl.apl lib itself.
If you suspect this, then I would suggest you write a small test case to see if a call to CStructPutStringCustom() is crashing in the EXE.
Jeff Luther @ PC Design
Palm Springs, California
TD info. & samples: http://www.jeffluther.net/TD/

wilhelm
Germany
Posts: 191
Joined: 22 Mar 2017, 08:49
Location: Cologne

Exe crashing

Post by wilhelm » 29 Jun 2017, 19:23

Hi Jeff,
thanks fpor jumping in!
Jeff Luther wrote:
29 Jun 2017, 17:04
Let me jump in with a couple questions based on what you wrote, Wilhelm:
4.2 application to 6.0 SP8 I finally complied an exe file from it.
> Does that mean that running the converted source with TD runs OK, no crash?
Yes absulotely
> Are you running your test EXE from the same development folder where your source code is?
Yes
> One of the big changes from 4.x --> 5.2 and later was the Unicode feature. Any external libs. with String LPSTR declarations needs to be changed to LPWSTR, etc. Here's an old Unicode overview set of links on my TD web site area if you are not familiar with Unicode issues in later TDs: http://www.jeffluther.net/TD/#UNICODE_INFORMATION
Ok, I will read that. If I understand correctly you say the dlls must be unicode? That is not possible in my case. Some of the dll come from a German health organisation and they don't provide unicode support.
I have no influence on that. But as I said above. in the IDE all seems ok.
> Another possibility might be that your EXE is (somehow) picking up runtime DLLs from the old v4.2 TD, and not the correct TD v6.0 DLLs.
No, I renamed the 4.2 Unify directory so there is no chance that it is found
it crashes even before the SAM_Createcomplete message is finished
> That msg. is sent to toplevel windows, so it's a form, dlg., table window SAM_CreateComplete msg. you are referring to? How far into the msg. does the code get? (You can't single-step in an EXE, but for a test put a SalMsgBox with title = <previous code line> after each line of code in the SAM msg. to see how far the code works before the crash. Primitive but it can work.)
You could also use event logging instead of the msg. box. See my sample titled EVENT LOGGING among my samples: http://www.jeffluther.net/TD/#Code_Samples
Ok, but I suspect the crash is asynchronous, because it doesn't happen always in the exact same place.
What I am suspecting is a problem with the CStruct library...
> That function comes from the SalExtensions library many of us have contributed to, cstructlExt.apl, I see, and not from TD's cstructl.apl lib itself.
If you suspect this, then I would suggest you write a small test case to see if a call to CStructPutStringCustom() is crashing in the EXE.
As I stated above, it runs ok in the IDE. I don't suspect I can make a reproducable test case, but we will see.

Thanks again for you input. I'll keep you posted

Wilhelm

Dave Rabelink
Founder/Site Admin
Founder/Site Admin
Netherlands
Posts: 1137
Joined: 24 Feb 2017, 09:12
Location: Gouda, The Netherlands

Exe crashing

Post by Dave Rabelink » 30 Jun 2017, 05:21

Hi Wilhelm,

Random crashes is a good indication for memory management issues.
Something makes TD instable and unrelated actions in the application sometime later on could eventually lead to a crash.
I have seen many occasions where the location of the crash had nothing to do with the actual cause.

Your prime suspect is ANSI vs UNICODE and your API calls.

The first thing to do is making sure what you are doing. Be aware of the differences between ANSI and UNICODE when it comes to memory management.

But let me give some additional tips on your converted sources:

Make sure you use the original TD include libraries (eg the visual toolchest libraries or the quick* libs).
Most of the TD API's have changed from ANSI to UNICODE. I have seen many projects where the vt*.dll declarations were just a copy from the original libraries.
And changing vti31.dll to vti42.dll was a fairly safe action when converting. But that is not the case in TD42->TD5.x and higher.

So remove all those declarations and include the official vt libs you need.

Also. In some cases, hidden settings are still present in your sources referring to older TD dll's.

One of the first actions I do when converting sources is:
  • Make sure all sources are in text format
  • Make a list of used dll's. Do this by using a text search tool on your files. Search for .dll
Having a list of references to dll's, you can see if the used dll's are custom ones, Win API dll's or TD dll's.

TD dll's you find (like vti42.dll) are prime suspect. They are copies. Be sure to use the original declarations when you want to keep the copies or even better, use the original libraries instead.

You might also find hits using the text search tool like this:

Code: Select all

.head 4 -  Class DLL Name: vti42.dll;4128;64;;;
They are from custom controls which have references to TD dll's

You must change this (using a text editor) into the correct TD version (by changing the version number only). So in your case

Code: Select all

.head 4 -  Class DLL Name: vti60.dll;4128;64;;;
THese lines can cause TD to crash or have strange effects on the GUI when still present in your code.


When you are using stuff from SalExtension (like Jeff explained), you can use the UNICODE version of SalExtension.

You can find the latest version (v211) here:

http://samples.tdcommunity.net/index ... Extension/

So, if your code has copies of classes or functions from SalExtension in the past, look up these classes or functions in the latest SalExtension and use that in your code.

As for WinAPI and other 3rd party dll's:

It is not a must to change ANSI API's to UNICODE API's. You can use both. A dll is not ANSI or UNICODE, the API interface expects ANSI or UNICODE.

This is the rule:

LPSTR expects ANSI strings
LPWSTR expects UNICODE strings
LPVOID expects any data (binary, ANSI or UNICODE)

When a UNICODE TD version calls a function with a LPSTR declaration, TD will automatically convert the passed string (which is UNICODE) to ANSI for you. THe DLL gets the string as ANSI.
When a UNICODE TD version calls a function with a LPWSTR declaration, the string will be passed as-is. TD expects that the passed string is already UNICODE, so the dll will get UNICODE string
But be aware of String: LPVOID declarations. These are specially suspect.
LPVOID means *ANY* type of data. Could be binary, ANSI strings or UNICODE strings. TD will pass a string as-is to the function.
So when a UNICODE string is passed, the DLL function will get UNICODE. When ANSI is passed, it will be ANSI.

You really have to visit every DLL function call and inspect the parameter and return values. Be suspicious of every function and see what it does and expects.
For WinAPI, use MSDN online to read the function documentation. See what the function expects and see how TD is using it.

If you are unsure about the usage, you can always ask here in the forum.

I'm quite sure your issue is related to API functions and wrong usage of strings and string lengths.


Some other remarks:
TDAppTools is not the tool to find crash causes.

As your application crashes at startup, it seems to me that the actions performed are fairly limited. So hopefully not much code is executed, so finding the rotten line is easier.
It is time consuming, but running the application from IDE and debug it starting in SAM_AppStartup at the first line and step by step inspect what it is doing.
Focus on dll API calls. Mark them as suspicious and investigate the correct usage. See that the results of those calls are the same in TD42 and TD60. Can even run them side-by-side to see if return values or received strings are identical.

When you are unsure about the correct working, make a simple testcase application only using those API calls.

TDProfiler tool shows you which functions are called. The trace file shows the calls up until the crash. Using the trace file, inspect those functions are focus on API calls there.
Regards,
Dave Rabelink

Image
Articles and information on Team Developer Tips & Tricks Wiki
Download samples, documents and resources from TD Sample Vault
Videos on TDWiki YouTube Channel

Christof
Germany
Posts: 9
Joined: 06 Mar 2017, 07:27
Location: Frankfurt, Germany

Exe crashing

Post by Christof » 30 Jun 2017, 06:29

In addition to Jeffs and Daves excellent remarks, a few details regarding string buffers.
Since TD uses Unicode for internal character representations, when it comes to functions which expect buffer lengths in bytes as parameters - and that is SalSetBufferLength as well as the whole CStruct-API - you always have to count two bytes per character. Also the terminating Nullbyte should be considered accordingly.
That means for example:

Code: Select all

Set nBytes = SalStrLength( sString ) * 2 + 2
If SalSetBufferLength( sMyString, nBytes )
  Call CStructPutString( sBufferString, 0,nBytes, sString )
  ...
Or for calling dll functions which fill a receive string (LWSTR) with string data, you need to reserve twice as much bytes as the expected character length, plus 2 for the Nullbyte.

Code: Select all

! Allow the GetClassNameW-APi to write up to 20 characters into sBuffer, we need 20 * 2 + 2 bytes allocated:
Call SalSetBufferLength( sBuffer, 42 )
Call GetClassNameW( hWnd, sBuffer, 20 )

wilhelm
Germany
Posts: 191
Joined: 22 Mar 2017, 08:49
Location: Cologne

Exe crashing

Post by wilhelm » 30 Jun 2017, 07:19

Hi Dave,

thanks for taking the time to write such an elaborate list of problems.
I think your tipp using a textsearch to find *42.dll parts in the source files is the best.
I found tons of q*42.dll entries in the class dll names of several objects.

When I'm through changing them all and following the other hints I will report.
Until then, have a nice day,

Wilhelm

wilhelm
Germany
Posts: 191
Joined: 22 Mar 2017, 08:49
Location: Cologne

Exe crashing

Post by wilhelm » 30 Jun 2017, 07:32

Thanks Christof,

I think thats only true, when using *W.dll s right?
If I understand correctly otherwise TD converts the strings to 8Bit.
Cheers

Wilhelm

Christof
Germany
Posts: 9
Joined: 06 Mar 2017, 07:27
Location: Frankfurt, Germany

Exe crashing

Post by Christof » 30 Jun 2017, 10:58

I think thats only true, when using *W.dll s right?
Yes that's right. But you've pointed out the use of the CStruct-Apis with strings, and there you definitely need to regard the byte lengths of Unicode strings!

Jeff Luther
Site Admin
Site Admin
United States of America
Posts: 2166
Joined: 04 Mar 2017, 18:34
Location: Palm Springs, California

Exe crashing

Post by Jeff Luther » 30 Jun 2017, 17:10

A clarification, Wilhelm, when you wrote
If I understand correctly otherwise TD converts the strings to 8Bit.
If you are saying what I think it is, the answer is No: TD assumes the string to be in the correct string format for passing as the param. to a function. Dave wrote about LPSTR, LPWSTR, etc. above about this.

And FYI TD has a pair of SalStr functions: SalStrToMultiByte() & SalStrToWideChar(), functions are used to convert a Unicode/double-byte string to single byte, and single byte (back) to Unicode/double-byte formats. Used to pass the correct 8- or 16-bit formatted string to a function so the stack doesn't get corrupted.

If you think the DLL might be the problem, then a small test case with TD code and calls to the function is the thing to do. Though when you wrote that
I suspect the crash is asynchronous, because it doesn't happen always in the exact same place
That makes it more problematic for zeroing in on the problem. A non-correct string param. call can corrupt the stack as I wrote, which might not show up as a crash (yet) until later. Dave R. might well have some thoughts on this too.
Jeff Luther @ PC Design
Palm Springs, California
TD info. & samples: http://www.jeffluther.net/TD/

wilhelm
Germany
Posts: 191
Joined: 22 Mar 2017, 08:49
Location: Cologne

Exe crashing

Post by wilhelm » 30 Jun 2017, 18:03

hi Jeff,

i spent the day today to narrow down the cause.
I face the problem, that I cannot reproduce the crash when running in the IDE. For what it's worth there are no major problems.
When starting the exe, the app crashes during the initialisation of the main mdi window.
So I try commenting several message actions to find narrow down the cause. no success yet.

My initial impression, that the problem is asynchronous seems to be wrong. I am still trying to imagine what might be different between running in the IDE and running the exe.

i have also checked the external definitions and everything seems to be in order. there are no Pointers that seem to be
suspicious during initialisation. All parameters are passed as lpstr and running in the IDE if this strings were passed in the wrong format, I should see some problems.

we'll see how long that process will take. I am beginning to doubt that the externals are the cause...
Thanks again
Wilhelm

wilhelm
Germany
Posts: 191
Joined: 22 Mar 2017, 08:49
Location: Cologne

Exe crashing

Post by wilhelm » 01 Jul 2017, 11:52

Hi guys,

just to let you know: I fixed it today.

As it turns out, all suspicions we shared were wrong. The cause was a WM_WindowsPosChanged message that one of my base classes was sending during SAM_CreateComplete. That must have lead to a message overflow in the runtime libary which lead to the crash in user32.dll. The only thing I did was comment that single SendMsg() line. Puhhh.

Everything else, especially the cstruct and buffer statement and the external libraries seem to be ok even with staying 8Bit.

I will have to do some finetuning and check exverything but I think I can handle that. Especially the Themes seem to need some work.

So thanks again for all your input.
Have a nice weekend!

Wilhelm

Jeff Luther
Site Admin
Site Admin
United States of America
Posts: 2166
Joined: 04 Mar 2017, 18:34
Location: Palm Springs, California

Exe crashing

Post by Jeff Luther » 01 Jul 2017, 19:35

That must have lead to a message overflow in the runtime
Wunderbar! Good find and the overflow sounds likely. Odd it didn't happen in the IDE, though. Thanks for letting us know about your solution!
Jeff Luther @ PC Design
Palm Springs, California
TD info. & samples: http://www.jeffluther.net/TD/

Return to “General Discussion”

Who is online

Users browsing this forum: [Ccbot] and 0 guests