|
Hi!
How can I pass a string array to an LPARAM parameter in C++?
I've tried a
std::list<std::basic_string<TCHAR> type but my program crashes when I cast the values:
string_list szFile = (string_list) ppsp->lParam;
Thanks in advance.
|
|
|
|
|
What is string_list , and what does ppsp point to? There is so much detail missing from your question it's impossible to guess what the problem is.
One of these days I'm going to think of a really clever signature.
|
|
|
|
|
string_list is defined as:
typedef std::list<std::basic_string<TCHAR> > string_list;
ppsp is defined as
PROPSHEETPAGE* ppsp
|
|
|
|
|
Yes but what does the variable ppsp actually point to at the time of the crash? It is impossible, as I said earlier, to guess what is happening in your program without more detail as to the content of the variables being referenced and the actual instruction at the time of the crash.
One of these days I'm going to think of a really clever signature.
|
|
|
|
|
I usually create a dummy class/struct to hold the data to pass to LPARAM.
The dummy class is allocated on the heap and destroyed (delete) by the handler of the message. it contains a copy of the data.
not very practical for large data sets, but for small dataset it seems to be working fine.
(YMMV).
Watched code never compiles.
|
|
|
|
|
Supposing you can do that (e.g. you are not using it for posting a message to another application), you should pass the pointer to the list, e.g.
std::list< std::basic_string< TCHAR > > myList;
PostMessage(hWnd, wParam, (LPARAM) &myList);
std::list< std::basic_string< TCHAR > > * pList = (std::list< std::basic_string< TCHAR> > *) ppsp->lParam;
Veni, vidi, vici.
|
|
|
|
|
It might not be obvious for the OP that myList is either declared somewhere in a persistent location (and not on the stack) when using PostMessage() , or it can be on the stack as a temporary object but in that case SendMessage() must be used instead of PostMessage() and the message handler code must copy the contents of the list object because it might run out of scope after the message processor function returns. A perfect solution though and it shows that anything can be passed to the gui thread as a parameter.
The difference between SendMessage() and PostMessage() is that both functions put a message on the queue of the window to process but SendMessage() blocks the calling thread until the message is processed on the gui thread. If you use PostMessage() then the message is placed on the queue and your PostMessage() call returns immediately and this means that the stack object probably runs out of scope and the pointer parameter associated with the message will be invalid at the time the other thread processes the message.
|
|
|
|
|
Good point.
Veni, vidi, vici.
|
|
|
|
|
This code doesn't work.
I'm writting a Shell Extension (Property Page).
myList must point to a string array that represents the selected files.
In the AddPage function:
HRESULT CCSheetExt::AddPages (LPFNADDPROPSHEETPAGE lpfnAddPageProc, LPARAM lParam )
I have:
psp.lParam = (LPARAM) &myList;
All is OK. But in the
BOOL OnInitDialog ( HWND hwnd, LPARAM lParam ) function, I have:
string_list* pszFile = (string_list*) ppsp->lParam;
This line causes a program crash.
|
|
|
|
|
I think you should provide more code.
For instance, are you sure ppsp is a valid pointer?
Veni, vidi, vici.
|
|
|
|
|
std::list<std::basic_string<TCHAR> > m_lsFiles;
HRESULT CCSheetExt::Initialize (LPCITEMIDLIST pidlFolder, LPDATAOBJECT pDataObj, HKEY hProgID )
{
TCHAR szFile [MAX_PATH];
UINT uNumFiles;
HDROP hdrop;
FORMATETC etc = { CF_HDROP, NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL };
STGMEDIUM stg;
if ( FAILED( pDataObj->GetData ( &etc, &stg )))
return E_INVALIDARG;
hdrop = (HDROP) GlobalLock ( stg.hGlobal );
if ( NULL == hdrop )
{
ReleaseStgMedium ( &stg );
return E_INVALIDARG;
}
uNumFiles = DragQueryFile ( hdrop, 0xFFFFFFFF, NULL, 0 );
for ( UINT uFile = 0; uFile < uNumFiles; uFile++ )
{
if ( 0 == DragQueryFile ( hdrop, uFile, szFile, MAX_PATH ))
continue;
m_lsFiles.push_back ( szFile );
}
GlobalUnlock ( stg.hGlobal );
ReleaseStgMedium ( &stg );
return ( m_lsFiles.size() > 0 ) ? S_OK : E_FAIL;
}
HRESULT CCSheetExt::AddPages (LPFNADDPROPSHEETPAGE lpfnAddPageProc, LPARAM lParam )
{
PROPSHEETPAGE psp;
HPROPSHEETPAGE hPage;
TCHAR szPageTitle [MAX_PATH];
string_list::const_iterator it, itEnd;
LoadString (hModuleInstance,IDS_PROJNAME,szPageTitle,sizeof(szPageTitle));
szPageTitle[24] = '\0';
psp.dwSize = sizeof(PROPSHEETPAGE);
psp.dwFlags = PSP_USEREFPARENT | PSP_USETITLE | PSP_DEFAULT |
PSP_USECALLBACK;
psp.hInstance = hModuleInstance;
psp.pszTemplate = MAKEINTRESOURCE(IDD_PROPPAGE);
psp.pszIcon = 0;
psp.pszTitle = szPageTitle;
psp.pfnDlgProc = PropPageDlgProc;
psp.lParam = (LPARAM) &m_lsFiles;
psp.pfnCallback = PropPageCallbackProc;
psp.pcRefParent = (UINT*) &_Module.m_nLockCnt;
hPage = CreatePropertySheetPage ( &psp );
if ( NULL != hPage )
{
if ( !lpfnAddPageProc ( hPage, lParam ))
{
DestroyPropertySheetPage ( hPage );
}
}
return S_OK;
}
BOOL OnInitDialog ( HWND hwnd, LPARAM lParam )
{
PROPSHEETPAGE* ppsp = (PROPSHEETPAGE*) lParam;
string_list* pszFile = (string_list*) ppsp->lParam;
HANDLE hFind;
WIN32_FIND_DATA rFind;
string_list::const_iterator it;
it = pszFile->begin();
CCOMString File=it->c_str();
MessageBox (0, File, "Tests", 0);
}
|
|
|
|
|
How do you create the dialog (have I missed something?)?
Veni, vidi, vici.
|
|
|
|
|
This code come from a Shell Extension, so the dialog is created by Windows Explorer when the user right click on a file.
|
|
|
|
|
What you did is pretend that a string is a LPARAM. That does not change the contents of the variable though! If it had a size of 20 bytes before, it's size is still 20 bytes afterward.
An analogy would be to write 'glass' on a bucket, and then pour it's contents into a glass. Of course that glass will overflow. The water inside that bucket didn't magically compress.
The only case where this would work is when you initially started with an empty bucket, then poured a glass of water in it. At that point you know that while you see a bucket, it's contents is only one glass of water, so you can write 'glass' on it and pour that water back into another glass.
The same is true for typecasting: if you had previously (ab)used that string of yours to store an LPARAM, then - and only then - it would be valid to cast that string back to LPARAM and copy it over into a variable of that type.
As a rule of thumb, never use type-casting. If you think you need a type-cast, then either the type of one (or more) of the involved variables had been wrong from the start, or you're about to break the code. The former would be like using a bucket when you never need to store more than a glass full of water, the latter would be like pouring a bucket full of water into a glass.
There are very few exceptions to that rule, e. g. when you deal with a third-party library that uses inproper argument types such as LPARAM. The clean solution would be to fix that interface and use proper argument types, but sadly you don't have that option. MS should have fixed that 10 years ago, but they didn't.
This leaves you with the onus of assuring that the variables that you wish to pass actually fits into an LPARAM. As already pointed out, it does not. So you have to find another way, and that is passing a pointer to your string, rather than the string itself.
|
|
|
|
|
Hi,
I have a dialog box. from that dialog box, I am invoking a Modal dialog box. I have a slider control on that modal dialog box. Now I want when the user drags the slider control, value should get passed to the parent dialog box while scrolling. For example, while zooming an image, user drags the slider, Image size will increase appropriately.
Anybody have an idea.?
Regards,
Mbatra
|
|
|
|
|
the simplest way is to have the child call a member function on the parent.
void CChildDlg::OnHScroll(whatever)
{
CParentDlg *pParent = (CParentDlg *)GetParent();
pParent->UpdateZoomInfo(some info about the zoom);
}
|
|
|
|
|
You question is already answered, I just wanted to say that your solution seems to be a bad gui design. Setting the parameters of a disabled window from a modal dialog box isnt the way to go. I think you should do that from a modeless toolbox window.
|
|
|
|
|
hi guys,
i am using vs.net 2010 c++ and i need help:
i have
class school
{
public:
vector<student*>* students;
school()
{
vector<student*> s;
students = &s;
}
}
however when i try to
school s;
students.push_back(&s);
there is always an error,
Unhandled exception at 0x0f5757aa (msvcr100d.dll) in ast1.exe: 0xC0000005: Access violation reading location 0xccccccc0.
could anyone help me please.
|
|
|
|
|
There are so many issues with your code ...
Your vector is a pointer; you must allocate it before using it :
The student vector is a member of the class; so you must access it via the school class.
Change to (it is still very early here, and I've noy yet had coffee):
class school
{
public:
vector<student*> students;
school()
{
}
}
int main()
{
student* pStudent = new student; school aSchool; aSchool.students.push_back( pStudent );
return 0;
}
As a side note, your vector could contain "plain" students if the size and the data inside each student is small and simple enough; that would reduce the need for allocatation and de-allocation.
Also, have a look at smart/shared pointers for cleaner code (more advanced concepts).
Good luck.
Watched code never compiles.
|
|
|
|
|
neodeaths wrote: students.push_back(&s);
You are trying to push the address of a school object onto a vector expecting a student pointer. Is that the intent?
"One man's wage rise is another man's price increase." - Harold Wilson
"Fireproof doesn't mean the fire will never come. It means when the fire comes that you will be able to withstand it." - Michael Simmons
"Show me a community that obeys the Ten Commandments and I'll show you a less crowded prison system." - Anonymous
|
|
|
|
|
The exception is caused by invalid initialization code. In your constructor, you define a local vector s , and store the address to that variable in school::students . That local variable is located on the stack. The moment you leave that constructor though, the stack is unwound and the local variable will be destroyed. Then school::students points to an invalidated memory location. The moment you try work with the students vector, you'll get an exception as it points to invalid memory.
Instead of initializing your variable on the stack, you have to allocate it on the heap like this:
class school {
public:
vector<student*>* students;
school()
{
students = new vector<student*>:
}
~school()
{
delete students;
}
};
Note that I also added a destructor to make sure the memory will be released again when it is no longer needed.
|
|
|
|
|
Environment: Winows XP Pro, Visual Studio 2008, MFC, C++
Goal: To modify my blocking TCP code that transmitts data to a client to non-blocking or asynchronous operations. The blocking code works, but needs to be changed to async, or to a separate thread, or maybe both, I am uncertain but think that last will be best.
I have been reading the Article: Programming Windows TCP Sockets in C++ for the Beginner
By c_07 and found here:
Programming Windows TCP Sockets in C++ for the Beginner
I think I follow fairly well up through the method definition: int ListenOnPort(int portno)
As I understand it, this is the code for the server to listen for a client to connect and it is blocking. The the author proceeds into the async section and says to put this line of code after the listen() call:
WSAAsyncSelect (s, hwnd, MY_MESSAGE_NOTIFICATION, (FD_ACCEPT | FD_CONNECT |
FD_READ | FD_CLOSE); I don't understand how putting a call after the Listen() can transform that call from a blocking call to a non blocking call. I suspect there are more code changes to the server code but I am not unable to recognize what I need to change. I am writing the server part to communicate with a vendor's client application.
Please advise as to what I have missed.
Thank you.
Thanks for your time
|
|
|
|
|
The listen() call never blocks not even if you use blocking sockets. It just tells the operating system to establish listening on that socket and to put connection requests to a queue for that socket (the size of the queue is the backlog parameter of listen() ). What might block is the accept() call that removes an incoming connection from the listen queue. Your code replaces this blocking accept() call, windows sends your window a message when you have an incoming connection. Async or blocking? Either way you go its definitely better to put networking to a separate thread instead of handling it with the windows specific window-message events. This window-message driven networking mixes ui code with networking (against the Separation of Concerns - and the result is not reusable code), might decrease the responsiveness of your ui if you use high throughput. Async networking is more difficult to program but sometimes that's the clear way to go. Whether blocking or async it depends on what you exactly want to do.
modified 27-Aug-12 5:03am.
|
|
|
|
|
Well that is a quite interesting reply.
This application will be sending between three and nine messages per millisecond, maybe as much as nine killobytes per millisecond. I presume that puts it an the high end of the scal for throughput.
Just in case: This application outputs data and other than status from the TCP/IP manager, does not input any data via the TCP/IP port
Do you have a favorite tutorial or guideline for starting new threads and transferring data from the main thread to the new one?
Thanks for your time
|
|
|
|
|
That's around 10MByte/sec, thats quite OK, with good network 100MByte/sec can be achieved. You might want to set the send/receive buffer size of your sockets (setsockopt/SO_SNDBUF/SO_RCVBUF), without this sometimes its not possible to reach the best throughput with the default buffer sizes (I don't know why, found this out by experimenting). But this is not a parameter that decides between async/blocking. Its rather the protocol. When do you send and when do you receive data? If you can exactly determine when to receive and when to send then use blocking sockets because its easier (the typical protocol for blocking sockets is request - response, one of the peers is active and the other just replies). If you might want to send at arbitrary points and you might have to receive incoming packets at random points then you need to write an async solution that also handles when the bandwith isn't good enough to send data with the desired rate.
EDIT: Transferring data from one thread to another one: this stuff is called blocking queue. It is the most universal and often the most efficient way to send data/events from one thread to another. The worker thread has a blocking queue and it always gets the first item from it, if the queue is empty then the worker thread blocks on the get() method of the queue until another thread puts an item to it. After getting the item from the queue the worker thread processes that item (sends data on the socket) and then it goes back to the beginning of the loop and gets another item from the loop for processing. The other thread or threads can put data to the other side of the queue. The put method doesn't block. You should just store pointers in this queue, pointers to data objects to minimize the synchronization overhead (by avoiding data copying) in the blocking queue. Unfortunately I have no favorite threading tutorial but I'm currently working on a codeproject article about threading for dummies. That will describe threading step by step and will teach using blocking queues too.
EDIT: Since in your case the data flow goes to a single direction you should use a blocking socket. You should also handle somehow when your bandwidth goes too low, in that case you should avoid the blocking queue from growing ultra large causing an out of memory error. You should somehow suspend the generation of messages in that case because sooner or later you will not have space to store the newly generated messages.
EDIT: A very simple example to using a multi-producer single consumer blocking message queue (with only a single producer thread - the main thread):
#include <windows.h>
#include <stdio.h>
#include <assert.h>
#include <queue>
template <typename T>
class BlockingQueue
{
public:
BlockingQueue()
{
InitializeCriticalSection(&m_Lock);
m_hBecameNonEmptyEvent = CreateEventW(NULL, TRUE, FALSE, NULL);
}
~BlockingQueue()
{
assert(m_Queue.empty());
DeleteCriticalSection(&m_Lock);
CloseHandle(m_hBecameNonEmptyEvent);
}
void Put(const T& item)
{
EnterCriticalSection(&m_Lock);
if (m_Queue.empty())
SetEvent(m_hBecameNonEmptyEvent);
m_Queue.push(item);
LeaveCriticalSection(&m_Lock);
}
void Get(T& item)
{
EnterCriticalSection(&m_Lock);
if (m_Queue.empty())
{
ResetEvent(m_hBecameNonEmptyEvent);
LeaveCriticalSection(&m_Lock);
WaitForSingleObject(m_hBecameNonEmptyEvent, INFINITE);
EnterCriticalSection(&m_Lock);
}
item = m_Queue.front();
m_Queue.pop();
LeaveCriticalSection(&m_Lock);
}
private:
BlockingQueue(const BlockingQueue&);
BlockingQueue& operator=(const BlockingQueue&);
private:
CRITICAL_SECTION m_Lock;
HANDLE m_hBecameNonEmptyEvent;
std::queue<T> m_Queue;
};
BlockingQueue<int> q;
DWORD __stdcall ThreadProc(void* param)
{
printf("thread started\n");
for (;;)
{
int i;
q.Get(i);
printf("processing %d\n", i);
if (i == 0)
break;
}
printf("thread is out of the loop, returning from threadproc...\n");
return 0;
}
int main(int argc, char* argv[])
{
printf("Creating thread...\n");
DWORD thread_id;
HANDLE hThread = ::CreateThread(NULL, 0, ThreadProc, NULL, 0, &thread_id);
if (!hThread)
{
fprintf(stderr, "CreateThread error!\n");
return 1;
}
for (;;)
{
char buf[0x100];
if (!gets(buf))
break;
int i;
if (1 == sscanf(buf, "%d", &i))
{
q.Put(i);
if (i == 0)
break;
}
else
{
printf("Not an integer: %s\n", buf);
}
}
printf("Waiting for the thread to finish...\n");
WaitForSingleObject(hThread, INFINITE);
printf("Wait finished.\n");
CloseHandle(hThread);
return 0;
}
You should store pointers in the blocking queue and you can use for example the NULL pointer to ask the other thread to exit like I used the zero value.
modified 27-Aug-12 16:11pm.
|
|
|
|
|