COM/OLE question: Is this bad practice?

Started by
3 comments, last by JonW 13 years, 3 months ago
Hi,

I've been using a multi-threaded COM apartment for my application's threads in order to achieve the best performance I can for anything that uses COM.

However I recently wanted to add support for drag and drop to my program window. Windows uses OLE for this type of operation. According to MSDN, "applications that use the following functionality must call OleInitialize before calling any other function in the COM library:
Clipboard
Drag and drop
Object linking and embedding (OLE)
In-place activation"

Okay fine, so I have to call OleInitialize. The problem is, OleInitialize wants to put the thread into a single-threaded apartment: "OleInitialize calls CoInitializeEx internally to initialize the COM library on the current apartment. Because OLE operations are not thread-safe, OleInitialize specifies the concurrency model as single-thread apartment."

Since I want to be able to stick with an MTA for the rest of the application, I decided to create a separate thread running in an STA for the express purpose of handling drag and drop requests. The thread registers the main window as a drop target and then sits and pumps messages for OLE (which is required in a STA). When it gets the signal to quit, it removes drag and drop support from the main window and exits:


//////////////////////////////////////////////////////////////////////////// Thread procedure for running OLE drag and drop. We use a separate thread// because OLE's drag and drop feature requires a single-threaded COM// apartment, and we want our application to be able to use a multi-threaded// apartment.uint __stdcall ThreadProc(void *arguments){	// Applications that use drag and drop must call OleInitialize before calling any other function in the COM library. 	OleInitialize(NULL);	CDropTarget *target;	try	{		target = new CDropTarget();	}	catch (bad_alloc)	{		StatusLog_ReportOutOfMemory();		OleUninitialize();		_endthreadex(0);		return 0;	}	// The CoLockObjectExternal function prevents the reference count of an object	// from going to zero, thereby "locking" it into existence until the lock is	// released.	CoLockObjectExternal(target, TRUE, FALSE);	// Tell OLE that the window is a drop target.	HRESULT hResult = RegisterDragDrop(g_hMainWnd, target);	if (hResult != S_OK)		StatusLog_ReportWarning(L"Drag and Drop", L"Unable to register drag and drop (error code %d).", hResult);	// Each single-threaded apartment must have a message loop to handle calls from other	// processes and apartments within the same process. If we didn't have this message loop,	// we would hang other applications that are acting as drag-drop sources for us because	// their message could not get handled.	while (MsgWaitForMultipleObjects(1, &g_hEvtStopThread, FALSE, INFINITE, QS_ALLINPUT))	{		MSG msg;		if (GetMessage(&msg, NULL, NULL, NULL) <= 0)			break;		TranslateMessage(&msg);		DispatchMessage(&msg);	}	// Remove drag and drop from the window.	RevokeDragDrop(g_hMainWnd);	// Remove the strong lock.	CoLockObjectExternal(target, FALSE, TRUE);	// Release our own reference.	target->Release();	OleUninitialize();	// Calling end is not strictly necessary but according to MSDN is a good practice.	_endthreadex(0);	return 0;}


My question is: Is it a bad practice to setup OLE on a dedicated thread like this and give it a handle to the main window running on the original thread? The application runs fine but I'm nervous that I've opened the door to some sort of concurrancy issue or other evil thing.

I know this is probably a difficult question to answer because the RegisterDragDrop function's documentation doesn't include any details on this, but I'm curious as to whether anyone else is familiar with doing something like this as a general OLE practice.

Thanks!!
Advertisement
You might have if the threads have the same priority status. I think you would need to decide which thread to run first. I would think that the original or 'Main' window is the most important & should have priority over the OLE stuff. I think you need to look at how to set the priority of the threads that you have running. By doing this, I believe the stability of you program increase.
What would the potential negative consequence be of both threads having the same priority? Some sort of deadlock situation?
No the first thread created would be done first then the 2nd. Think FIFO(First in First Out). I think it really depends on how much control you want to have in your program. Technically nothing wrong could happen if you just forget about thread priority for this program you wrote. In the future though if your running thread process that depend on one another. Then I could see problems happening.
Thanks for the quick responses. Actually the main process thread starts with the program, it starts the OLE drag-and-drop thread at the early onset, and when the user closes the program, the main process thread tells the OLE thread to close and waits for it to close before exiting.

The drag-and-drop thread sits in its message pump just like the main thread (as required when existing in a single-threaded COM apartment) and dispatches messages to the invisible window that OLE creates for its own use.

My question basically is whether or not it is okay to pass the main window's handle, which is "owned" by the process thread, to the OLE registration function in the drag-and-drop thread. OLE is then working with the main window, but from a second thread--I'm not sure if this is proper or not.


This topic is closed to new replies.

Advertisement