Avatar of AngryLoop
AngryLoop

asked on 

AccessViolation calling COleDataSource::DoDragDrop from C++/CLI

Here's a quick background on what I'm trying to acomplish:

I'm trying to drag drop virtual files by deriving System::Windows::Forms::ListView in my own class and using unmanaged code to delay render.

Here's my OnItemDrag override:
1 virtual void OnItemDrag(ItemDragEventArgs ^e) override  
2 {  
3     UINT uFileCount = this->SelectedItems->Count;  
4     UINT uBuffSize = sizeof(FILEGROUPDESCRIPTOR) +    
5         (uFileCount-1) * sizeof(FILEDESCRIPTOR);  
6     HGLOBAL hFileDescriptor = GlobalAlloc (    
7         GHND | GMEM_SHARE, uBuffSize );  
8     if(hFileDescriptor)  
9     {  
10         FILEGROUPDESCRIPTOR* pGroupDescriptor =    
11             (FILEGROUPDESCRIPTOR*) GlobalLock ( hFileDescriptor );  
12         if(pGroupDescriptor)  
13         {  
14             FILEDESCRIPTOR* pFileDescriptorArray =    
15                 (FILEDESCRIPTOR*)((LPBYTE)pGroupDescriptor + sizeof(UINT));  
16             pGroupDescriptor->cItems = uFileCount;  
17             int index = 0;  
18             m_pDataSrc->m_Files->RemoveAll();  
19             for (int i = 0; i < uFileCount; ++i)  
20             {  
21                 ZeroMemory(&pFileDescriptorArray[index],    
22                     sizeof(FILEDESCRIPTOR));                      
23  
24                 pin_ptr<const wchar_t> wch = PtrToStringChars(this->SelectedItems[i]->Text);  
25  
26                 CString fileName(wch);  
27  
28                 lstrcpy ( pFileDescriptorArray[index].cFileName, fileName );  
29  
30                 m_pDataSrc->m_Files->Add(pFileDescriptorArray[index].cFileName);  
31                 pFileDescriptorArray[index].dwFlags = FD_FILESIZE|FD_ATTRIBUTES;  
32                 pFileDescriptorArray[index].nFileSizeLow = 512;  
33                 pFileDescriptorArray[index].nFileSizeHigh = 0;  
34                 pFileDescriptorArray[index].dwFileAttributes = FILE_ATTRIBUTE_NORMAL;  
35                 index++;  
36             }  
37         }  
38         else  
39         {  
40             GlobalFree ( hFileDescriptor );  
41         }  
42     }  
43     GlobalUnlock ( hFileDescriptor );      
44  
45     FORMATETC etcDescriptor = {    
46         RegisterClipboardFormat(CFSTR_FILEDESCRIPTOR),    
47         NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL };  
48         m_pDataSrc->CacheGlobalData ( RegisterClipboardFormat(  
49             CFSTR_FILEDESCRIPTOR), hFileDescriptor, &etcDescriptor );  
50  
51     FORMATETC etcContents = {    
52         RegisterClipboardFormat(CFSTR_FILECONTENTS),    
53         NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL };  
54  
55     m_pDataSrc->DelayRenderFileData(  
56         RegisterClipboardFormat(CFSTR_FILECONTENTS),    
57         &etcContents);  
58  
59     DROPEFFECT dwEffect = m_pDataSrc->DoDragDrop (    
60         DROPEFFECT_COPY | DROPEFFECT_MOVE );              
61  
62     if(dwEffect == DROPEFFECT_NONE )  
63     {  
64         GlobalFree( hFileDescriptor );  
65     }    
66 }  

I'm getting an AccessViolationException on line 59 - the call to DoDragDrop.

Here's the definition of m_pDataSrc:
protected:  
    CMyOleDataSource * m_pDataSrc;  

It gets instanciated using new in the class constructor.

Here is the implementation of CMyOleDataSource:

[.h file]
1  
2 #pragma once  
3  
4 #include <afxwin.h>         // MFC core and standard components  
5 #include <afxext.h>         // MFC extensions  
6  
7 #include <afxdisp.h>        // MFC Automation classes  
8  
9 #ifndef _AFX_NO_OLE_SUPPORT  
10 #include <afxdtctl.h>       // MFC support for Internet Explorer 4 Common Controls  
11 #endif  
12 #ifndef _AFX_NO_AFXCMN_SUPPORT  
13 #include <afxcmn.h>         // MFC support for Windows Common Controls  
14 #endif // _AFX_NO_AFXCMN_SUPPORT  
15 #include <afxole.h>  
16  
17 // CMyOleDataSource command target  
18  
19 class CMyOleDataSource : public COleDataSource  
20 {  
21     DECLARE_DYNAMIC(CMyOleDataSource)  
22  
23 public:  
24     CMyOleDataSource();  
25     virtual ~CMyOleDataSource() { delete m_Files; }  
26     virtual BOOL OnRenderFileData(LPFORMATETC lpFormatEtc,CFile* pFile);  
27     CStringArray *m_Files;  
28  
29 protected:  
30     DECLARE_MESSAGE_MAP()  
31 };  

[.cpp file]
1 // MyOleDataSource.cpp : implementation file  
2 //  
3  
4 #include "stdafx.h"
5 #include "MyOleDataSource.h"  
6  
7  
8 // CMyOleDataSource  
9  
10 IMPLEMENT_DYNAMIC(CMyOleDataSource, COleDataSource)  
11  
12  
13 CMyOleDataSource::CMyOleDataSource()  
14 {  
15     m_Files = new CStringArray();  
16 }  
17  
18 BEGIN_MESSAGE_MAP(CMyOleDataSource, COleDataSource)  
19 END_MESSAGE_MAP()  
20  
21  
22  
23 // CMyOleDataSource message handlers  
24  
25 BOOL CMyOleDataSource::OnRenderFileData(  
26     LPFORMATETC lpFormatEtc,CFile* pFile)  
27 {  
28     if(lpFormatEtc->cfFormat ==    
29         RegisterClipboardFormat(CFSTR_FILECONTENTS))  
30     {      
31         HGLOBAL hGlob = NULL;  
32         const int buffSize = 512;  
33         hGlob = GlobalAlloc(GMEM_FIXED, buffSize);  
34         if(hGlob)  
35         {  
36             LPBYTE pBytes = (LPBYTE)GlobalLock(hGlob);            
37             if(pBytes)  
38             {  
39                 memset(pBytes, (int) m_Files->GetAt(  
40                     lpFormatEtc->lindex)[0], buffSize);  
41                 pFile->Write(pBytes,buffSize);                
42             }  
43             GlobalUnlock(hGlob);  
44         }  
45         GlobalFree(hGlob);  
46         return TRUE;  
47     }  
48     return COleDataSource::OnRenderFileData(  
49         lpFormatEtc, pFile);  
50 }  

Any ideas why I would be getting an AccessViolation?

Thanks,
AngryLoop
Editors IDEsVisual C++.NETC#

Avatar of undefined
Last Comment
DanRollins
Avatar of DanRollins
DanRollins
Flag of United States of America image

About the only reason to get an Access Violation there is if m_pDataSrc is NULL or otherwise invalid.  That seems unlikely becasue it appears to be used elsewhere.  

Sometimes the debugger points to the wrong line, so check that.   I sugggest that you breakpoint on that line and single-step into the MFC source code.
Avatar of AngryLoop
AngryLoop

ASKER

Thanks for your reply.  I tried what you suggested and it does indeed hit that line and throws an Access Violation exception.  I tried actually stepping into the function... but that doesn't work, it immediately throws the exception.
Avatar of DanRollins
DanRollins
Flag of United States of America image

Did you check to see if m_pDataSrc is NULL?  If not, has iut changed value (via, some perhaps concurrent thread or a "wild pointer" type error?
One thing that you don't show is exactly what m_pDataSrc really is, it's scope, how it gets created and so forth.  Can you provide some code that shows all of that?
Avatar of AngryLoop
AngryLoop

ASKER

Yes, I verified it wasn't null - it had a memory address.  It also stays at the same address all the way through.

Here's the entire class definition:

public ref class DnDListView : public ListView
{
public:
	DnDListView() { m_pDataSrc = new CMyOleDataSource(); }
	~DnDListView() { delete m_pDataSrc; }
	/** Override the OnItemDrag method to handle the native
	code used for virtual file DnD. */
	virtual void OnItemDrag(ItemDragEventArgs ^e) override
	{
		UINT uFileCount = this->SelectedItems->Count;
		UINT uBuffSize = sizeof(FILEGROUPDESCRIPTOR) + 
			(uFileCount-1) * sizeof(FILEDESCRIPTOR);
		HGLOBAL hFileDescriptor = GlobalAlloc ( 
			GHND | GMEM_SHARE, uBuffSize );
		if(hFileDescriptor)
		{
			FILEGROUPDESCRIPTOR* pGroupDescriptor = 
				(FILEGROUPDESCRIPTOR*) GlobalLock ( hFileDescriptor );
			if(pGroupDescriptor)
			{
				FILEDESCRIPTOR* pFileDescriptorArray = 
					(FILEDESCRIPTOR*)((LPBYTE)pGroupDescriptor + sizeof(UINT));
				pGroupDescriptor->cItems = uFileCount;
				int index = 0;
				m_pDataSrc->m_Files->RemoveAll();
				for (int i = 0; i < uFileCount; ++i)
				{
					ZeroMemory(&pFileDescriptorArray[index], 
						sizeof(FILEDESCRIPTOR));					
 
					pin_ptr<const wchar_t> wch = PtrToStringChars(this->SelectedItems[i]->Text);
 
					CString fileName(wch);
 
					lstrcpy ( pFileDescriptorArray[index].cFileName, fileName );
 
					m_pDataSrc->m_Files->Add(pFileDescriptorArray[index].cFileName);
					pFileDescriptorArray[index].dwFlags = FD_FILESIZE|FD_ATTRIBUTES;
					pFileDescriptorArray[index].nFileSizeLow = 512;
					pFileDescriptorArray[index].nFileSizeHigh = 0;
					pFileDescriptorArray[index].dwFileAttributes = FILE_ATTRIBUTE_NORMAL;
					index++;
				}
			}
			else
			{
				GlobalFree ( hFileDescriptor );
			}
		}
		GlobalUnlock ( hFileDescriptor );	
 
		FORMATETC etcDescriptor = { 
			RegisterClipboardFormat(CFSTR_FILEDESCRIPTOR), 
			NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL };
			m_pDataSrc->CacheGlobalData ( RegisterClipboardFormat(
				CFSTR_FILEDESCRIPTOR), hFileDescriptor, &etcDescriptor );
 
		FORMATETC etcContents = { 
			RegisterClipboardFormat(CFSTR_FILECONTENTS), 
			NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL };
 
		m_pDataSrc->DelayRenderFileData(
			RegisterClipboardFormat(CFSTR_FILECONTENTS), 
			&etcContents);
 
		DROPEFFECT dwEffect = m_pDataSrc->DoDragDrop ( 
			DROPEFFECT_COPY | DROPEFFECT_MOVE );			
 
		if(dwEffect == DROPEFFECT_NONE )
		{
			GlobalFree( hFileDescriptor );
		} 
	}
	
protected:
	CMyOleDataSource * m_pDataSrc;
 
};

Open in new window

Avatar of AngryLoop
AngryLoop

ASKER

To exand on that a little more - in the question details I included the CMyOleDataSource code, which derrives from COleDataSource.  If you need more details on that let me know.

Also, I'd be happy to send the entire project if you'd like - it's a Visual Stuido 2008 project.
Avatar of DanRollins
DanRollins
Flag of United States of America image

I apologize and must say that I'm out of my depth here.  It appears that you need to set drag-drop permissions, but I have no experience in doing that and can provide no guidence.
 
From:
     Control..DoDragDrop Method
     http://msdn.microsoft.com/en-us/library/system.windows.forms.control.dodragdrop.aspx ;

     Visual C++
      [UIPermissionAttribute(SecurityAction::Demand, Clipboard = UIPermissionClipboard::OwnClipboard)] public: DragDropEffects DoDragDrop( Object^ data, DragDropEffects allowedEffects )

=-=-=-=
One thing to try would be to see if the same error occurs if you change to:
     DROPEFFECT dwEffect=m_pDataSrc->DoDragDrop (DROPEFFECT_COPY);              

As I presume that might require a lower permission level (it cannot modify the source).
Avatar of AngryLoop
AngryLoop

ASKER

Control.DoDragDrop doesn't really apply since I'm using the "DoDragDrop" from COleDataSource and not a .NET control.

I tried changing the allowed effects to just copy and I still get the same errror.  If I look at the additional info for the error I get:
An unhandled exception of type 'System.AccessViolationException' occurred in VirtualDnDListView.dll

Additional information: Attempted to read or write protected memory. This is often an indication that other memory is corrupt.
Avatar of DanRollins
DanRollins
Flag of United States of America image

Here's the stange thing:  
   COleDataSource::DoDragDrop( ... )
is provided in the MFC source code.  That means that in a Debug Build, you should be able to single step INTO that code and find out where the error occurs.  But you say you get the error without seeing that source code, so something is peculiar.

There are actually several impementations of DoDragDrop in different objects.  I wonder if somehow your code is calling the wrong one (though I can't think of how that could be).  You could switch from C++ source code to ASM souce (View/Debug Windows/Disassembly) at the location of the function call and looking at that (and singlestepping it) that might provide a clue.
Avatar of AngryLoop
AngryLoop

ASKER

When I step through the ASM source here's what I get:
    DROPEFFECT dwEffect = m_pDataSrc->DoDragDrop (
          DROPEFFECT_COPY);
                  
00000384  mov         eax,dword ptr [ebp+FFFFFF74h]
0000038a  mov         esi,dword ptr [eax+00000160h]
00000390  push        0    
00000392  push        0    
00000394  mov         ecx,esi
00000396  mov         edx,1
0000039b  call        01672830               <---------- FAILS HERE
000003a0  mov         esi,eax
000003a2  mov         dword ptr [ebp-44h],esi
Avatar of DanRollins
DanRollins
Flag of United States of America image

It's odd that the disassembly shows only an address.  Are you working with a Build that has no symbolic information?  
DROPEFFECT n= cODS.DoDragDrop( DROPEFFECT_COPY );
00401C54   push        0
00401C56   push        0
00401C58   push        1
00401C5A   lea         ecx,[ebp-44h]
00401C5D   call        COleDataSource::DoDragDrop (00402dec)  <<--- the call, with symbolic name
00401C62   mov         dword ptr [ebp-48h],eax
129:
130:  }
00401C65   mov         dword ptr [ebp-4],0FFFFFFFFh

You need to be working with a Debug Build in order to diagnose these things.  
When I single-step into that call, I end up in an MFC Source code file named OLEDROP1.CPP
Avatar of AngryLoop
AngryLoop

ASKER

I'm working with a debug build - however I'm running it in conjunction with a C# application.  Or in other words - the C# application is referencing the C++/CLI DLL which contains the MFC code.  Both are running in debug mode of course when I'm looking at the code.  I'm really not sure why it's not loading the symbolic info.
ASKER CERTIFIED SOLUTION
Avatar of DanRollins
DanRollins
Flag of United States of America image

Blurred text
THIS SOLUTION IS ONLY AVAILABLE TO MEMBERS.
View this solution by signing up for a free trial.
Members can start a 7-Day free trial and enjoy unlimited access to the platform.
See Pricing Options
Start Free Trial
Avatar of AngryLoop
AngryLoop

ASKER

I was able to get it working.  I had to do a few changes related to the native code (which I first got working in purely C++) and then re-worked the C++/CLI interop code and it now works.

Thanks Dan for your excellent help!
Avatar of DanRollins
DanRollins
Flag of United States of America image

Thanks for the points and the grade :-)
The following "Grading Comment" was included and I've copied it here for the use of future PAQ searchers:
Grading Comments: I was able to get it working. I had to do a few changes related to the native code (which I first got working in purely C++) and then re-worked the C++/CLI interop code and it now works.

Thanks Dan for your excellent help!

C#
C#

C# is an object-oriented programming language created in conjunction with Microsoft’s .NET framework. Compilation is usually done into the Microsoft Intermediate Language (MSIL), which is then JIT-compiled to native code (and cached) during execution in the Common Language Runtime (CLR).

98K
Questions
--
Followers
--
Top Experts
Get a personalized solution from industry experts
Ask the experts
Read over 600 more reviews

TRUSTED BY

IBM logoIntel logoMicrosoft logoUbisoft logoSAP logo
Qualcomm logoCitrix Systems logoWorkday logoErnst & Young logo
High performer badgeUsers love us badge
LinkedIn logoFacebook logoX logoInstagram logoTikTok logoYouTube logo