What happen with MFC CString in " CStringA csA = CStringW("hello", 5);" - visual-c++

It does compiled. But I do not think it should. It compile both in VS2008 and VS2013.
I Add a picture to show it does compile. but I am really confused at this. The picture is VS2013.

Why shouldn't it compile? There's explicit code in CString to handle exactly such unicode-to-ascii conversions:
CStringT& operator=(_In_opt_z_ PCYSTR pszSrc)
{
...
PXSTR pszBuffer = GetBuffer( nDestLength );
StringTraits::ConvertToBaseType( pszBuffer, nDestLength, pszSrc);
...
}
and internally (note the explicit LPSTR and LPCWSTR in the signature):
static void __cdecl ConvertToBaseType(
_Out_writes_(nDestLength) LPSTR pszDest,
_In_ int nDestLength,
_In_ LPCWSTR pszSrc,
_In_ int nSrcLength = -1) throw()
{
// nLen is in XCHARs
::WideCharToMultiByte( _AtlGetConversionACP(), 0, pszSrc, nSrcLength, pszDest, nDestLength, NULL, NULL );
}
You can step into it from the debugger.

Related

Can't suppress MSVC assertion failure dialog

I've tried this SO answer: How can I disable the debug assertion dialog on Windows?.
Still, no luck.
The code I'm using:
#include <Windows.h>
#include <crtdbg.h>
#include <cassert>
int test(int reportType, char* message, int* returnValue)
{
return 0;
}
int APIENTRY wWinMain(_In_ HINSTANCE hInstance,
_In_opt_ HINSTANCE hPrevInstance,
_In_ LPWSTR lpCmdLine,
_In_ int nCmdShow)
{
_CrtSetReportHook(&test);
_CrtSetReportMode(_CRT_ASSERT, _CRTDBG_MODE_FILE | _CRTDBG_MODE_DEBUG);
_CrtSetReportFile(_CRT_ASSERT, _CRTDBG_FILE_STDERR);
_CrtSetReportMode(_CRT_ERROR, _CRTDBG_MODE_FILE | _CRTDBG_MODE_DEBUG);
_CrtSetReportFile(_CRT_ERROR, _CRTDBG_FILE_STDERR);
//_ASSERT(0); // works as expected: no dialog appears
assert(0); // The dialog appears
return 0;
}
Maybe, there is something wrong with my system's config?
assert documentation notes _set_error_mode should be used:
To override the default output behavior regardless of the app type, call _set_error_mode to select between the output-to-stderr and display-dialog-box behavior.
From their example:
_set_error_mode(_OUT_TO_STDERR);
assert(2+2==5);

error C2440: 'return' : cannot convert from 'char *const ' to 'LPCTSTR'

struct StaticString
{
StaticString() { Str = NULL; }
~StaticString() { if(Str) delete [] Str; Str=0; }
char* Str;
void operator = (const char * pchar)
{
Str = new char[strlen(pchar)+1];
strcpy(Str,pchar);
}
operator LPCTSTR() const
{
return Str;
}
operator PCHAR() const
{
return Str;
}
};
error C2440: 'return' : cannot convert from 'char *const ' to 'LPCTSTR'
Its from game . and how can i fix that? i search in google but no one work
LPCTSTR is "long pointer to constant TCHAR string".
The TCHAR type is ancient. It dates back to the original transition from "ANSI" to "wide-character" Unicode with Windows 98/NT.
#ifdef _UNICODE
typedef wchar_t TCHAR;
#else
typedef char TCHAR;
#endif
Most projects these days default to _UNICODE which means TCHAR is not a char but is instead wchar_t.
See What are TCHAR, WCHAR, LPSTR, LPWSTR, LPCTSTR (etc.)?
Generally you should avoid using these Windows portable types and stick with C++ standard types.

C++ to C# char[]

C# code:
class Hello{
public void helloWorld(char[] chars){
//do something
}
}
C++ code to call C#:
MyCSDLL::Hello* hello;
//init hello, some calls are ok.
char* myCharPtr;
//init with message
HRESULT result = hello->helloWorld(safeArray, (MyCSDLL::_MyRetVal) _retValPtr);
Adapting from How to create and initialize SAFEARRAY of doubles in C++ to pass to C#
void createSafeArray(SAFEARRAY** saData, char* charPtr)
{
char* iterator = charPtr;
SAFEARRAYBOUND Bound;
Bound.lLbound = 0;
Bound.cElements = 10;
*saData = SafeArrayCreate(VT_R8, 1, &Bound);
char HUGEP *pdFreq;
HRESULT hr = SafeArrayAccessData(*saData, (void HUGEP* FAR*)&pdFreq);
if (SUCCEEDED(hr))
{
do {
*pdFreq++ = *iterator;
} while (*iterator++);
}
}
How to call hello->helloWorld()? it is expecting SAFEARRAY*. The current code gives 80131538 error. How to fix it?
C++ Project is not CLR.
Let's suppose the C# code is this:
namespace ClassLibrary1
{
[ComVisible(true)]
[ClassInterface(ClassInterfaceType.AutoDual)]
public class Hello
{
public void helloWorld(char[] chars)
{
...
}
}
}
Then, you can call it with this C/C++ code, for example:
#import "C:\mycode\ClassLibrary1\bin\Debug\classlibrary1.tlb" raw_interfaces_only
using namespace ClassLibrary1;
HRESULT CallHello(wchar_t* charPtr, int count)
{
CComPtr<_Hello> p;
HRESULT hr = p.CoCreateInstance(__uuidof(Hello));
if (FAILED(hr))
return hr;
SAFEARRAY* psa = SafeArrayCreateVector(VT_UI2, 0, count);
if (!psa)
return E_OUTOFMEMORY;
LPVOID pdata;
hr = SafeArrayAccessData(psa, &pdata);
if (SUCCEEDED(hr))
{
CopyMemory(pdata, charPtr, count * 2); // count is the number of chars
SafeArrayUnaccessData(psa);
hr = p->helloWorld(psa);
}
SafeArrayDestroy(psa);
return hr;
}
.NET's char type is unicode, so the binary size is two bytes, the C equivalent is wchar_t (or unsigned short, etc...). So the safearray element type must match that, that's why I used VT_UI2 (VT_R8 that you used is Real of size 8 bytes, so it's equivalent to .NET's double type).
If you really want to use C's char, then you must do some kind of conversion to a 2-byte character.
Also, you can use the SafeArrayCreateVector function which directly allocates a 1-dimension safe array. Don't forget to call cleanup methods.

how to convert a msvc exe project to a dll project?

in the exe project:
int WINAPI WinMain( __in HINSTANCE hInstance, __in_opt HINSTANCE hPrevInstance, __in_opt LPSTR lpCmdLine, __in int nShowCmd )
{
g_hMainWnd=CreateDialog(hInstance,MAKEINTRESOURCE(IDD_DIALOG1),NULL,(DLGPROC)DialogProc);
RECT rcWnd;
GetWindowRect(g_hMainWnd,&rcWnd);
int X=(GetSystemMetrics(SM_CXSCREEN)-rcWnd.right+rcWnd.left)>>1,
Y=(GetSystemMetrics(SM_CYSCREEN)-rcWnd.bottom+rcWnd.top)>>1;
MoveWindow(g_hMainWnd,X,Y,rcWnd.right-rcWnd.left,rcWnd.bottom-rcWnd.top,FALSE);
ShowWindow(g_hMainWnd,SW_SHOW);
BOOL bRet;
MSG msg;
while( (bRet = GetMessage( &msg, NULL, 0, 0 )) != 0)
{
if (bRet == -1)
{
MessageBox(NULL,_T("GetMessage error with -1 returned!"),_T("error"),MB_ICONHAND);
break;
}
else if (!IsWindow(g_hMainWnd) || !IsDialogMessage(g_hMainWnd, &msg))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
return 0;
}
I changed the project setting to output a dll firstly.
Then I changed the WinMain to:
BOOL APIENTRY DllMain( __in HINSTANCE hInstance, __in_opt HINSTANCE hPrevInstance, __in_opt LPSTR lpCmdLine, __in int nShowCmd )
{
g_hMainWnd=CreateDialog(hInstance,MAKEINTRESOURCE(IDD_DIALOG1),NULL,(DLGPROC)DialogProc);
HWND hMainWnd;
//DialogProc involves the critical initialization of the data required for the export function used later
return 0;
}
So, if it is a foolish idea, or have I missed something?
Thank you all!
BOOL WINAPI DllMain(
HINSTANCE hinstDLL, // handle to DLL module
DWORD fdwReason, // reason for calling function
LPVOID lpReserved ) // reserved
{
// Perform actions based on the reason for calling.
switch( fdwReason )
{
case DLL_PROCESS_ATTACH:
// Initialize once for each new process.
// Return FALSE to fail DLL load.
break;
case DLL_THREAD_ATTACH:
// Do thread-specific initialization.
break;
case DLL_THREAD_DETACH:
// Do thread-specific cleanup.
break;
case DLL_PROCESS_DETACH:
// Perform any necessary cleanup.
break;
}
return TRUE; // Successful DLL_PROCESS_ATTACH.
}
For more informations: Dll entry point
The definition of DllMain is to be used by the operating system, and on a few occasions you must enter their codes. To execute the code that implements your EXE, you must create a public routine that receives the required parameters.
Use Visual Studio do create one library project to export some data and functions.
New Project-> Select Viasual c++ -> Select Win32 -> Win32 Project -> Name your project -> Next -> Select DLL -> Select Export symbols -> finish
The final project will contain a variable being exported and a public routine. Use as a template in your code.

Move constructor (rvalue reference) in implicit conversion

I am upgrading a C++ project from MSVC 2008 to 2010, and because of the new CComBSTR move constructor [CComBSTR( CComBSTR&& )], I am getting a compiler error because of an ambiguous call.
Essentially, we have a String class, very similar to std::wstring that have a cast operator to CComBSTR. This is similator to the following code:
class CString {
public:
// ...
operator CComBSTR() {
CComBSTR temp;
/* Encoding conversion here */
return temp;
}
}
class CObjectConfig {
public:
CString GetName() const { return m_name; }
private:
CString m_name;
}
Now, at some places in the code, we do the following:
CObjectConfig config = GetObjectConfig();
CComBSTR objectName( config.GetName() );
In VS2008, this would work because the CString object would be implicitly converted to a CComBSTR rvalue and the copy constructor of CComBSTR (taking a const CComBSTR&) would be called to construct objectName.
In VS2010 with C++0x however, the compiler gives an ambiguous call error because CComBSTR rvalue seems to fit both the copy constructor and the move constructor.
While a bit clumsy, my solution to this problem is to static_cast the call to GetName:
CComBSTR objectName( static_cast<const CComBSTR&>( config.GetName() ) );
// or
CComBSTR objectName( static_cast<CComBSTR&&>( config.GetName() ) );
Both lines compile without error, but I need your advice on whether this is illegal, bad practice or undefined. Thank you.
This looks like a VC2010 bug to me. Either that, or I've incorrectly emulated your situation on my computer (I don't have VC2010). Here's what I'm doing:
#include <iostream>
class CComBSTR
{
public:
CComBSTR() {std::cout << "CComBSTR()\n";}
CComBSTR(const CComBSTR&) {std::cout << "CComBSTR(const CComBSTR&)\n";}
CComBSTR(CComBSTR&&) {std::cout << "CComBSTR(CComBSTR&&)\n";}
};
class CString {
public:
// ...
operator CComBSTR() {
CComBSTR temp;
/* Encoding conversion here */
return temp;
}
};
class CObjectConfig {
public:
CString GetName() const { return m_name; }
private:
CString m_name;
};
CObjectConfig GetObjectConfig()
{
return CObjectConfig();
}
int main()
{
CObjectConfig config = GetObjectConfig();
CComBSTR objectName( config.GetName() );
}
For me on g++-4.4 and clang (with -std=c++0x), this compiles fine. And it either calls or elides a call to CComBSTR(CComBSTR&&). My recommendation for working around this suspected bug is simply:
CComBSTR objectName( CComBSTR(config.GetName()) );
This is equivalent to your:
CComBSTR objectName( static_cast<CComBSTR&&>( config.GetName() ) );
but not as scary looking (and just as efficient). If you want to stay with the static_cast, then go with cast to CComBSTR&& as this will probably be more efficient than construction from a const lvalue.

Resources