In bellow function I need to dereference shared pointer to an array of TCHAR
however none of the operands available in std::share_ptr seem to work:
The FormatMessage API expects PTSTR which is in case of UNICODE wchar_t*
How to dereference the given pointer (see comment in the code)?
If you think the same thing could be achieved with more elegant sintax that it would be great you provide example code.
const std::shared_ptr<TCHAR[]> FormatErrorMessage(const DWORD& error_code)
{
constexpr short buffer_size = 512;
std::shared_ptr<TCHAR[]> message = std::make_shared<TCHAR[]>(buffer_size);
const DWORD dwChars = FormatMessage(
FORMAT_MESSAGE_FROM_SYSTEM,
nullptr,
error_code,
MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US),
*message, // no operator "*" matches these operands
buffer_size,
nullptr);
return message;
}
EDIT
Thanks to answers and commnts (the only) way to make it work with Microsoft compiler is this:
const std::shared_ptr<std::array<WCHAR, buffer_size>>
FormatErrorMessageW(const DWORD& error_code, DWORD& dwChars)
{
const std::shared_ptr<std::array<WCHAR, buffer_size>> message =
std::make_shared<std::array<WCHAR, buffer_size>>();
dwChars = FormatMessageW(
FORMAT_MESSAGE_FROM_SYSTEM,
nullptr, // The location of the message definition.
error_code,
MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US),
message.get()->data(),
buffer_size,
nullptr);
return message;
}
*message returns TCHAR&, whereas FormatMessage requires TCHAR* there. Instead of *message do message.get().
Also, since this function doesn't keep a reference to the formatted message, it should return std::unique_ptr<TCHAR[]> to document the fact that the caller is now the sole owner.
Related
I need to use WinAPI function to restart a windows service, I am not familiar with strings in C++.
My function receive as parameter: const CStringA& serviceName:
bool MyClassName::RestartServer(const CStringA& serviceName)
When I obtain SC Handle via OpenService(..) I need to provide type LPCWSTR :
SC_HANDLE SHandle = OpenService(hSCManager, LPCWSTR serviceNameAsWideString, SC_MANAGER_ALL_ACCESS);
How do I convert CStringA to LPCWSTR?
I tried to following:
CA2W(serviceName, CP_UTF8);
CString str("MyServiceName"); CStringW strw(str); LPCWSTR ptr = strw;
Both did not work properly, they compiled, but when I tried to execute the code.
It failed to OpenService().
What worked:
LPCWSTR newString = serviceName.AllocSysString();
What am I missing here? Why 1 and 2 did not work? Why 3 worked?
How do I properly deallocate newString?
Your code requires a conversion because you are calling the TCHAR-based OpenService() macro, which maps to either OpenServiceW() or OpenServiceA() depending on whether UNICODE is defined:
__checkReturn
WINADVAPI
SC_HANDLE
WINAPI
OpenServiceA(
__in SC_HANDLE hSCManager,
__in LPCSTR lpServiceName,
__in DWORD dwDesiredAccess
);
__checkReturn
WINADVAPI
SC_HANDLE
WINAPI
OpenServiceW(
__in SC_HANDLE hSCManager,
__in LPCWSTR lpServiceName,
__in DWORD dwDesiredAccess
);
#ifdef UNICODE
#define OpenService OpenServiceW
#else
#define OpenService OpenServiceA
#endif // !UNICODE
In your case, UNICODE is clearly being defined in your project, so your code is really calling OpenServiceW(), which is why it expects an LPCWSTR as input.
Your RestartServer() method takes a CStringA (char-based ANSI) string as input, so you should use OpenServiceA() explicitly to match the same character type, no conversion needed:
bool MyClassName::RestartServer(const CStringA& serviceName)
{
...
SC_HANDLE SHandle = OpenServiceA(hSCManager, serviceName, SC_MANAGER_ALL_ACCESS);
...
}
Otherwise, if you are going to continue using TCHAR-based functionality in your code 1, then you should change your RestartServer() method to take a CString instead of a CStringA so it adopts the same ANSI/Unicode mapping that OpenService() does (and other TCHAR-based functions do), again avoiding a conversion:
1: which you should not do, since there is rarely a need to ever write code for Win9x/ME nowadays. Windows has been a Unicode-based OS since NT4.
bool MyClassName::RestartServer(const CString& serviceName)
If that is not an option for you, then CA2W() will work just fine:
bool MyClassName::RestartServer(const CStringA& serviceName)
{
USES_CONVERSION;
...
SC_HANDLE SHandle = OpenService(hSCManager, ATL::CA2W(serviceName), SC_MANAGER_ALL_ACCESS);
...
}
Though, you might consider just using CString internally and let it handle a conversion if needed:
bool MyClassName::RestartServer(const CStringA& serviceName)
{
...
SC_HANDLE SHandle = OpenService(hSCManager, CString(serviceName), SC_MANAGER_ALL_ACCESS);
...
}
Or, make the code conditional:
bool MyClassName::RestartServer(const CStringA& serviceName)
{
...
SC_HANDLE SHandle = OpenService(hSCManager,
#ifdef UNICODE
CStringW(serviceName)
#else
serviceName
#endif
, SC_MANAGER_ALL_ACCESS);
...
}
CStringA and CStringW have constructors taking both const char* and const wchar_t* C strings.
Write following:
CStringW serviceNameW( serviceName );
About AllocSysString, it creates a copy in BSTR, they’re more complex than C strings, they’re null-terminated too but they also have length at negative offset. If you want to do manual memory management, call SysFreeString on the pointer. Or if you want BSTR but don’t want manual memory management, use CComBSTR class.
I'm creating a dll file.
My code:
BOOL CALLBACK EnumWindowsProc(HWND hwnd, LPARAM lParam);
void test() {
EnumWindows(EnumWindowsProc, NULL);
}
BOOL CALLBACK EnumWindowsProc(HWND hwnd, LPARAM lParam)
{
char class_name[80];
char title[80];
GetClassName(hwnd, (LPWSTR) class_name, sizeof(class_name));
GetWindowText(hwnd, (LPWSTR) title,sizeof(title));
std::string titlas(title);
std::string classas(class_name);
Loggerc(titlas);
Loggerc("Gooing");
return TRUE;
}
Then I just call test().
In the log, titlas is empty and code stops.
When I try this code in a Win32 app with CodeBlock, everything works, all of the titles show. But in a dll, it does not work.
Where is the problem?
char class_name[80];
char title[80];
GetClassName(hwnd, (LPWSTR) class_name, sizeof(class_name));
GetWindowText(hwnd, (LPWSTR) title,sizeof(title));
std::string titlas(title);
std::string classas(class_name);
Considering that since VS2005 the default has been building in Unicode mode (instead of ANSI/MBCS) and that you have those (ugly C-style) (LPWSTR) casts, I'm assuming that you got compile-time errors when passing your char-based string buffers to APIs like GetClassName() and GetWindowText(), and you tried to fix those errors with casts.
That's wrong. The compiler was actually helping you with those errors, so please follow its advice instead of casting the compiler errors away.
Assuming Unicode builds, you may want to use wchar_t and std::wstring instead of char and std::string, and _countof() instead of sizeof() to get the size of buffers in wchar_ts, not in bytes (chars).
E.g.:
// Note: wchar_t used instead of char
wchar_t class_name[80];
wchar_t title[80];
// Note: no need to cast to LPWSTR (i.e. wchar_t*)
GetClassName(hwnd, class_name, _countof(class_name));
GetWindowText(hwnd, title, _countof(title));
// Note: std::wstring used instead of std::string
std::wstring titlas(title);
std::wstring classas(class_name);
If other parts of your code do use std::string, you may want to convert from UTF-16-encoded text stored in std::wstring (returned by Windows APIs) to UTF-8-encoded text and store it in std::string instances.
I have a Win32 C++ dll (A) that calls another Win32 C++ dll (B). (B) is loaded using LoadLibrary and contains a method:
Draw(HDC hDC, LPRECT lpRect, LPBUFFER buffer, LPOPTIONS options)
Buffer structure is defined as:
struct Buffer
{
char* pData;
long Length;
TCHAR FileName[MAX_PATH];
Extension Extension;
};
typedef Buffer BUFFER, *LPBUFFER;
(A) fills BUFFER with filename, length etc and calls the Draw function. The Draw function then uses the values from BUFFER. It all works fine when DLLs are compiled as 64-bit but if I compile them as 32-bit then I start getting garbage values in BUFFER fields in (B). Logs shows that the values are good in (A) but turn into garbage when they reach (B).
I tried changing the Structure Alignment Option /ZpX and calling convention for Draw method (__cdecl, __stdcall) but none helped. I think it is related to calling convention because if I change Draw function syntax and put BUFFER as first param then (B) gets correct values. What's going on here?
Function pointer type:
typedef bool (__cdecl *DrawFunc)(HDC hDC, LPRECT lpRect, LPBUFFER buffer, LPOPTIONS options);
Then in InitInstance:
pDrawFunc = (DrawFunc)GetProcAddress(dllHandle, "Draw");
UPDATE
1. As mentioned above, if I put BUFFER as first param then it receives correct values.
2. HDC being a single numeric value always receives correct value
3. RECT gets incorrect values, very large ones
I believe the problem has something to do with structs. Only structs get incorrect values.
UPDATE 2
OK I found out my own silly mistake, the declaration for Draw method had LPRECT whereas the implementation had RECT. My bad, sorry about that.
But I am still not sure why:
1. Other parameters were showing garbage values?
2. Why it worked in 64-bit?
Ok, I create a solution with 3 projects: library B, that contains Draw(), library A, that has Test(), that loads library B and call Draw() with some Buffer* and application test, that links with library A and calls Test(). Everything works fine, both for 32 bit and 64. Small snippet of Test():
#include "stdafx.h"
#include "A.h"
#include "../B/B.h"
namespace {
LPBUFFER CreateBuffer(const char* const data, LPCTSTR const name)
{
if(!data || !name)
return NULL;
LPBUFFER buffer = new BUFFER();
buffer->Length = static_cast<long>(strlen(data) + 1);
buffer->pData = new char[buffer->Length];
strcpy_s(buffer->pData, buffer->Length * sizeof(char), data);
buffer->Extension = 0;
::ZeroMemory(buffer->FileName, _countof(buffer->FileName) * sizeof(TCHAR));
_tcscpy_s(buffer->FileName, name);
return buffer;
}
void DestroyBuffer(LPBUFFER buffer)
{
delete [] buffer->pData;
buffer->Length = 0;
buffer->pData = NULL;
buffer->Extension = 0;
::ZeroMemory(buffer->FileName, _countof(buffer->FileName) * sizeof(TCHAR));
delete buffer;
}
} // namespace
A_API void Test()
{
HMODULE b_lib = ::LoadLibrary(_T("B.dll"));
if(!b_lib)
{
::OutputDebugString(_T("Can't load library\n"));
return;
}
typedef bool (*DrawFunction)(HDC hDC, LPRECT lpRect, LPBUFFER buffer, LPOPTIONS options);
DrawFunction draw = reinterpret_cast<DrawFunction>(::GetProcAddress(b_lib, "Draw"));
if(!draw)
{
::OutputDebugString(_T("Can't get address of Draw()"));
goto FINISH_LABEL;
}
LPBUFFER buffer = CreateBuffer("test", _T("path"));
draw(NULL, NULL, buffer, NULL);
DestroyBuffer(buffer);
FINISH_LABEL:
::FreeLibrary(b_lib);
b_lib = NULL;
}
And a whole solution: https://www.dropbox.com/s/5ei6ros9e8s94e2/B.zip
I am trying to write a CLI wrapper around some low-level COM-related calls. One of the operations that I need to do specifically is to get a specific value from a PROPVARIANT, i.e.:
pwszPropName = varPropNames.calpwstr.pElems[dwPropIndex];
where pwszPropName is documented to be an LPWSTR type and dwPropIndex is a DWORD value passed into the function by the user.
I have a native function defined as follows:
HRESULT CMetadataEditor::GetPropertyNameByID(DWORD ID, wchar_t *PropertyName)
I would like to return the value of pwszPropName via *PropertyName.
Is the wchar_t* type the best way to do this, and would I need to pin *PropertyName in my CLI to ensure it does not move in memory? Do I need to define the length of *PropertyName before passing it to native code (buffer)?
If wchar_t* is the right variable type to pass into the native function, what is the proper conversion of LPWSTR to whar_t*, and how then would you convert that value to System::String?
I have tried a number of different techniques over the past few days and can't seem to get anything right.
------------UPDATE------------
Here is my full code. First, the CLI:
String^ MetadataEditor::GetPropertyNameByID(unsigned int ID)
{
LPWSTR mPropertyName = L"String from CLI";
m_pCEditor->GetPropertyNameByID(ID, mPropertyName);
//Convert return back to System::String
String^ CLIString = gcnew String(mPropertyName);
return CLIString;
}
And the native code:
HRESULT CMetadataEditor::GetPropertyNameByID(DWORD ID, LPWSTR PropertyName)
{
HRESULT hr = S_OK;
LPWSTR myPropName;
PROPVARIANT varNames;
PropVariantInit(&varNames);
hr = m_pMetadata->GetAllPropertyNames(&varNames);
if(hr != S_OK)
{
PropVariantClear(&varNames);
return hr;
}
myPropName = varNames.calpwstr.pElems[ID];
PropertyName = myPropName;
PropVariantClear(&varNames);
return hr;
}
It doesn't seem like the value (myPropName) is set properly and/or sustained back into the CLI function because the CLI returns the value I set on mPropertyName before calling the native function.. I'm not sure why or how to fix this.
UPDATE!!!!
I suspected my problem had something to do with variables going out of scope. So I changed the C++ function definition as follows:
LPWSTR GetPropertyNameByID(DWORD ID, HRESULT ErrorCode);
After adjusting the CLI as well, I now get a value returned, but the first character is incorrect, and in fact can be different with every call. I tried using ZeroMemory() in the native class before assigning the output of the PROPVARIANT to the variable (ZeroMemory(&myPropName, sizeof(myPropName +1)); but still no luck.
You can design unmanaged function by the following way:
HRESULT CMetadataEditor::GetPropertyNameByID(DWORD ID, LPWSTR PropertyName, size_t size)
{
....
wcscpy(PropertyName, varNames.calpwstr.pElems[ID]); // or wcsncpy
...
}
PropertyName is the buffer allocated by caller, size is its size. Inside the function wcscpy or wcsncpy the string varNames.calpwstr.pElems[ID] to PropertyName. Client code:
WCHAR mPropertyName[100];
m_pCEditor->GetPropertyNameByID(ID, mPropertyName, sizeof(mPropertyName)/sizeof(mPropertyName[0]));
Think, for example, how GetComputerName API is implemented, and do the same
Im modifiy my display drivers to get update notifcation sent from the USB port. So far so good, but i got stock on follow:
GPEFlat::GPEFlat()
{
PBOOT_ARGS args;
ULONG fbSize;
ULONG fbOffset;
ULONG offsetX;
ULONG offsetY;
BOOL bFoundArgs = FALSE;
BOOL m_MouseDisabled = TRUE;
HANDLE m_hAttachEvent = CreateEvent(NULL, FALSE, FALSE, L"MouseAttached");
HANDLE m_hDetachEvent = CreateEvent(NULL, FALSE, FALSE, L"MouseDetached");
HANDLE m_hCursorThread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)MouseEventThread, NULL, 0, NULL);
DWORD
GPEFlat::MouseEventThread(void)
{
DWORD rc = TRUE;
HANDLE handles[2];
handles[0] = m_hAttachEvent;
handles[1] = m_hDetachEvent;
The resulting error is:
Error 1 error C2440: 'type cast' : cannot convert from 'overloaded-function' to 'LPTHREAD_START_ROUTINE' drivers\display\vgaflat
So the line : HANDLE m_hCursorThread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)MouseEventThread, NULL, 0, NULL);
Dosnt work. Got some pointers that it may be to non static method.
How should i do this?
Greetings
The thing to understand is that functions (including static methods) and non-static methods are different things. CreateEvent expects a function. You must give it that, it will not work with GPEFlat::MouseEventThread because that's a method. What you can do though is give it a function which calls GPEFlat::MouseEventThread. Usually this is done like this
DWORD WINAPI thread_starter(LPVOID that)
{
return ((GPEFlat*)that)->MouseEventThread();
}
...
CreateThread(NULL, 0, thread_starter, this, 0, NULL);
Note that I pass this to CreateThread, that's very important. CreateThread passes it to the parameter that in thread_starter, which uses that to call the method you wanted to call all along.
The MouseEventThread have to be a static function, because a function pointer is not the same as a member function pointer. Static methods can be used as normal function pointers, but non-static member functions can not.
If you need to reference class members, then one very simple solution is to have a static wrapper functions, which takes the instance of the object (this in the constructor) and then calls the actual member function using that instance pointer.
Something like
class GPEFlat
{
// ...
private:
static DWORD MouseEventThreadWrapper(LPVOID instance)
{ return reinterpret_cast<GPEFlat*>(instance)->MouseEventThread(); }
// ...
};
Create the thread with this wrapper function instead, passing this as argument to it:
GPEFlat::GPEFlat()
{
// ...
HANDLE m_hCursorThread = CreateThread(
NULL, 0, (LPTHREAD_START_ROUTINE)MouseEventThreadWrapper, this, 0, NULL);
}