Visual C++ 6.0 on Windows 8 - visual-c++

Visual C++ 6.0 is not supported on Windows 8, but we have a couple of legacy apps that still needs to be compiled with Visual C++ 6.0. :-(
It is possible to install Visual C++ 6.0 on Windows 8 by unchecking Data Access -> Change Options -> ADO, RDS and OLE DB Providers. See this SU-question and this thread. You also need to install SP6 afterwards.
Visual C++ 6.0 works perfectly on one computer, but two others cannot use the debugger. The same hardware, same version of Windows, same person doing the installation, same project. There must be some difference...
On the computers with the problem you can set a break point and the debugger will break into the IDE, but when you try do step, step into or run the code will crash with Unhandled exception in EXENAME.EXE (OLE32.DLL): 0xC0000005: Access Violation.
Walter Oney reports the exact same problem on MSDN forums, but they have no solution as VC++ 6.0 is unsupported.
As we have Visual C++ 6.0 working on one Win8 computer there is apparently way to do it. Any ideas on what the difference could be?

Turning off OLE RPC debugging (Tools / Options / Debug) works for me (Windows 8 Pro 64 bit, Visual C++ 6.0 with SP6). This solution was suggested (later) within the above-mentioned MSDN forum thread.

I was eventually able to get VS 6 working on Win 8 and Win 10. The basic steps were these:
Create a dummy file named msjava.dll in \Windows. (E.g., "echo >msjava.dll") Without this step, the VS 6 installer can't get very far.
Install VS 6 and SP 6.
Rename MSDEV.EXE to something else, such as MSDEVQ.EXE.
Create a compatibility database for MSDEVQ that excludes the fault-tolerant heap shim. Without this step, debugging a program that makes heavy use of HeapAlloc, etc., is excruciatingly slow.
For debugging, ensure that a breakpoint is tripped before any calls to OLE32 can occur. I include the following header early in the main program or (for an MFC app) the InitInstance function:
X64DebugHack.h:
#ifdef _DEBUG
// In order to be able to debug this application on x64, we need to single
// step across at least one statement before ole32.dll gets loaded. So
// always leave this breakpoint in place.
requiredbreakpoint:
int junkola = 42;
// Check to see that there was a breakpoint...
PUCHAR pjunk;
_asm lea eax, requiredbreakpoint
_asm mov pjunk, eax
if (*pjunk != 0xCC)
AfxMessageBox("Required breakpoint was not set prior to loading OLE32.DLL -- single stepping will not be possible during this debugging session.", MB_OK | MB_ICONHAND, 0);
LoadLibrary("OLE32");
#endif
Write an extension DLL that provides a "Stop Debugging" button. The extension has to search and destroy debug handles, which have a different handle type in Win64 than in Win32. The mechanics of writing the extension are beyond the scope of this forum, but the code that does the actual work is here:
CCommands::HelpAssistantKill:
typedef LONG NTSTATUS;
#define NT_SUCCESS(Status) (((NTSTATUS)(Status)) >= 0)
#define STATUS_INFO_LENGTH_MISMATCH ((NTSTATUS)0xC0000004L)
enum SYSTEM_INFORMATION_CLASS {
SystemHandleInformation = 16,
};
typedef NTSTATUS(NTAPI *PNTQUERYSYSTEMINFORMATION)(SYSTEM_INFORMATION_CLASS, PVOID, ULONG, PULONG);
typedef struct _SYSTEM_HANDLE_INFORMATION {
ULONG ProcessId;
UCHAR ObjectTypeNumber;
UCHAR Flags;
USHORT Handle;
PVOID Object;
ACCESS_MASK GrantedAccess;
} SYSTEM_HANDLE_INFORMATION, *PSYSTEM_HANDLE_INFORMATION;
typedef struct _SYSTEM_HANDLE_INFORMATION_DATA {
ULONG HandleCount;
SYSTEM_HANDLE_INFORMATION HandleInformation[1];
} SYSTEM_HANDLE_INFORMATION_DATA, *PSYSTEM_HANDLE_INFORMATION_DATA;
#define HANDLE_TYPE_DEBUG_OBJECT 11 // correct value for Win8 x64
STDMETHODIMP CCommands::HelpAssistantKill()
{ // CCommands::HelpAssistantKill
AFX_MANAGE_STATE(AfxGetStaticModuleState());
BOOL didit = FALSE;
HMODULE hDll = NULL;
PSYSTEM_HANDLE_INFORMATION_DATA phi = NULL;
do { // do once
HRESULT hr;
// Locate NtQuerySystemInformation within NTDLL.DLL
hDll = LoadLibrary("NTDLL");
if (!hDll)
break;
PNTQUERYSYSTEMINFORMATION NtQuerySystemInformation = (PNTQUERYSYSTEMINFORMATION) GetProcAddress(hDll, "NtQuerySystemInformation");
if (!NtQuerySystemInformation)
break;
// Do an initial query to get the number of handles presently open in the system.
// This is a large number. The returned length value is meaningless for this query.
SYSTEM_HANDLE_INFORMATION_DATA hid;
DWORD junk;
NTSTATUS status = (*NtQuerySystemInformation)(SystemHandleInformation, &hid, sizeof(hid), &junk);
if (!NT_SUCCESS(status) && status != STATUS_INFO_LENGTH_MISMATCH)
break;
ULONG length = sizeof(SYSTEM_HANDLE_INFORMATION_DATA) + (hid.HandleCount - 1) * sizeof(SYSTEM_HANDLE_INFORMATION);
phi = (PSYSTEM_HANDLE_INFORMATION_DATA) new UCHAR[length];
if (!phi)
break;
// Get a list of all handles open in the system
status = (*NtQuerySystemInformation)(SystemHandleInformation, phi, length, &junk);
if (!NT_SUCCESS(status))
break;
// Find and close any debug objects that are open in this instance of Visual Studio.
DWORD pid = GetCurrentProcessId();
ULONG ihandle;
for (ihandle = 0; ihandle < hid.HandleCount; ++ihandle)
{ // for each open handle
PSYSTEM_HANDLE_INFORMATION p = phi->HandleInformation + ihandle;
if (p->ProcessId != pid || p->ObjectTypeNumber != HANDLE_TYPE_DEBUG_OBJECT)
continue;
if (CloseHandle((HANDLE) p->Handle))
didit = TRUE;
} // for each open handle
// Instruct DevStudio to stop
BSTR bsStopDebugging = SysAllocString(L"DebugStopDebugging");
if (!bsStopDebugging)
break;
hr = m_pApplication->ExecuteCommand(bsStopDebugging);
SysFreeString(bsStopDebugging);
if (hr != 0)
break;
} // do once
while (FALSE);
if (phi)
delete[] phi;
if (hDll)
FreeLibrary(hDll);
if (!didit)
{ // didn't do anything
MessageBox(NULL, "Unable to find and close any debug object handles", "HelpAssistant", MB_OK | MB_ICONINFORMATION);
} // didn't do anything
return S_OK;
} // CCommands::HelpAssistantKill
This felt like a pretty heroic effort, but I had about a million lines of code built on VS 6 that I had to keep working. Now that I've built myself a workable macro processor for VS 2015, I may undertake a conversion of this application.

One wrinkle -- I had the very same same issue with the Visual C++ 6.0 debugger on Windows 8.1 . But I could not find the RPC debug option under the Tools/Options/ Debug option described in the answer above. Instead I had to go into the registry editor and delete the RPC Debug key that is mentioned in the same MSDN thread referenced above (maybe it was there because I had already installed later versions of Microsoft Visual Studio before I had installed 6.0) . The debugger works great now, and thanks to previous posters!

The issue is due to incompatible “ADO, RDS and OLE DB Providers” comes along with the Visual C++ 6.0.
Please follow the below mentioned steps to disable ADO, RDS and OLE DB Providers and install the Visual C++ 6.0 –
1) Start the installation as usual.
2) Click on Custom installation when installer will ask for type of installation.
3) Click on Data Access from available items and then click on ‘Change Option’.
4) In new window de-select “ADO, RDS and OLE DB Providers” and click OK (ignore the warning).
5) Click on continue to proceed with the installation.
6) Installer will not freeze during ‘Updating components’ and will install successfully.
7) Now install the service pack ‘Vs6sp6’ and it will also install successfully.

Non of above answers work for me.
Solution from this site fix my problem.
Re-register ole32.dll file and check if it helps.
Click Start, type cmd in the Start search.
Right click on cmd and click on Run as administrator.
In the Command prompt, type the following commands and hit ENTER
after each command.
takeown /f ole32.dll
regsvr32 ole32.dll
Close the Command prompt after running the above two commands.
Try to run the application and check is the issue persists.

Related

Visual Studio 2017 C++ exception message box

I try to show an exception (or error code) in C++ with visual studio 2017 when a crash occurs.
For example, the following codes does not show any dialog(message box).
int* p = 0;
*p = 10;
or
throw std::exception("some error");
Thus, I cannot attach it with just in time debugger.
In fact, the second code shows a dialog but it is not what I want.
UPDATE
Windows 10 does not support the WER dialog any more. - link
(link is provided by Hans Passant)
Undefined.
You should also note:
If the given example is complete (no further use of p), an exception might occur, but in release mode the code may be optimized. In this case, there would be no message at all.

Visual Studio 2015 doesn't honour _Check_return_ or _Must_inspect_result_

I have a cross-platform build. On a *nix platform using GCC, I use the __attribute__((warn_unused_result)) to notify the consumer of my API if a return value is not checked. I assumed that _Check_return does the same thing on MSVC, but it doesn't appear to be working the way I expect.
The following code does not produce a warning as I expect. Warnings are set to /Wall.
_Check_return_ _Must_inspect_result_ int foo()
{
return 100;
}
int main()
{
foo();
return 0;
}
Code compiles without warnings. What am I doing wrong (or what should I be using to generate warnings for unchecked return codes)?
SAL annotations like _Check_return_ and _Must_inspect_result_ are only checked during code analysis builds (either by starting a code analysis build in the IDE or by building with the /analyze flag on the command line).
See "Understanding SAL" on MSDN for more information.

warning C4996: 'GetVersionExW': was declared deprecated

I am working on VS 2013 in Win 8.1.
How to solve this warning?
The basic question is "why are you calling GetVersionExW in the first place?" The answer to that question determines what you should do instead.
The deprecation warning is there to give developers a heads-up about the appcompat behavior change that started in Windows 8.1. See Windows and Windows Server compatibility cookbook: Windows 8, Windows 8.1, and Windows Server 2012. In short, that function doesn't return what you think it returns by default.
Historically, badly written OS version checks are the primary source of appcompat bugs for Windows OS upgrades. There've been a number of different approaches to trying to mitigate this problem (the AppVerifier version lie, the VerifyVersionInfo API, etc.), and this is the most aggressive to date.
The VersionHelpers.h mentioned in the comments are in the Windows 8.1 SDK that comes with Visual Studio 2013. They are not a new API; they are just utility code that makes use of the VerifyVersionInfo API introduced back in Windows 2000. These functions are for doing "You must be this high to ride this ride" style checks which are the class of version checks that are most often badly written. The code is pretty simple. For example, the IsWindowsVistaSP2OrGreater test is:
VERSIONHELPERAPI
IsWindowsVersionOrGreater(WORD wMajorVersion, WORD wMinorVersion, WORD wServicePackMajor)
{
OSVERSIONINFOEXW osvi = {};
osvi.dwOSVersionInfoSize = sizeof(osvi);
DWORDLONG const dwlConditionMask = VerSetConditionMask(
VerSetConditionMask(
VerSetConditionMask(
0, VER_MAJORVERSION, VER_GREATER_EQUAL),
VER_MINORVERSION, VER_GREATER_EQUAL),
VER_SERVICEPACKMAJOR, VER_GREATER_EQUAL);
osvi.dwMajorVersion = wMajorVersion;
osvi.dwMinorVersion = wMinorVersion;
osvi.wServicePackMajor = wServicePackMajor;
return VerifyVersionInfoW(&osvi, VER_MAJORVERSION | VER_MINORVERSION | VER_SERVICEPACKMAJOR, dwlConditionMask) != FALSE;
}
VERSIONHELPERAPI
IsWindowsVistaSP2OrGreater()
{
return IsWindowsVersionOrGreater(HIBYTE(_WIN32_WINNT_VISTA), LOBYTE(_WIN32_WINNT_VISTA), 2);
}
You don't need to use VersionHelpers.h as you could just do this kind of code yourself, but they are convenient if you are already using the VS 2013 compiler. For games, I have an article What's in a version number? which uses VerifyVersionInfo to do the kind of reasonable checks one should for game deployment.
Note if you are using VS 2013 with the v120_xp platform toolset to target Windows XP, you'll actually be using the Windows 7.1A SDK and #include <VersionHelpers.h> won't work. You can of course use VerifyVersionInfo directly.
The other major use of GetVersionExW is diagnostic logs and telemetry. In this case, one option is to continue to use that API and make sure you have the right manifest entries in your application to ensure reasonably accurate results. See Manifest Madness for details on what you do here to achieve this. The main thing to keep in mind is that unless you routinely update your code, you will eventually stop getting fully accurate information in a future version of the OS.
Note that it is recommended you put the <compatibility> section in an embedded manifest whether or not you care about the results of GetVersionEx as general best practice. This allows the OS to automatically apply future appcompat fixes based on knowing how the app was originally tested.
For diagnostic logs, another approach that might be a bit more robust is to grab the version number out of a system DLL like kernel32.dll using GetFileVersionInfoW. This approach has a major caveat: Do not try parsing, doing comparisons, or making code assumptions based on the file version you obtain this way; just write it out somewhere. Otherwise you risk recreating the same bad OS version check problem that is better solved with VerifyVersionInfo. This option is not available to Windows Store apps, Windows phone apps, etc. but should work for Win32 desktop apps.
#include <Windows.h>
#include <cstdint>
#include <memory>
#pragma comment(lib, "version.lib" )
bool GetOSVersionString( WCHAR* version, size_t maxlen )
{
WCHAR path[ _MAX_PATH ] = {};
if ( !GetSystemDirectoryW( path, _MAX_PATH ) )
return false;
wcscat_s( path, L"\\kernel32.dll" );
//
// Based on example code from this article
// http://support.microsoft.com/kb/167597
//
DWORD handle;
#if (_WIN32_WINNT >= _WIN32_WINNT_VISTA)
DWORD len = GetFileVersionInfoSizeExW( FILE_VER_GET_NEUTRAL, path, &handle );
#else
DWORD len = GetFileVersionInfoSizeW( path, &handle );
#endif
if ( !len )
return false;
std::unique_ptr<uint8_t> buff( new (std::nothrow) uint8_t[ len ] );
if ( !buff )
return false;
#if (_WIN32_WINNT >= _WIN32_WINNT_VISTA)
if ( !GetFileVersionInfoExW( FILE_VER_GET_NEUTRAL, path, 0, len, buff.get() ) )
#else
if ( !GetFileVersionInfoW( path, 0, len, buff.get() ) )
#endif
return false;
VS_FIXEDFILEINFO *vInfo = nullptr;
UINT infoSize;
if ( !VerQueryValueW( buff.get(), L"\\", reinterpret_cast<LPVOID*>( &vInfo ), &infoSize ) )
return false;
if ( !infoSize )
return false;
swprintf_s( version, maxlen, L"%u.%u.%u.%u",
HIWORD( vInfo->dwFileVersionMS ),
LOWORD(vInfo->dwFileVersionMS),
HIWORD(vInfo->dwFileVersionLS),
LOWORD(vInfo->dwFileVersionLS) );
return true;
}
If there is some other reason you are calling GetVersionExW, you probably shouldn't be calling it. Checking for a component that might be missing shouldn't be tied to a version check. For example, if your application requires Media Foundation, you should set a "You must be this high to ride this ride check" like the VersionHelpers.h IsWindowsVistaOrGreater for deployment, but at runtime you should use explicit linking via LoadLibrary or LoadLibaryEx to report an error or use a fallback if MFPLAT.DLL is not found.
Explicit linking is not an option for Windows Store apps. Windows 8.x solves this
particular problem by having a stub MFPLAT.DLL and MFStartUp will return E_NOTIMPL.
See "Who moved my [Windows Media] Cheese"?
Another example: if your application wants to use Direct3D 11.2 if it is available and otherwise uses DirectX 11.0, you'd use set a IsWindowsVistaSP2OrGreater minimum bar for deployment perhaps using the D3D11InstallHelper. Then at runtime, you'd create the DirectX 11.0 device and if it fails, you'd report an error. If you obtain a ID3D11Device, then you'd QueryInterface for a ID3D11Device2 which if it succeeds means you are using an OS that supports DirectX 11.2. See Anatomy of Direct3D 11 Create Device.
If this hypothetical Direct3D application supports Windows XP, you'd use a deployment bar of IsWindowsXPSP2OrGreater or IsWindowsXPSP3OrGreater, and then at run time use explicit linking to try to find the D3D11.DLL. If it wasn't present, you'd fall back to using Direct3D 9--since we set the minimum bar, we know that DirectX 9.0c or later is always present.
They key point here is that in most cases, you should not use GetVersionEx.
Note that with Windows 10, VerifyVersionInfo and getting the file version stamp via GetFileVersionInfo for kernel32.lib are now subject to the same manifest based behavior as GetVersionEx (i.e. without the manifest GUID for Windows 10, it returns results as if the OS version were 6.2 rather than 10.0).
For universal Windows apps on Windows 10, you can a new WinRT API AnalyticsInfo to get a version stamp string for diagnostic logs and telemetry.
you can disable this warning and use GetVersionEx anyway by adding:
#pragma warning(disable : 4996)
While GetVersionEx was declared deprecated, if you toss in a proper compatibility manifest declaring compatibility with Windows 8.1 and Windows 10, GetVersionEx will return the correct version number. I use GetVersionEx to detect Windows 8 or greater, and because Windows 8 is the last version of Windows to not require a manifest to return the proper Windows version, my code works fine regardless of whether the API returns Windows 6.2, 6.3, 6.4 (for early Windows 10 previews), or 10.0.
With all that said, Microsoft deprecated this API in part due to bad usage of it. Take for instance this attempt to detect Windows XP or greater:
BOOL IsXPOrGreater;
OSVERSIONINFO osver;
osver.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
GetVersionEx(&osver);
if((osver.dwMajorVersion >= 5) && (osver.dwMinorVersion >=1) IsXPOrGreater = TRUE;
else IsXPOrGreater = FALSE;
This sample would return TRUE on Windows XP, Server 2003, 7, 8, and 8.1 but would return FALSE on Windows Vista or 10. Adding one line would fix this:
BOOL IsXPOrGreater;
OSVERSIONINFO osver;
osver.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
GetVersionEx(&osver);
if((osver.dwMajorVersion >= 5) && (osver.dwMinorVersion >=1) IsXPOrGreater = TRUE;
else if(osver.dwMajorVersion >= 6) IsXPOrGreater = TRUE;
else IsXPOrGreater = FALSE;
This sample would function correctly because it knows that if the major version is 6 or greater than it is greater than XP.
if you look at sysinfoapi.h you will find the following
NOT_BUILD_WINDOWS_DEPRECATE
WINBASEAPI
__drv_preferredFunction("IsWindows*", "Deprecated. Use VerifyVersionInfo* or IsWindows* macros from VersionHelpers.")
BOOL
WINAPI
GetVersionExW(
_Inout_ LPOSVERSIONINFOW lpVersionInformation
);
#ifdef UNICODE
#define GetVersionEx GetVersionExW
#else
#define GetVersionEx GetVersionExA
#endif // !UNICODE
if you track the NOT_BUILD_WINDOWS_DEPRECATE in the same header file you will find
#if defined(FKG_FORCED_USAGE) || defined(WINPHONE) || defined(BUILD_WINDOWS)
# define NOT_BUILD_WINDOWS_DEPRECATE
#else
# define NOT_BUILD_WINDOWS_DEPRECATE __declspec(deprecated)
#endif
the above code mean in simple words if you define one of the following
BUILD_WINDOWS or WINPHONE or FKG_FORCED_USAGE it will not show the deprecated error
so in your code you could do thing like this :
#define BUILD_WINDOWS before #include <windows.h>
and that should solve it for you.

MFC CRecordset heap corruption detected at Close()

I recently upgraded my operating system from Windows XP to Windows 7 SP1 64 bit. We are using Visual Studio 2008 Professional Edition and Oracle Database 11g Enterprise Edition Release 11.2.0.2.0 - 64bit Production.
When I try to execute this code I am getting the below exceptions
try
{
CDatabase *pDatabase = CDatabaseConnection::getDatabaseConnectionProcessLog();
ORSProcessLog rsProcessLog(pDatabase);
CString strFilter = _T("SELECT PROCESS_ID, MESSAGE FROM OP_PROCESS_LOG");
rsProcessLog.SetRowsetSize(1);
if( !rsProcessLog.Open(CRecordset::dynaset, strFilter, CRecordset::appendOnly) )
return;
if( !rsProcessLog.CanAppend() )
return;
rsProcessLog.AddNew();
rsProcessLog.m_PROCESS_ID = gcsProcessID;
rsProcessLog.m_MESSAGE = csMessageA;
rsProcessLog.Update();
rsProcessLog.Close();
}
catch ( CDBException* pEx )
{
bException = true;
pEx->GetErrorMessage(szCause, 255);
}
catch( CException* pEx )
{
bException = true;
pEx->GetErrorMessage(szCause, 255);
}
where rsProcessLog is the CRecordset object using a successfully connected database pointer pDatabase
In 32- bit Debug version I get a message box at rsProcessLog.Close(); with the below text
Debug Error
Program: ......\Test.exe
HEAP CORRUPTION DETECTED: after Normal block (#506) at 0x0087F628. CRT detected that the application wrote to memory after end of heap buffer.
Memory allocated at f:\dd\vctools\vc7libs\ship\atlmfc\src\mfc\dbcore.cpp(2626)
(Please Retry to debug the application)
In 32- bit Release version I get a message box at rsProcessLog.Close(); with the below text
Windows has triggered a breakpoint in Test.exe
This may be due to a corruption of the heap, which indicates a bug in Test.exe or any of the DLLS it has loaded.
This may also be due to the user pressing F12 while Test.exe has focus.
The output window may have more diagnostic information.
The above code was a working code in Windows XP with the rest of the env remaining the same and it continues to run in Windows XP but not in Windows 7. Any help will be greatly appreciated.
After some analysis of MFC CRecordest class I noticed that the problem appears after call to ::SqlSetPos where m_rgRowStatus array allocated on the heap become damaged (one byte more is written on the heap).
First and clean approach to problem is to force CRecordset class to use update/delete SQL statements instead of ::SqlSetPos function. To achive this you need to open your database using OpenEx method with CDatabase::userCursorLib option.
CDatabase db;
db.OpenEx(ConnectionString, CDatabase:useCursorLib);
This will change some CRecordset functionalities. See more at: http://msdn.microsoft.com/en-us/library/c689y99f.aspx
Second approach (dirty) is to reallocate m_rgRowStatus field, to use more memory on the heap, so call to ::SqlSetPos will not write to unallocated memory.
One way to do that is to override CRecordset::PreBindFields function:
void CMyDerivedRecordset::PreBindFields()
{
if ( ! (m_dwOptions & useMultiRowFetch) )
{
delete [] m_rgRowStatus;
m_rgRowStatus = new WORD[2];
}
CRecordset::PreBindFields();
}
You can do that in all of your CRecordset derived classes, or you can make one new CRecordset derived class which will become base class for all of your existing CRecordsetderived classes.

VC++ 6.0: Why is CASyncSocket::GetLastError() causing an access violation?

I'm using Visual C++ 6.0. I'm not sure of the service pack level of the visual studio installation, but the OS is Win 2K SP4. The failing code is part of a DLL.
Here's the code:
EIO::OpenConnection()
{
m_Client = new CSocket();
if(m_Client->Create() == 0) {
delete m_Client;
m_Client = NULL;
return CAsyncSocket::GetLastError();
}
if (!m_Client->Connect((LPCTSTR)m_IPAddress, 7)) {
delete m_Client;
m_Client = NULL;
return CAsyncSocket::GetLastError();
}
...<stuff>...
}
This compiles without error on my build system and executes without either of the calls to m_Client methods failing. When I move this DLL to the production system (Win 2K, not sure of service pack level yet), the call to m_Client->Connect() returns an error, so it goes into the IF block. CAsyncSocket::GetLastError() then the debugger to open and report an 0xC0000005 access violation. I don't understand this stuff enough to get anything out of the disassembly.
I've also tried CSocket::GetLastError() and m_Client->GetLastError() with the same results.
I'm fairly certain that m_Client->Connect() fails because of some security policy that's on the production machine that's absent on the development system, but I'd like to get the actual error code so I can help the IT guy narrow his search.
I haven't yet tried forcing a call to GetLastError() on my build system to see if I get an access violation there.
The GetLastError() method most likely calls WSAGetLastError().
But for WSAGetLastError() to work, WSACleanup() must not have been called yet.
I'm guessing that when you delete m_Client that exactly this happens.
Try calling GetLastError() before you delete the m_Client object.

Resources