|
I'm using VC++6
Has anyone ever gotten OLE Drag&Drop to work between multiple CListCtrls with multiple columns?
If so, could you please give me some example code of how to get this working?
I can get it working if I just dummy data that I feed in OnInitDialog, but if I read data from a file and InsertItem/SetItemText, the Drag&Drop bombs.
The weird thing is it is not consistent. Sometimes I can drag&drop a couple of items, and then it bombs, sometimes it bombs after only one item. Selecting multiple items always bombs.
But everthing works fine if I preload some dummy data, like I said.
I am totally stumped, so please I need some help!
Murrah Boswell
|
|
|
|
|
The fact that you can sometimes drop more than one item, whil at other times you can not, suggests to me that somewhere along the line not enough memory is being allocated.
Maybe try dragging a few items whose data members are very short/small. Compare that with dragging longer/larger items. Any difference?
Also, some clarification would be great: what do you mean when you say "bombs"? GPFs? Fails? If the latter, then are any useful error codes returned anywhere?
|
|
|
|
|
Hello,
The error message is always the same:
Instruction at "0x77fcc452" referenced memory at "0x676e6973". The memory could not be "written".
And then when I go into debug, I get:
Unhandled exception ... (NTDLL.DLL): 0xC0000005: Access Violation.
I have a structure defined:
typedef struct {
LVITEM* plvi;
CString sSubject;
CString sFrom;
CString smsg_num;
} ListInfo, *plvItem;
and
ListInfo* rowdata[MAXMESSAGES * sizeof(ListInfo*)];
Where MAXMESSAGES is defined to be 2000.
The code I use for OnBeginDrag:
void CPopListCtrl::OnBegindrag(NMHDR* pNMHDR, LRESULT* pResult)
{
NM_LISTVIEW* pNMListView = (NM_LISTVIEW*)pNMHDR;
FILE* m_fpTmp;
CString sMsgCount;
StartInRammedEarth = False;
StartInCob = False;
StartInAdobe = False;
// Get the CWnd handle of the current control where we start dragging!!
CPoint pt;
GetCursorPos(&pt);
CWnd* pWnd = WindowFromPoint(pt);
int iItem = ((NM_LISTVIEW*) pNMHDR)->iItem;
if (pWnd->GetDlgCtrlID() == IDC_LIST_RAMMEDEARTH)
StartInRammedEarth = True;
else if (pWnd->GetDlgCtrlID() == IDC_LIST_COB)
StartInCob = True;
else if (pWnd->GetDlgCtrlID() == IDC_LIST_ADOBE)
StartInAdobe = True;
m_iDragItem = iItem; // Item on which D&D is started
m_iDropItem = -1; // Not yet known
m_bDragging = TRUE; // D&D started
m_bSource = TRUE; // We start D&D on the source
m_bTarget = FALSE; // Not yet known
m_nItem = GetSelectedCount(); // Used for counting number of selected items
// Allocate an array for saving item indexes
m_pSaveIndItem = new int[m_nItem];
// This doesn't work!
// HGLOBAL hgData = GlobalAlloc(GPTR,m_nItem*sizeof(ListInfo)+2*sizeof(int));
// ASSERT(hgData!=NULL);
// char* p = (char*) GlobalLock(hgData);
// ASSERT(p!=NULL);
m_fpTmp = fopen("incomingmail\\msgcount" , "wb");
sMsgCount.Format(_T("%d"),m_nItem);
fprintf(m_fpTmp,sMsgCount);
fclose(m_fpTmp);
LVITEM* plvitem;
ListInfo* pItem;
int jItem = -1, i=0;
while ((jItem = GetNextItem(jItem,LVNI_ALL | LVNI_SELECTED)) > -1)
{
ASSERT(i>=0 && i <m_nItem);
plvitem = new LVITEM;
ZeroMemory(plvitem, sizeof(LVITEM));
pItem = new ListInfo;
//If you use ZeroMemory on the lvItem struct, it creates an error when you try to set sFrom
//ZeroMemory(pItem, sizeof(ListInfo));
pItem->plvi = plvitem;
pItem->plvi->iItem = jItem;
pItem->plvi->mask = LVIF_TEXT;
//since this is a pointer to the string, we need a new pointer to a new string on the heap
pItem->plvi->pszText = new char;
pItem->plvi->cchTextMax = 255;
GetItem(pItem->plvi);
pItem->sSubject = GetItemText(jItem, 0);
pItem->sFrom = GetItemText(jItem, 1);
pItem->smsg_num = GetItemText(jItem, 2);
rowdata[i] = pItem;
m_pSaveIndItem[i] = jItem;
i++;
}
HGLOBAL hgData = GlobalAlloc(GPTR,(m_nItem+1)*sizeof(rowdata));
ASSERT(hgData!=NULL);
// ListInfo* lpData[m_nItem * sizeof(ListInfo*)]=(ListInfo*)GlobalLock(hgData);
ListInfo* lpData=(ListInfo*)GlobalLock(hgData);
lpData = *rowdata;
// Cache the data, and initiate DragDrop
m_COleDataSource.CacheGlobalData(CF_TEXT, hgData);
// Set drag/drop source rectangle (screen coord)
SetDragSourceRect();
DROPEFFECT dropEffect = m_COleDataSource.DoDragDrop(DROPEFFECT_COPY|DROPEFFECT_MOVE,NULL);
if (m_bRemove && (dropEffect&DROPEFFECT_MOVE)==DROPEFFECT_MOVE)
{
// Delete items in reverse order so that indexes are preserved
for (i=m_nItem-1; i>=0; i--)
{
jItem = m_pSaveIndItem[i];
if (m_bSource && m_bTarget)
{
ASSERT(m_iDropItem>=0);
if (jItem > m_iDropItem) jItem += m_nItem;
}
BOOL bSuccess = DeleteItem(jItem);
ASSERT(bSuccess);
}
}
m_bSource = FALSE;
m_bTarget = FALSE;
m_iDropItem = -1;
delete[] m_pSaveIndItem;
m_pSaveIndItem = NULL;
m_nItem = 0;
*pResult = 0;
}
and the code I use for OnDrop
BOOL COleListCtrlDropTarget::OnDrop(CWnd* pWnd, COleDataObject* pDataObject,
DROPEFFECT dropEffect, CPoint point )
{
FILE* m_fpTmp;
CString sMsgCount;
char c;
int nItem;
int iNewItem;
HGLOBAL hGlobal;
ListInfo* pData;
// TRACE("\nOnDrop");
CPopListCtrl* pDDList = (CPopListCtrl*) pWnd;
// Stop the scroll timer if it's running.
pDDList->KillTimer (1);
// Flag the list as target
pDDList->m_bTarget = TRUE;
if (pWnd->GetDlgCtrlID() == IDC_LIST_RAMMEDEARTH) {
RAMMEDEARTH = True;
COB = False;
} else if (pWnd->GetDlgCtrlID() == IDC_LIST_COB) {
COB = True;
RAMMEDEARTH = False;
}
// Find out the drop item
int iItem;
int iItemCountRammedEarth = m_listRammedEarth.GetItemCount();
int iItemCountCob = m_listCob.GetItemCount();
if (pDDList->GetItemCount() == 0)
iItem = 0; // List is empty
else
{
// Find drop element in list
UINT nFlags;
point.y += 5;
iItem = pDDList->HitTest (point, &nFlags);
if (iItem == -1)
{
// Get coordinates of top and bottom visible points
int iTopItem = pDDList->GetTopIndex();
int iBotItem = iTopItem + pDDList->GetCountPerPage() -1;
if (iBotItem > pDDList->GetItemCount()-1)
iBotItem = pDDList->GetItemCount() - 1;
CPoint topPoint, botPoint;
BOOL bSuccess = pDDList->GetItemPosition(iTopItem, &topPoint);
ASSERT(bSuccess);
bSuccess = pDDList->GetItemPosition(iBotItem, &botPoint);
ASSERT(bSuccess);
if (point.y <= topPoint.y+5)
iItem = 0;
else if (point.y >botPoint.y)
iItem = pDDList->GetItemCount(); // Add at the end
else
{
// If there was an error adding the text to the control
// return FALSE so that the text is not removed from
// the drop source
return FALSE;
}
}
}
// iItem in the next available index number in dropbox.
pDDList->m_iDropItem = iItem;
ASSERT(pDDList->m_iDropItem>=0);
if (pDDList->m_bSource && pDDList->m_bTarget)
{
// Check that we don't drop on dragged items
TRACE("\niItem=%d pSaveInItem[0]=%d pSaveInItem[0]=%d",iItem,pDDList->m_pSaveIndItem[0],pDDList->m_pSaveIndItem[pDDList->m_nItem-1]);
if (iItem >= pDDList->m_pSaveIndItem[0] &&
iItem <= pDDList->m_pSaveIndItem[pDDList->m_nItem-1])
{
// Display an error message if the move is illegal.
AfxMessageBox (_T ("An item can't be dropped onto itself"));
pDDList->SelectDropTarget(-1);
// If there was an error adding the text to the control
// return FALSE so that the text is not removed from
// the drop source
return FALSE;
}
}
// Get List data from COleDataObject
hGlobal = pDataObject->GetGlobalData(CF_TEXT);
pData=(ListInfo*)GlobalLock(hGlobal);
ASSERT(pData!=NULL);
// Add the item(s) to the list
m_fpTmp = fopen("incomingmail\\msgcount" , "rb");
do {
c = fgetc (m_fpTmp);
sMsgCount += c;
} while (c != EOF);
fclose(m_fpTmp);
nItem = atoi((LPCSTR)sMsgCount);
for (int i=0; i<nItem; i++)
{
if (RAMMEDEARTH) {
iNewItem = m_listRammedEarth.InsertItem(i+iItemCountRammedEarth,rowdata[i]->sSubject);
m_listRammedEarth.SetItemText(i+iItemCountRammedEarth,1,rowdata[i]->sFrom);
m_listRammedEarth.SetItemText(i+iItemCountRammedEarth,2,rowdata[i]->smsg_num);
// iNewItem = m_listRammedEarth.InsertItem(i+iItemCountRammedEarth,pData[i]->sSubject);
// m_listRammedEarth.SetItemText(i+iItemCountRammedEarth,1,pData[i]->sFrom);
// m_listRammedEarth.SetItemText(i+iItemCountRammedEarth,2,pData[i]->smsg_num);
} else if (COB) {
iNewItem = m_listCob.InsertItem(i+iItemCountCob,rowdata[i]->sSubject);
m_listCob.SetItemText(i+iItemCountCob,1,rowdata[i]->sFrom);
m_listCob.SetItemText(i+iItemCountCob,2,rowdata[i]->smsg_num);
// iNewItem = m_listCob.InsertItem(i+iItemCountCob,pData[i]->sSubject);
// m_listCob.SetItemText(i+iItemCountCob,1,pData[i].sFrom);
// m_listCob.SetItemText(i+iItemCountCob,2,pData[i]->smsg_num);
}
} // End for (int i=0; i<nItem; i++)
// Unlight all list items
pDDList->SelectDropTarget(-1);
// Select the newly added item.
BOOL bSuccess = pDDList->SetItemState(iNewItem, LVIS_SELECTED, LVIS_SELECTED);
// Unlock memory
GlobalUnlock(hGlobal);
return TRUE;
} // End OnDrop
If you can see what I am doing wrong, I really would appreciate it!
Thanks,
Murrah Boswell
|
|
|
|
|
One definite problem is this part of CPopListCtrl::OnBegindrag():
//since this is a pointer to the string, we need a new pointer to a new string on the heap
pItem->plvi->pszText = new char;
It should be: new char[SOME_NUMBER];
I assume you want SOME_NUMBER to be 255, as the next line of code indicates:
pItem->plvi->cchTextMax = 255;
This error could easily explain the somewhat sporadic nature of your crash: it all depends what memory is being overwritten when the next line of code, GetItem(pItem->plvi), causes data to be written to the address pointed to by pItem->plvi->pszText.
Try fixing this problem and let us know if things are cool. If not, we'll keep digging.
|
|
|
|
|
Hello and Thank You,
...
It should be: new char[SOME_NUMBER];
...
That was the problem!
I changed it to new char[255] and it works perfectly.
Don't know what I would do without this forum!
Thanks again,
Murrah Boswell
|
|
|
|
|
Hi!
How can I convert an unsigned to std string?
Well... I am a beginner ...
|
|
|
|
|
|
hi guys,
I am now writting a dial-up program with ras, and I want to get the connection status. For example ,speed rate, send data bytes or get data bytes.
Does anyone has a idear? It must be valid for windows2000 and windows98.
tks.
|
|
|
|
|
Did you open the connection or do you want to get the status of an already open connection?
Well... I am a beginner ...
|
|
|
|
|
Two classes (declared in different headers and defined in different *.cpp files) use each other. How do I #include them in each other's headers correctly? When I use #pragma once it doesn't compile, but without it the headers get infinitely included.
Tnx in advance.
|
|
|
|
|
If the shared data are simple types such as char, int etc., wouldn't it be better to use a "global" header and place them there, or use extern .
If the data are more complicated types (e.g. CEdit), my suggestion would be to just pass the desired data (e.g. CEdit's text - CString) between the two classes.
|
|
|
|
|
Each of the two classes must contain a pointer to the other one. I know it can be done, but how? The just need to be included.
|
|
|
|
|
You can forward declare the pointed class in your .h file. For example, if class A needs to point to class B , do this (in a.h ):
class B;
class A {
...
public:
B* m_pointerToB;
}
/ravi
My new year's resolution: 2048 x 1536
Home | Articles | Freeware | Music
ravib@ravib.com
|
|
|
|
|
|
Hi guys,
as coming from a pure C++ programming background, I'm quite used to the use of boolean type bool and has decided to continue using it when developing MFC apps. From MSDN, I understood that bool type variable would occupy less memory than BOOL (1 bytes vs. 2 or 4 bytes), since BOOL is actually int type. Correct?
In my programs, I have some BOOL type DDX control value to be passed as function parameters. And when I did that, I get warning message like the following:
warning C4800: 'BOOL' : forcing value to bool 'true' or 'false' (performance warning)
performance warning, doesn't sound very good to me Is it better I do a conversion manually before passing it or that effort isn't generally required?
<code>
BOOL bTest;
if (bParameter == true)
bTest = TRUE;
else
bTest = FALSE;
Thanks!
|
|
|
|
|
BOOL is indeed a typedef 'd int .
If you want to do a safe conversion do this:
bTest = (bParameter != FALSE);
I don't know what kind of performance decrease you get when directly casting a bool to a BOOL.
regards
modified 12-Sep-18 21:01pm.
|
|
|
|
|
You have it backwards, the performance hit is when you do a BOOL to a bool.
bool bOut = bIn != FALSE;
BTW, with a BOOL, never do (x == TRUE) as a test. As far as conditionals go, it is 0 or not 0. It doesn't test for FALSE and TRUE.
Tim Smith
I'm going to patent thought. I have yet to see any prior art.
|
|
|
|
|
Thanks alot guys,
the comments are very useful.
Tim, are you saying a BOOL type variable can be more than just TRUE (1) and FALSE (0) ?
|
|
|
|
|
actually, yes. But I've not seen any app setting the value of a BOOL to anything other apart from TRUE and FALSE.
TRUE is just a #define (1), while FALSE is a #define (0)
modified 12-Sep-18 21:01pm.
|
|
|
|
|
Don;t be too sure about it... TrackPopupMenu return BOOL and it can be made to return which menu item was selected in the popup menu (setting via parameters).
|
|
|
|
|
Thanks; that's why I said "I haven't seen any app....". Now I know there IS at least one API doing such things
regards
modified 12-Sep-18 21:01pm.
|
|
|
|
|
The WIN32 API is a bit of a minefield when it comes to BOOL processing. On NT the API might return a true TRUE/FALSE while on Win9x, then API might return ==0/!=0. This is why I always say to play it safe and never test for "== TRUE".
Tim Smith
I'm going to patent thought. I have yet to see any prior art.
|
|
|
|
|
if your BOOL > 0 it is TRUE.
if your BOOL = 0 it is FALSE.
Don't know for sure for values < 0.
their are apps eg. where your BOOL has value 2 or 3 , ...
then you can do if(YOURBOOL){ ... }
personally I think BOOL is against the whole idea of the basic datatype of a boolean. I would recommend a bool if you want to use true or false and an int or something if you have more values (and do if(yourint == 3){...} )
but it's MFC
"If I don't see you in this world, I'll see you in the next one... and don't be late." ~ Jimi Hendrix
|
|
|
|
|
it is
BOOL == 0 is FALSE
BOOL != 0 is TRUE
Tim Smith
I'm going to patent thought. I have yet to see any prior art.
|
|
|
|
|
Hi Everybody,
I have a question regarding "Using MFC in Win32 Application". I am using Visual Studio6.0. I want to use MFC in my Win32 Application. I started File->New->Win32 Application->A Simple Win32 Application. And I get the following code pasted below. Now I want to use MFC, say, CString, How do I do it? I tried to use as "CString str" and included the header file <afx.h> but of no use. It gives compile errors as "CString undeclared identifier" Can anybody help? Can anybody tell me which header files and .lib files to use, or any other settings to be made to the editor???
----------------------------------------------------------
// FirstSample.cpp : Defines the entry point
// for the application.
//
#include "stdafx.h"
int APIENTRY WinMain(HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPSTR lpCmdLine,
int nCmdShow)
{
// TODO: Place code here.
CString str;
return 0;
}
-----------------------------------------------------------
Regards
VYJU
|
|
|
|
|