[lnkForumImage]
TotalShareware - Download Free Software

Confronta i prezzi di migliaia di prodotti.
Asp Forum
 Home | Login | Register | Search 


 

Forums >

microsoft.public.dotnet.framework.interop

How to place a custom .NET control in clipboard for OLE data trans

krzys

8/4/2007 5:04:00 PM

Hi,

I'd like to insert a custom .NET control into clipboard as a part of OLE
drag and drop data transfer, or to be manually pasted something like Word or
Excel. My control otherwise works as an ActiveX (you can insert it manually
using "insert object" in Word, for example), but I have difficulties getting
it to "materialize" into a Word document via drag and drop. I'm getting an
error message shown below.

There is a problem saving the file. Usually this is because the disk or
floppy disk is too small for the file or is full, RAM memory is low, or there
is a permission problem with the drive the file is being saved to. If the
amount of disk space for a paging file is low, save the file to another
drive. If the RAM memory is low, increase available RAM. If permissions to
the drive do not allow you to save to that drive, save the file to another
drive or request permissions from the administrator to save files to the
drive.

Weirdly enough, my control gets pasted just fine into Wordpad or a Visio
document, but not to Word or Outlook. Once it gets pasted into Wordpad, you
can move it into Word just fine, though. But a direct transfer into Word or
Outlook fails.

Here's my code that attempts (and fails) at transferring my custom object
(here, object "counter1" is the AxctiveX .NET). I'm passing "Object
Descriptor" and "Embedded Object" clipboard formats, the former through
HGLOBAL and the latter via file on a disk, filled in with data using OleSave,
given the IPersistStorage of my .NET control as argument. My custom
DataObject just stores the references to memory or IStorage and copies them
to the recipient. I think reference counting is working just fine.

Here's the insertion code:
(it might get distorted by smileys, but you can find the good version at
http://www.cs.cornell..../embe...).


STGMEDIUM stm[2];
FORMATETC fe[2];

IUnknown *pUnkObject = (IUnknown *)
System::Runtime::InteropServices::Marshal::GetIUnknownForObject(counter1).ToPointer();
if (pUnkObject == NULL)
throw gcnew Exception("GetIUnknownForObject failed");

::IOleObject *pOleObject;
HRESULT hr = pUnkObject->QueryInterface(__uuidof(::IOleObject), (LPVOID FAR
*) &pOleObject);
if (FAILED(hr))
throw gcnew Exception("QueryInterface failed (" + hr.ToString("x") + ")");

CLSID objectclsid;
if (FAILED(pOleObject->GetUserClassID(&objectclsid)))
throw gcnew Exception("GetUserClassID failed.");

DWORD objectmiscstatus;
if (FAILED(pOleObject->GetMiscStatus(DVASPECT_CONTENT, &objectmiscstatus)))
throw gcnew Exception("GetMiscStatus failed.");

pOleObject->Release();

POINTL ptl;
ptl.x = 0;
ptl.y = 0;

SIZEL szl;
szl.cx = 200;
szl.cy = 200;

HGLOBAL hgDescriptor =
_AfxOleGetObjectDescriptorData(objectclsid, DVASPECT_CONTENT, szl, ptl,
objectmiscstatus,
OLESTR("a very nice live counter"), OLESTR("a nice drag and drop app"));

stm[0].tymed = ::TYMED_HGLOBAL;
stm[0].hGlobal = hgDescriptor;

fe[0].cfFormat = RegisterClipboardFormat(L"Object Descriptor");
fe[0].dwAspect = DVASPECT_CONTENT;
fe[0].ptd = NULL;
fe[0].tymed = ::TYMED_HGLOBAL;
fe[0].lindex = -1;

::IStorage *pIS;

hr = :Tongue TiedtgCreateDocfile(L"C:\\QuickSilver\\TEMP\\object.txt",
STGM_TRANSACTED | STGM_READWRITE | STGM_CREATE |
STGM_SHARE_EXCLUSIVE | STGM_DELETEONRELEASE, 0, &pIS);
if (FAILED(hr))
throw gcnew Exception("StgCreateDocfile failed (" + hr.ToString("x") + ")");

LPPERSISTSTORAGE pIPS;
hr = pUnkObject->QueryInterface(__uuidof(::IPersistStorage), (LPVOID FAR *)
&pIPS);
if (FAILED(hr))
throw gcnew Exception("QueryInterface for IPersistStorage failed (" +
hr.ToString("x") + ")");

:SurpriseleSave(pIPS, pIS, FALSE);
pIPS->SaveCompleted(NULL);
pIPS->Release();

stm[1].tymed = TYMED_ISTORAGE;
stm[1].pstg = pIS;

fe[1].cfFormat = RegisterClipboardFormat(L"Embedded Object");
fe[1].dwAspect = :Big SmileVASPECT_CONTENT;
fe[1].ptd = NULL;
fe[1].tymed = ::TYMED_ISTORAGE;
fe[1].lindex = -1;

::IDataObject *pDataObject;
hr = CreateDataObject(fe, stm, 2, &pDataObject);

if (hr == S_OK)
{
OleSetClipboard(pDataObject);
OleFlushClipboard();
pDataObject->Release();
}

GlobalFree(hgDescriptor);
pIS->Release();

The code for _AfxOleGetObjectDescriptorData is borrowed from "olemisc.cpp".

The code for the data object is based mostly on
http://www.codeproject.com/managedcpp/Ghost_drag..., and various
articles linkes to it. The code just copies the arguments to the recipient.

CDataObject::CDataObject(FORMATETC *fmtetc, STGMEDIUM *stgmed, int count)
{
m_lRefCount = 1;
m_nNumFormats = count;
m_pFormatEtc = new FORMATETC[count];
m_pStgMedium = new STGMEDIUM[count];
for(int i = 0; i < count; i++)
{
m_pFormatEtcIdea = fmtetcIdea;
m_pStgMediumIdea = stgmedIdea;
}
}


HRESULT __stdcall CDataObject::GetData(FORMATETC *pFormatEtc, STGMEDIUM
*pMedium)
{
int idx;
if ((idx = LookupFormatEtc(pFormatEtc)) == -1)
return DV_E_FORMATETC;
pMedium->tymed = m_pFormatEtc[idx].tymed;
pMedium->pUnkForRelease = 0;
switch (m_pFormatEtc[idx].tymed)
{
case ::TYMED_HGLOBAL:
pMedium->hGlobal = DupMem(m_pStgMedium[idx].hGlobal);
break;

case ::TYMED_ISTORAGE:
::CopyStgMedium(&m_pStgMedium[idx], pMedium);
break;

default:
return DV_E_FORMATETC;
}
return S_OK;
}

I'd appreciate any help with this...

Krzys
http://www.cs.cornell....