Thursday, November 23, 2006

Failing to import WSDL file?


Seen days ago: there’s a WSDL file, MS VB.NET 2005 Express and a programmer planning to attach his VB.NET application to a WebService described with given WSDL file.
Insert in project WSDL file, build it – and get the error:



Quick solution: use WSDL compiler, compile the WSDL file, specify target language (/language:cs or /language:vb) and bind then the produced source file to your project instead of inserting the .wsdl file). It works!
Otherwise get ready to perform manual changes in the WSDL file to get it imported properly into you project. Do not ask why.
Enjoy!

Tuesday, September 12, 2006

How to find your Outlook Express post store

Are you looking for your Outlook Express Emails on local harddisk to transfer them to new machine?

Very good, look here:

http://email.about.com/cs/oetipstricks/qt/et101202.htm

Nice manual, with pictures, good prepared, enjoy!

Wednesday, September 06, 2006

Thursday, August 31, 2006

Symantec Firewall Client causes error joining Lenovo notebook x60s to W2K3 based domain

That was a wasting time action! Imagine: new x60s, working brilliant , all software setup properly. Trying to join MS W2K3 SBS based domain - failure!
You can joind the box to domain, you get invitation to restart - after restart the box doesn't see the domain.
Technical support of Lenovo has also no idea - and states, the box is OK, look for problem cause elsewhere.

Hours later: just disabled Symantec Firewall Client - and the problem solved.

I wonder, if test department of Lenovo does test this simple but very often used scenario... Seems to be - they miss that in test scenarios suite at all. Definitely.

So, if you are going to join Lenovo notebook with preinstalled software package to your domain - disable Symantec Firewall client and enjoy!

Monday, August 07, 2006

Missing Umlaute in ASP.NET WebForm Application?

Assume, you developed an ASP.NET WebForms Application running on Windows Server 2003 box. Assume, the application contains some portion of WebForm elements having special characters to show to user (like german Umlaute chars - ö Ö ä Ä ü Ü ß ).

Assume, one comes and installs something essential for ASP.NET settings on the same machine - mind just SharePoint Server for example.

Be next morning as early as you can in the office at your desk and get ready to hear the phone ringing: the users of your application will report missing chars in the forms.

The reason: you saved your .aspx files as ANSI, but actually the UTF-8 encoding expected.

Two ways out:

1. Re-save your application files (.aspx assumed) as UTF-8.
2. Tune fileEncoding attribute in globalization element of web.config for your application.

Choose appropriate one. Keep in mind, each save of web.config causes application restart (runnings sessions will be abandoned).

If the application is clustered (NLB), apply changes on each node. Enjoy!

Thursday, August 03, 2006

Investigation of application end crash in _CRT_INIT

Never seen?

The application does it's work, but crashes on exit. One clicks on the windows close box or selects "Exit" from menu and - ooops! - the MessageBox with read access vioaltion on the address 0xFFFFFFFC or so.

Well, the crash on exit is mostly not so dangerous as in session progress, but somehow annoying.

Where to search?

Let's investigate it: start WinDbg and attach to the application. Invoke application end and you'll get break on the similar code position:

(500.298): Access violation - code c0000005 (first chance)
First chance exceptions are reported before any exception handling.
This exception may be expected and handled.
eax=008dac60 ebx=30000000 ecx=00000000 edx=04790003 esi=fffffffc edi=00000000eip=3002eaef esp=0012f7e8 ebp=0012f808 iopl=0 nv up ei ng nz na po nccs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00010286
MyDLL!_CRT_INIT+0x83:3002eaef 8b0e mov ecx,[esi] ds:0023:fffffffc=????????

What does it mean? Your application uses a DLL MyDLL and crashes trying to unload this DLL.
Why?

Look into disassembly window:

3002ead2 eb3d jmp MyDLL!_CRT_INIT+0xa5 (3002eb11)
3002ead4 85c0 test eax,eax
3002ead6 7539 jnz MyDLL!_CRT_INIT+0xa5 (3002eb11)
3002ead8 a154be0630 mov eax,[HoFa32!__onexitbegin (3006be54)]
3002eadd 85c0 test eax,eax
3002eadf 7430 jz MyDLL!_CRT_INIT+0xa5 (3002eb11)
3002eae1 8b0d50be0630 mov ecx,[HoFa32!__onexitend (3006be50)]
3002eae7 56 push esi
3002eae8 8d71fc lea esi,[ecx-0x4]
3002eaeb 3bf0 cmp esi,eax
3002eaed 7212 jb MyDLL!_CRT_INIT+0x95 (3002eb01)
3002eaef 8b0e mov ecx,[esi] ds:0023:fffffffc=????????
3002eaf1 85c9 test ecx,ecx


What's that? I didn't implement any _CRT_INIT methods in MyDLL? Why does it crash here?

Here is it.

MyDLL is a DLL using MS C-Runtime: the _CRT_INIT comes from C-Runtime stub and will be added automatically to any DLL built with MC C-Runtime stub (refer to Platform SDK for more info).

The function _CRT_INIT is called on each attach to a process or a thread and is repsonsible for store of pointers to methods to be called on DLL start and exit. These methods may be chained, so two internal variables: __onexitend and __onexitbegin.

At DLL exit the C-Runtime stub perfroms sequential calls to registered methods as follows:


/*
* do _onexit/atexit() terminators
* (if there are any)
*
* These terminators MUST be executed in
* reverse order (LIFO)!
*
* NOTE:
* This code assumes that __onexitbegin
* points to the first valid onexit()
* entry and that __onexitend points
* past the last valid entry. If
* __onexitbegin == __onexitend, the
* table is empty and there are no
* routines to call.
*/
if (__onexitbegin) {

while ( --__onexitend >= __onexitbegin )
/*
* if current table entry is not
* NULL, call thru it.
*/
if ( *__onexitend != NULL ) ' <-- here occures the crash!
(**__onexitend)();
/*
* free the block holding onexit table to
* avoid memory leaks. Also zero the ptr
* variable so that it is clearly cleaned up.
*/
_free_crt ( __onexitbegin ) ;
__onexitbegin = NULL ;
}
}


The crash occures due to invalid pointer stored in __onexitend.

How does it come?

The both __onexitend and __onexitbegin resides in memory space of MyDLL. Somewhere in MyDLL code is a memory write operation (for example, varable assignement or array copy or so), that overwrites one or both of these variables with unpredictable values loosing original pointers.
At DLL _CRT_INIT just checks if content of __onexitend is not NULL: having a garbage value due to former overwrite operation causes try to call content of pointed memory fragment as CPU instruction - with read access violation as result.

How to investigate?

Well, if the content is overwritten, it is to late to cure. To find out, what portion of code causes the overwrite action, you need WinDbg and symbols for your application modules - at least of MyDLL, since frequently the local DLL methods are responsible for this boundary violation. So perform following steps:

1. Start WinDbg and open your application as executable.
2. WinDbg halts on start - here you have a chance to set first breakpoint. Set the breakpoint to _CRT_INIT of your DLL:

>bp MyDLL!_CRT_INIT

MyDLL is not loaded yet, so the breakpoint will be set as deferred:

Bp expression 'MyDLL!_CRT_INIT' could not be resolved, adding deferred bp

3. Resume the application and wait until your DLL will be loaded.
4. Some time later your DLL will be loaded and breakpoint hit occures

Breakpoint 0 hit
eax=00000000 ebx=30000000 ecx=000067e8 edx=7c91eb94 esi=00000001 edi=00000000
eip=3002ea6c esp=0012dc18 ebp=0012dc34 iopl=0 nv up ei pl zr na po nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000246
MyDLL!_CRT_INIT:
3002ea6c 8b442408 mov eax,[esp+0x8] ss:0023:0012dc20=00000001


5. Now you can set breakpoint on access operation for __onexitend and __onexitbegin:

> ba w4 MyDLL!__onexitend
> ba w4 MyDLL!__onexitbegin

6. You do not need the breakpoint on _CRT_INIT anymore (you used it to set access breakpoints), so you can disable or clear it:

>bd 0

7. Resume application and wait until breakpoint hit:

Breakpoint 1 hit
eax=ffffffff ebx=0000007b ecx=0012dd84 edx=0012dd84 esi=3006be50 edi=3004d84aeip=77c1466e esp=0012db58 ebp=0012dd70 iopl=0 nv up ei pl zr na po nccs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000246
*** ERROR: Symbol file could not be found. Defaulted to export symbols for C:\WINNT\system32\msvcrt.dll - msvcrt!wscanf+0x23a8:77c1466e e985fbffff
jmp msvcrt!wscanf+0x1f32 (77c141f8)

8. You've got it! This is the code place the content of internal system variables got overwritten. Analyze callstack to find out the calling method where the overwrite occures:

> kp
ChildEBP RetAddr
0012bfbc 77c11ba9 msvcrt!_input+0x97c
0012bff0 3000198a msvcrt!sscanf+0x37
00000000 00000000 MyDLL!process_answer+0x7a


OK, the overwrite happens in the method process_answer in MyDLL. Now you have enough info to navigate to the source code for bugfixing.
Keep memory safe! Enjoy.

Tuesday, July 04, 2006

ANSI BSTR in VB.NET

Assume you have an C DLL working fine with your VB6 program and now you are hitting the road to migrate towards VB.NET. Suddenly, you see, that the strings in structures tunneled to DLL from VB.NET code don't come properly. That's because VB.NET marshals strings as BSTR (double byte counted strings) and your DLL was trained to accept ANSI strings (same as BSTR but single byte). Try to use predefined MarshalAs(UnmanagedType.AnsiBStr) - maybe you'll be lucky. Didn't work for me.
There are two ways out:
- rewrite your DLL (if sources and resources are still available etc.)
- adjust you VB.NET code with AnsiBStr class (as follows) to get strings transferred to and from unmanaged world.

Enjoy!

Imports System.Runtime.InteropServices
'
' Class AnsiBString realizes marshaling of ANSI strings to
' unmanaged DLLs tuned for VB6 clients

'

Public Class AnsiBString
Implements IDisposable

' Used by IDisposable
Protected disposed As Boolean = False

' String buffer size
Dim Size As Integer
' String buffer
Dim Buffer As String
' Private pointer to unmanaged memory block contaning bytes
Private _ptr As IntPtr
'
' Public property - pointer to unmanaged memory containing single byte BSTR
'
ReadOnly Property Ptr() As IntPtr
Get
' String buffer starts after buffer size integer
Ptr = _ptr.ToInt32() + IntPtr.Size
End Get
End Property
'
' Constructor
'
Sub New(ByVal s As String)
'
' ONLY FOR DEBUGGING PURPOSES
' REMOVE FOR RELEASE VERSION
' System.Diagnostics.Trace.WriteLine("ANSIBSTR: Ctor for " + s + " " + Me.GetHashCode().ToString())

' Set buffer
Buffer = s
' Calculate size
Size = 0
If Not String.IsNullOrEmpty(Buffer) Then
Size = Buffer.Length
End If
' Allocate unmanaged memory block to store size and string buffer
' plus one byte for trailing zero to be safe
_ptr = Marshal.AllocHGlobal(Size + IntPtr.Size + 1)
' Store size in unmanaged memory
Marshal.WriteIntPtr(_ptr, 0, CType(Size, IntPtr))
If Size > 0 Then
' Get string buffer as ANSI bytes
Dim bArray() As Byte = System.Text.ASCIIEncoding.Default.GetBytes(Buffer)
' Write ANSI bytes to unmanaged memory
Marshal.Copy(bArray, 0, CType(_ptr, Integer) + IntPtr.Size, bArray.Length)
' Write zero byte at end for safety
Marshal.WriteByte(_ptr, IntPtr.Size + bArray.Length, 0)
End If
End Sub
'
' Counter part - get ANSI BSTR from pointer
'
Shared Function FromPointer(ByVal aPtr As IntPtr, Optional ByVal bFreePointer As Boolean = False) As AnsiBString
Dim size As Integer
If aPtr = IntPtr.Zero Then
FromPointer = New AnsiBString("")
Else
' Calculate string buffer size
size = CType(Marshal.ReadIntPtr(aPtr, -(IntPtr.Size)), Integer)
Dim bytes() As Byte
ReDim bytes(size)
' Read string bytes
Marshal.Copy(aPtr, bytes, 0, size)
' Create AnsiBString instance
Dim ansiBstring As New AnsiBString(System.Text.ASCIIEncoding.Default.GetString(bytes))
FromPointer = ansiBstring
If bFreePointer Then
Try
Marshal.FreeHGlobal(aPtr)
Catch ex As Exception
System.Diagnostics.Trace.WriteLine(System.Reflection.Assembly.GetExecutingAssembly().FullName + ":" + _
System.Reflection.Assembly.GetCallingAssembly().FullName + ": " + _
"free ANSI string pointer (" + aPtr.ToString() + "): " + ex.Message + ": " + ex.StackTrace)
End Try
End If
End If
End Function

Public Overloads Function ToString() As String
ToString = Buffer
End Function

Protected Overridable Overloads Sub Dispose( _
ByVal disposing As Boolean)
If Not Me.disposed Then
If disposing Then
' free managed resources
End If
'
' ONLY FOR DEBUGGING PURPOSES
' REMOVE FOR RELEASE VERSION
' System.Diagnostics.Trace.WriteLine("ANSIBSTR: free unmanaged buffer for " + Me.GetHashCode().ToString())

Try
Marshal.FreeHGlobal(_ptr)
Catch ex As Exception
'System.Diagnostics.Trace.WriteLine("ANSIBSTR: exception by release unmanaged memory " + _ptr.ToString() + " " + Me.GetHashCode().ToString())
End Try
' Note that this is not thread safe.
End If
Me.disposed = True
End Sub

#Region " IDisposable Support "
' Do not change or add Overridable to these methods.
' Put cleanup code in Dispose(ByVal disposing As Boolean).
Public Overloads Sub Dispose() Implements IDisposable.Dispose
Dispose(True)
GC.SuppressFinalize(Me)
End Sub
Protected Overrides Sub Finalize()
'
' ONLY FOR DEBUGGING PURPOSES
' REMOVE FOR RELEASE VERSION
' System.Diagnostics.Trace.WriteLine("ANSIBSTR: Finalizer for " + Buffer)

Dispose(False)
MyBase.Finalize()
End Sub
#End Region
End Class

Thursday, June 29, 2006

Underscore in URL and not saved cookies

Have a web site using cookies? Browse the site and wonder why the cookies are not saved?
http://support.microsoft.com/kb/275033/en-us is the answer.

Shortly: avoid using invalid characters like "_" (underscore) in hostname

http://my_host is bad, http://myhost is better.

Do not forget it! Enjoy!

Monday, June 26, 2006

Troubleshooting RMS Service setup and usage

Ever tried to setup Windows Rights Management Service "from scratch" ? Keep in mind to take care about following things - to avoid wasting time:

1. Install MSMQ on the box prior to setup RMS.
MSMQ is used for logging purposes - later setup of MSMQ has no effect. So be sure to have a WS2003 CD ready - some files might be copied to harddisk while setup MSMQ

2. Install SQL Server.
SQL Server stores RMS relevant data. RMS will setup SQL Express if no SQL detected on the machine.

3. Ensure Active Directory is available.
After setup you'll need to register RMS in active directory (except you plan to work with Passport based identification). Ensure RMS account has enough privileges to make required changes in AD.

4. Apply database update to prevent SqlException on rights assignement.
Consult http://support.microsoft.com/kb/913372 - KB article describing changes in database. Ensure you have enough privileges to apply them - these are changes in master database.

5. Ensure email addresses are set to users in AD.
Only users having email address set in AD are served by RMS service. Be aware of that.

6. Ensure privileges to search/browse AD.
RMS service account must have privilege to search in AD.

7. Ensure the GC for AD is visible.
Just start Active Directory Sites MMC and browse properties of NTDS: the GC checkbox must be checked.

Follow the advices - and you'll keep the adrenaline level lower trying to assign digital rights to your Office documents. Enjoy!

Tuesday, June 13, 2006

Unmarshal Double with VB.NET

One might be suprised howto unmarshal double values got to VB.NET over P/Invoke.
Well, Double is 64bit value, but there's no explicit ReadDouble(...) method in Marshal. So the first try may look like:

Dim myDbl as Double = Convert.ToDouble(Marshal.ReadInt64(myPtr,myOffset))

It won't work!

Mind the bits have exponential as well as mantissa parts. These aren't available in Int64 and are guessed by .NET as missing. So all the bits contained in Int64 read are used for conversion and bring not the expected result.

Sample: you get over P/Invoke a Double value 20060610.0 (for what purposes ever). Read with ReadInt64 you get 4716150189222526976 as Int64, that easily converted to 4.716150189222527E+18 as Double.

Workaround: do not forget to use BitConverter!

Dim myDbl as Double = BitConverter.Int64BitsToDouble( _
Marshal.ReadInt64(myPtr,myOffset))


Enjoy!

Wednesday, June 07, 2006

Start

Seen on the Mark's site www.sysinternals.com : Powered by Blogger.
Why not to start an own blog? Enjoy!