|
Try following this[^] KB article on MSDN .
Prasad
MS MVP - VC++
|
|
|
|
|
|
I have code that implements drag & drop for a ShowPicturesOnArrival event. The code works fine under Windows XP but fails under Vista with an:
Invalid FORMATETC structure
error. For completeness, the relevant Registry keys I've added are below. Items preceeded by a "v" are values for the above key, not subkeys.
HKEY_CLASSES_ROOT
MyApp
shell
open
DropTarget
v CLSID [REG_SZ] = {My-GUID}
HKEY_LOCAL_MACHINE
SOFTWARE
Classes
CLSID
{My-GUID}
v (default) [REG_SZ] MyApp
InprocServer32
v (default) [REG_SZ] = C:\path\to\My.dll
v ThreadingModel [REG_SZ] = Apartment
Microsoft
Windows
CurrentVersion
Explorer
AutoplayHandlers
EventHandlers
ShowPicturesOnArrival
v MyApp [REG_SZ]
Handlers
MyApp
v Action [REG_SZ] = "Copy pictures ..."
v DefaultIcon [REG_SZ] = C:\path\to\MyApp.exe,0
v InvokeProgID [REG_SZ] = MyApp
v InvokeVerb [REG_SZ] = open
v Provider [REG_SZ] = MyApp's name
My code follows. (Yes, I know it's a lot to look through, but any help much
appreciated. The failure occurs where the comment containing "fails" below
is.) First, I have a utility reference-counting class:
class LC_DLLRefCount {
public:
static ULONG get() {
return m_refCount;
}
protected:
LC_DLLRefCount() { ++m_refCount; }
~LC_DLLRefCount() { --m_refCount; }
private:
static ULONG volatile m_refCount;
};
ULONG volatile LC_DLLRefCount::m_refCount;
Next, my IClassFactory implementation:
class LC_ClassFactory : public IClassFactory, public LC_DLLRefCount {
public:
LC_ClassFactory() : m_refCount( 0 ) { }
ULONG STDMETHODCALLTYPE AddRef() {
return ++m_refCount;
}
ULONG STDMETHODCALLTYPE Release() {
ULONG const remaining = --m_refCount;
if ( !remaining )
delete this;
return remaining;
}
HRESULT STDMETHODCALLTYPE CreateInstance( IUnknown*, REFIID,
LPVOID* );
HRESULT STDMETHODCALLTYPE LockServer( BOOL );
HRESULT STDMETHODCALLTYPE QueryInterface( REFIID, LPVOID* );
private:
ULONG volatile m_refCount;
};
HRESULT STDMETHODCALLTYPE LC_ClassFactory::CreateInstance
( IUnknown *pUnkOuter, REFIID iid, LPVOID *ppv )
{
if ( ::IsBadWritePtr( ppv, sizeof( LPVOID ) ) )
return E_POINTER;
if ( pUnkOuter )
return CLASS_E_NOAGGREGATION;
*ppv = NULL;
LC_AutoplayHandler *const handler = new LC_AutoplayHandler();
if ( !handler )
return E_OUTOFMEMORY;
HRESULT result = handler->QueryInterface( iid, ppv );
if ( FAILED( result ) )
delete handler;
return result;
}
HRESULT STDMETHODCALLTYPE LC_ClassFactory::LockServer( BOOL lock ) {
if ( lock )
++m_refCount;
else
--m_refCount;
return S_OK;
}
HRESULT STDMETHODCALLTYPE LC_ClassFactory::QueryInterface
( REFIID iid, LPVOID *ppv )
{
if ( ::IsBadWritePtr( ppv, sizeof( LPVOID ) ) )
return E_POINTER;
if ( ::IsEqualIID( iid, IID_IUnknown ) )
*ppv = dynamic_cast<IUnknown*>( this );
else if ( ::IsEqualIID( iid, IID_IClassFactory ) )
*ppv = dynamic_cast<IClassFactory*>( this );
else {
*ppv = NULL;
return E_NOINTERFACE;
}
AddRef();
return S_OK;
}
Next, my IDropTarget implementation:
class LC_AutoplayHandler : public IDropTarget, public LC_DLLRefCount {
public:
LC_AutoplayHandler() : m_refCount( 0 ) { }
ULONG STDMETHODCALLTYPE AddRef() {
return ++m_refCount;
}
ULONG STDMETHODCALLTYPE Release() {
ULONG const remaining = --m_refCount;
if ( !remaining )
delete this;
return remaining;
}
HRESULT STDMETHODCALLTYPE QueryInterface( REFIID, LPVOID* );
HRESULT STDMETHODCALLTYPE Drop( LPDATAOBJECT, DWORD, POINTL,
PDWORD );
HRESULT STDMETHODCALLTYPE DragEnter( LPDATAOBJECT, DWORD, POINTL,
PDWORD );
HRESULT STDMETHODCALLTYPE DragLeave();
HRESULT STDMETHODCALLTYPE DragOver( DWORD, POINTL, PDWORD );
private:
ULONG volatile m_refCount;
};
HRESULT STDMETHODCALLTYPE LC_AutoplayHandler::DragEnter
( LPDATAOBJECT, DWORD, POINTL, PDWORD pEffect )
{
*pEffect = DROPEFFECT_COPY;
return S_OK;
}
HRESULT STDMETHODCALLTYPE LC_AutoplayHandler::DragLeave() {
return S_OK;
}
HRESULT STDMETHODCALLTYPE LC_AutoplayHandler::DragOver
( DWORD, POINTL, PDWORD pEffect )
{
*pEffect = DROPEFFECT_COPY;
return S_OK;
}
HRESULT STDMETHODCALLTYPE LC_AutoplayHandler::Drop
( LPDATAOBJECT pDO, DWORD, POINTL, PDWORD )
{
UINT autoplayShellIDLists = ::RegisterClipboardFormat(
TEXT("Autoplay Enumerated IDList Array")
);
if ( !autoplayShellIDLists )
return ::GetLastError();
FORMATETC formatEtc = {
autoplayShellIDLists, NULL, DVASPECT_CONTENT, -1,
TYMED_HGLOBAL
};
STGMEDIUM medium = { 0 };
HRESULT result = pDO->GetData( &formatEtc, &medium );
if ( FAILED( result ) )
return result;
::ReleaseStgMedium( &medium );
return result;
}
HRESULT STDMETHODCALLTYPE LC_AutoplayHandler::QueryInterface
( REFIID iid, LPVOID *ppv )
{
if ( ::IsBadWritePtr( ppv, sizeof( LPVOID ) ) )
return E_POINTER;
if ( ::IsEqualIID( iid, IID_IUnknown ) )
*ppv = dynamic_cast<IUnknown*>( this );
else if ( ::IsEqualIID( iid, IID_IDropTarget ) )
*ppv = dynamic_cast<IDropTarget*>( this );
else {
*ppv = NULL;
return E_NOINTERFACE;
}
AddRef();
return S_OK;
}
Finally, my Dll* functions implementation:
#define LC_DLL_EXPORT(T) extern "C" __declspec(dllexport) T __stdcall
LC_DLL_EXPORT(HRESULT) DllCanUnloadNow() {
bool const canUnload = LC_DLLRefCount::get() == 0;
return canUnload ? S_OK : S_FALSE;
}
LC_DLL_EXPORT(HRESULT) DllGetClassObject( REFCLSID clsid, REFIID iid,
LPVOID *ppv ) {
if ( !::IsEqualCLSID( clsid, LC_AP_GUID ) )
return CLASS_E_CLASSNOTAVAILABLE;
if ( ::IsBadWritePtr( ppv, sizeof( LPVOID ) ) )
return E_POINTER;
*ppv = NULL;
LC_ClassFactory *const factory = new LC_ClassFactory();
if ( !factory )
return E_OUTOFMEMORY;
factory->AddRef();
HRESULT result = factory->QueryInterface( iid, ppv );
factory->Release();
return result;
}
Are there any mistakes in the above code but it just happens to work in XP but not Vista? How can this be made to work in Vista? Thanks.
- Paul
|
|
|
|
|
|
Please notice:
This is the C omponent O bject M odel forum (Not the serial communication one).
pra84veen wrote: the moment when i connect to the module
What module are you talking about?
If the Lord God Almighty had consulted me before embarking upon the Creation, I would have recommended something simpler.
-- Alfonso the Wise, 13th Century King of Castile.
This is going on my arrogant assumptions. You may have a superb reason why I'm completely wrong.
-- Iain Clarke
|
|
|
|
|
Hi,
instead of IViewObject i am using IViewObject2 for printing my activex control. But i am able to see a black image instead of my control. This is my code.
void CPrintControlView::PrintControlUsingScreen(CWnd *pWnd, CDC* pDC, CPrintInfo* pInfo)
{
// get the IUnknown pointer for the chart object (note, don't release this one per MSDN)
LPUNKNOWN pUnk = pWnd->GetControlUnknown();
if (!pUnk)
{
AfxMessageBox(_T("Not an ActiveX Control"));
return;
}
// get a reference to the drawing rectangle
CRect &rcPage = pInfo->m_rectDraw;
// maximize the image based on our drawing area, but keep the aspect ratio unchanged
CRect rect;
pWnd->GetClientRect(&rect);
float grph_xyratio = (float) rect.Width() / (float) rect.Height();
float page_xyratio = (float) rcPage.Width() / (float) rcPage.Height();
// determine the limiting dimension
float width, height;
if (grph_xyratio > page_xyratio)
{
// the x dimension is the limiting factor
width = (float) rcPage.Width();
height = rcPage.Width() / grph_xyratio;
}
else
{
// the y dimension is the limiting factor
height = (float) rcPage.Height();
width = rcPage.Height() * grph_xyratio;
}
// build the rectangle to print in
RECTL rectPrn;
rectPrn.top = 0;
rectPrn.left = 0;
rectPrn.right = rect.Width() - 1;
rectPrn.bottom = rect.Height() - 1;
// get the dc of the current display
CDC dc;
HDC hdc = ::GetDC(m_hWnd);
dc.Attach(hdc);
// offscreen memory and bitmap support
CDC dcMem;
CBitmap bmpMem;
CBitmap *oldbm = NULL;
LPVOID lpvBits = NULL;
// save the device context
pDC->SaveDC();
// do the drawing
HRESULT hRes = S_OK;
try
{
// create a memory device context for offscreen drawing
if (!dcMem.CreateCompatibleDC(&dc))
_com_issue_error(HRESULT_FROM_WIN32(::GetLastError()));
if (!bmpMem.CreateCompatibleBitmap(&dc, rect.Width(), rect.Height()))
_com_issue_error(HRESULT_FROM_WIN32(::GetLastError()));
oldbm = dcMem.SelectObject(&bmpMem);
IViewObject* temp = NULL;
hRes = pUnk->QueryInterface(IID_IViewObject2, (void **) &temp);
if (FAILED(hRes)) _com_issue_error(hRes);
// draw the object into our screen device context
hRes = temp->Draw(DVASPECT_CONTENT, //DOCPRINT,
-1, NULL, NULL,dcMem ,
((CMetaFileDC*)pDC)->m_hDC, //hdcMem,
&rectPrn,NULL, NULL, 0);
if (FAILED(hRes)) _com_issue_error(hRes);
// delesect the device dependent bitmap from the offscreen device context (must be out when GetDIBits is called)
dcMem.SelectObject(oldbm);
// get the header structure for a device independent bitmap (DIB) setup with the biggest possible palette
BITMAPINFO *bmi = (BITMAPINFO *) _alloca(sizeof(BITMAPINFOHEADER) + 256 * sizeof(RGBQUAD));
memset(&bmi->bmiHeader, 0, sizeof(BITMAPINFOHEADER));
bmi->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
// query for the bitmap information (NULL does a query)
int scanLineCount = GetDIBits(dcMem, bmpMem, 0, rect.Height(), NULL, bmi, DIB_RGB_COLORS);
if (!scanLineCount)
_com_issue_error(HRESULT_FROM_WIN32(::GetLastError()));
// allocate memory for the bitmap bits
lpvBits = new char[bmi->bmiHeader.biSizeImage];
if (!lpvBits)
_com_issue_error(HRESULT_FROM_WIN32(ERROR_OUTOFMEMORY));
// convert the device dependent bitmap to the DIB
// (See knowledge base article Q195830 for details)
scanLineCount = GetDIBits(dcMem, bmpMem, 0, rect.Height(), lpvBits, bmi, DIB_RGB_COLORS);
if (!scanLineCount)
_com_issue_error(HRESULT_FROM_WIN32(::GetLastError()));
// transfer the device independent bitmap to our printer device context
if (GDI_ERROR == StretchDIBits(pDC->m_hDC, rcPage.left, rcPage.top, (int) width, (int) height, 0, 0, rect.Width(), rect.Height(), lpvBits, bmi, DIB_RGB_COLORS, SRCCOPY))
_com_issue_error(HRESULT_FROM_WIN32(::GetLastError()));
}
catch (_com_error & e)
{
ErrorMessage(e.Error(), (LPCTSTR) e.Description());
}
}
What should i do
Regards
|
|
|
|
|
i,
I am able to print mschar control with IViewObject. But I am not able to print my activex control. HRESULT is returning zero but i am not able to see anything on the screen. Should i need to make any changes to my activex control so that it can print
Regards
|
|
|
|
|
i fixed the problem. i did not set the setmapmode in the activex control. after setting the setmap mode to himetric i am able to print the activex control. but it is printing with blackbackground. can anybody tell me the problem
|
|
|
|
|
I am printing activex controls. I was not able to print them. Last week i posted the problem in com forum. I found the solution. we have 4 legacy activex controls. out of them i am able to print two of them. One is raising one of the parameter is incorrect and another is printing with black background image. This is my problem. can any one tell where i have to look in the activex control code
|
|
|
|
|
Hi everyone,
I am using Microsoft Comm control ActiveX control in My program.I am not getting How to use that in proper way.Isearched in net i am not getting on VC++.
when i inserted com control into my program Two files are added they are mscomm.cpp and mscomm.h.I dont know the events of mscomm.In vb we have events like
commEvRecv and send.But i am not getting like that events in VC++ please tell me How To do that..I am in tension.Please help me.please give me some VC++ examples or articles in VC++.
Please...
Thanks in Advance,
Savitri.
|
|
|
|
|
Click here ->[^]
its an ATL tutorial and very helpful for you.
Yes U Can ...If U Can ,Dream it , U can do it ...ICAN
|
|
|
|
|
i have a com component exe. the methods exhibited by it are called thru javascript.
when the object is created, the exe is started and methods are called and then exe is exited. this works fine. but sometime the exe does not exit and remains in memory and the webpage calling it hangs.
is there any solution to this problem? is there a method by which i can terminate exe or destroy the object created?
some light on this is highly appreciated
|
|
|
|
|
Where is the application hanging?!
Steve
|
|
|
|
|
I created a simple ATL COM DLL in Visual C++ 6.0. I added a new ATL object and added a new method. The method simply does the following:
STDMETHODIMP CThrowErr::Throw()
{
return Error("Error desc", GetObjectCLSID());
}
I set the project properties to enable exception handling. This DLL compiles without and errors or warnings.
Next I created a new VB6.0 project and added reference to this DLL. Then I created an object of this class and invoked this method. This call is surrounded by On Error goto:
Private Sub Form_Load()
On Error GoTo ex
Dim e As New ThrowErr
e.Throw
Exit Sub
ex:
MsgBox Err.Description
Unload Me
End Sub
I should be seeing Error desc . If I compile and run the binary I get Method '~' of object '~' failed . If I run it in debug I get Method 'Throw' of object 'IThrowErr' failed . If I set a breakpoint on MsgBox Err.Description and watch description I get Automation error Exception occurred.
How can I get the error description to VB? Am I doing something wrong or am I missing something?
Any help would be highly appreciated. Thanks in advance.
|
|
|
|
|
Well I found the answer to this. The ATL object was not supporting the IErrorInfo interface. Once this was fixed the problem went away.
|
|
|
|
|
I need some help on creating a borderless sizable child window. I have been able to do it with the windows WS_SIZEBOX style but would like not to see the border until the mouse pointer moves over the child.
Thanks
Lenny
|
|
|
|
|
And what has it to do with COM ?
If the Lord God Almighty had consulted me before embarking upon the Creation, I would have recommended something simpler.
-- Alfonso the Wise, 13th Century King of Castile.
This is going on my arrogant assumptions. You may have a superb reason why I'm completely wrong.
-- Iain Clarke
|
|
|
|
|
hi all,
i am having a COM dll and which is in memory. for unregistering it i use regsvr32 -u 'path'. and loaded the same dll from different location by regsvr32 'newpath'. All this i am doing through code in C++. But when i try to get the module path by calling GetModuleFileName() api it returns me the old path not the newly registered path. So is it because of the old dll is still in memory or something else and if its still in memory how to remove that from memory or am i missing something ???
|
|
|
|
|
sandeepkavade wrote: But when i try to get the module path by calling GetModuleFileName()
How do you call it? I mean, usually you haven't the HINSTANCE of a COM DLL .
If the Lord God Almighty had consulted me before embarking upon the Creation, I would have recommended something simpler.
-- Alfonso the Wise, 13th Century King of Castile.
This is going on my arrogant assumptions. You may have a superb reason why I'm completely wrong.
-- Iain Clarke
|
|
|
|
|
i am creating the object using CoCreateInstance(). but before that i am doing all the registeration and unregisteration. Does regsvr32 -u 'path' removes the dll from memory? i think thats what creating all problems?
|
|
|
|
|
sandeepkavade wrote: i am creating the object using CoCreateInstance()
And then how could you use GetModuleFileName ?
sandeepkavade wrote: Does regsvr32 -u 'path' removes the dll from memory?
Nope. Registration means: put this f*ing COM class inside the registry (well, roughly speaking...). After registering a COM component, the COM runtime will load the registered DLL when asked by a client (i.e. whenever the client calls CoCreateInstance for such component).
If the Lord God Almighty had consulted me before embarking upon the Creation, I would have recommended something simpler.
-- Alfonso the Wise, 13th Century King of Castile.
This is going on my arrogant assumptions. You may have a superb reason why I'm completely wrong.
-- Iain Clarke
|
|
|
|
|
I am using GetModuleFileName() as fallows.
void GetModulePath(const TCHAR *strModuleName, CString &strModulePath)
{
TCHAR modulePath[_MAX_PATH];
HMODULE hModule = GetModuleHandle(strModuleName);
if( hModule != NULL )
{
GetModuleFileName(hModule, modulePath, _MAX_PATH);
TCHAR* slashPos = _tcsrchr(modulePath, _TCHAR('\\'));
if (slashPos != NULL)
*slashPos = NULL; // Terminate the string here.
strModulePath = CString(modulePath);
}
else
{
// DO ERROR HANDLING HERE
CString strError;
GetErrorText(GetLastError(), strError);
// Log the error;
}
}
|
|
|
|
|
Well it looks correct. Have you checked corrensponding registry entries?
If the Lord God Almighty had consulted me before embarking upon the Creation, I would have recommended something simpler.
-- Alfonso the Wise, 13th Century King of Castile.
This is going on my arrogant assumptions. You may have a superb reason why I'm completely wrong.
-- Iain Clarke
|
|
|
|
|
Sorry for delayed reply. As per your suggestion i checked the registry entries but i havent seen any problems in that they are getting updated before and after unregistering/registering.
|
|
|
|
|
Can't you include some debugging info (i.e. output to debugger, to file, ...) in your COM DLL to distinguish between the two ones at runtime?
If the Lord God Almighty had consulted me before embarking upon the Creation, I would have recommended something simpler.
-- Alfonso the Wise, 13th Century King of Castile.
This is going on my arrogant assumptions. You may have a superb reason why I'm completely wrong.
-- Iain Clarke
|
|
|
|
|