This is somewhat related to another question that I've asked that I've pretty much figured out. The last piece of the puzzle is using CoCreateInstance() instead of GetActiveObject(). I don't want to use an existing instance of EnvDTE, so I call CoCreateInstance, which properly fires off a new instance of VisualStudio. CoCreateInstance() calls AddRef() and I store the output pointer in a CComPtr, which properly calls Release on destruction. When this Release() happens, lo and behold the instance of VS closes! Of course it does because the refcount is at zero. What I'm wanting to do is have the new process own that last instance, so when the user closes VS with the Close (X) button it will destroy the COM object.
There are a few things I have tried:
1. Calling Detach() on my CComPtr, so the object lives on. Sure it works, however, closing VS with the close button doesn't actually kill the process (it's still running in the Task Manager list).
2. Launch a separate process of VS and then use ROT to find the new instance. This is ugly because I have to wait an indeterminate amount of time for the application to launch before trying to find the new instance of the COM object.
3. Use a global or static CComPtr, and manually destroy the object when my app closes. I'd rather not do it this way.
So, I've figured this out for the specific case of creating an VisualStudio.DTE object using CoCreateInstance. The DTE object returned has a UserControl property, which can be set to TRUE. When you set this to TRUE, then a Release() of the CComPtr that holds the DTE object doesn't destroy the instance:
#define RETURN_ON_FAIL( expression ) \
result = ( expression ); \
if ( FAILED( result ) ) \
return false; \
else // To prevent danging else condition
HRESULT result;
CLSID clsid;
CComPtr<IUnknown> punk = NULL;
CComPtr<EnvDTE::_DTE> dte = NULL;
RETURN_ON_FAIL( ::CLSIDFromProgID(L"VisualStudio.DTE", &clsid) );
RETURN_ON_FAIL( ::CoCreateInstance( clsid, NULL, CLSCTX_LOCAL_SERVER, EnvDTE::IID__DTE, (LPVOID*)&punk ) );
dte = punk;
dte->put_UserControl( TRUE );
Look at WindowClosing Event. You could subscribe to that event and when the event is fired call Release(). This will require you to determine which window events to subscribe to.
Related
So I am trying to put together a simple fullscreen OpenGL application using CGL and IOHIDManager in order to learn the lower-level APIs. Currently, I am creating an OpenGL context and starting it fullscreen. I am trying to now add keyboard input so I can quit the app. I've found many similar examples of using IOHIDManager to read keys, but no matter what I do my callback does not fire.
My callback is just a function that prints "here". I'm not sure where I am going wrong -- I've tried both CFRunLoopGetCurrent() and CFRunLoopMain(). My main is simply a while loop. What gives?
CFMutableDictionaryRef CreateMatchingDictionary(UInt32 usage_page, UInt32 usage) {
CFMutableDictionaryRef dictionary = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, &kCFCopyStringDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
CFNumberRef page_number = CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType, &usage_page);
CFDictionarySetValue(dictionary, CFSTR(kIOHIDDeviceUsagePageKey), page_number);
CFRelease(page_number);
CFNumberRef usage_number = CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType, &usage);
CFDictionarySetValue(dictionary, CFSTR(kIOHIDDeviceUsageKey), usage_number);
CFRelease(usage_number);
return dictionary;
}
void CreateInputManager() {
IOHIDManagerRef hid_manager = IOHIDManagerCreate(kCFAllocatorDefault, kIOHIDOptionsTypeNone);
CFMutableDictionaryRef matching_dictionary = CreateMatchingDictionary(kHIDPage_GenericDesktop, kHIDUsage_GD_Keyboard);
IOHIDManagerSetDeviceMatching(hid_manager, matching_dictionary);
IOHIDManagerRegisterInputValueCallback(hid_manager, KeyboardCallback, NULL);
IOHIDManagerOpen(hid_manager, kIOHIDOptionsTypeNone);
IOHIDManagerScheduleWithRunLoop(hid_manager, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode);
}
void KeyboardCallback(void *context, IOReturn result, void *sender, IOHIDValueRef value) {
puts("CALLBACK!");
}
int main() {
// Commented out CGL context & fullscreen window creation
CreateInputManager();
while(true) {
;
}
}
UPDATE
If I put CFRunLoopRun() at the end of function CreateInputManager, my callback is called but the function never returns. How is this supposed to work in a single-threaded CGL app? Is it a strict requirement that IOHIDManager requires a run loop to function?
IOKit and HID work via Mach messaging, which in turn is deeply integrated with the runloop mechanism, as you've found. If you really do want to busy-poll, you can use the CFRunLoopRunInMode function with a zero timeout to check for events.
You may wish to consider using a CVDisplayLink to invoke your rendering code on every vertical frame refresh instead. The display link's callback will be called from the runloop, so you can leave your main thread running in CFRunLoopRun().
See https://developer.apple.com/library/mac/qa/qa1385/_index.html for how Apple recommends you structure event handling in OpenGL applications.
Turns out I need to create a separate pthread with the CreateInputManager function, specify that the IOHIDManager is to schedule the callback on CFRunLoopGetCurrent() and kick off a run loop on that thread by calling CFRunLoopRun().
I wonder if there is a way to get IOHIDManager to work with plain-old polling instead of these callbacks...
Anybody got this problem, anyway I didn't find an answer. The code is simple:
void CbDlg::OnBnClickedOk()
{
for(int i=0; i<1000; i++)
{
HRSRC hRes = ::FindResource(NULL, MAKEINTRESOURCE(IDR_MAINFRAME), RT_GROUP_ICON);
HGLOBAL hResLoad = ::LoadResource(NULL, hRes);
BYTE* pIconBytes = (BYTE*)::LockResource(hResLoad);
int nId = ::LookupIconIdFromDirectory(pIconBytes, TRUE);
hRes = ::FindResource(NULL, MAKEINTRESOURCE(nId), RT_ICON);
DWORD read = ::SizeofResource(NULL ,hRes);
hResLoad = ::LoadResource(NULL, hRes);
pIconBytes = (BYTE*)::LockResource(hResLoad);
if(pIconBytes != NULL)
{
HICON hIcon = ::CreateIconFromResource(pIconBytes, read, TRUE, 0x00030000);
DWORD e = ::GetLastError();
if(hIcon != NULL)
{
::DestroyIcon(hIcon);
}
}
}
}
If I click the Ok button four times (On my computer), CreateIconFromResource start to return NULL (It worked fine before and I could even draw out the icon). As to the GetLastError, it's always return 6 whatever CreateIconFromResource return NULL or not.
When this problem happened, if I drag the title bar to move, UI crashed, see the pictrue.
Of course you can understand this piece of code is just a demo, my real business need to call CreateIconFromResource thousands of times just like this.
UPDATE:
According to Hans' suggestion, I keep tracking the Handles/USER Objects/GDI objects, and found that USER Objects grows 1000 and GDI objects grows 2000 against each clicking to OK button (handles didn't grow), and GDI objects is 9999 when problem happens. But how to release them correctly, when I finish to use? I didn't use that much at one time, but need to load, release, load again, release again... Just like this demo. As MSDN document, I called DestroyIcon for every HICON. What else do I need to do, to finally release the USER/GDI objects?
I found the answer. The success or failure is all due to MSDN.
It says:
"The CreateIconFromResource function calls CreateIconFromResourceEx passing LR_DEFAULTSIZE|LR_SHARED as flags" AND "Do not use this function(DestroyIcon) to destroy a shared icon"
But It also says:
"When you are finished using the icon, destroy it using the DestroyIcon function" in CreateIconFromResource's document.
Actually, the second statement is WRONG.
So, the solution is, using CreateIconFromResourceEx without LR_SHARED, and DestroyIcon every HICON after using.
So I am working on making my own wrapper class that can quickly and easily produce both custom (user defined) windows and provided (system defined) windows and allows for a custom WndProc for each. I have it set up fine aside from trying to super class the button class. I have tried several different iterations of trying to set up the super class (in terms of what I am setting to NULL and what I am redefining in the WNDCLASSEX) but no matter what I do, when it goes to register the new class I have defined in the WNDCLASSEX structure, it tells me "Error the parameter is incorrect." I tried switching to a basic Win32 project that creates just creates a blank window to see if I could implement the super classing technique in there but the error persists and I have no idea why. The relevant code is:
WNDCLASSEX wc;
ZeroMemory( &wc, sizeof(WNDCLASSEX) );
GetClassInfoEx( GetModuleHandle( NULL ), L"Button", &wc );
SetOldProc( (LONG_PTR)wc.lpfnWndProc );
wc.lpszClassName = L"myButton";
wc.hInstance = GetModuleHandle( NULL );
wc.lpszMenuName = NULL;
wc.lpfnWndProc = AbstractWindow::msgRouter;
if ( !RegisterClassEx( &wc ) )
{
::FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM,
NULL,
GetLastError(),
MAKELANGID(LANG_NEUTRAL,SUBLANG_DEFAULT),
lpBuffer,
sizeof(lpBuffer)-1,
NULL);
MessageBox (NULL, lpBuffer, L"Button", MB_ICONERROR) ;
return 0 ;
}
The SetOldProc is a method within the wrapper class I am making that stores the pointer to the original button WndProc and the AbstractWindow::msgRouter is the WndProc in the base class for my wrapper class that routes messages to the correct window classes when they are received. Custom classes within the wrapper classes work just fine the way the wrapper classes are set up and like I said, I have tried multiple variations of what variables in the WNDCLASSEX structure I change, including only giving it a name and instance, but everything I try just gives me the same error even if it is in a bare bones project and I have no idea what I'm doing wrong. Corrections to the code, tips for super classing, etc. are all welcome even if it isn't directly relevant to fixing my problem because I always like to learn more but if you have a solution please share it.
I have a GUI window in WTL that runs inside a thread inside a CMessageLoop instance which has been added to the application instance and runs. Now, inside a button handler within the main GUI I create a new window. Once I click that button and create the window and try to post the quit message to the main GUI loop. The code:
Main window, has its own thread:
CMessageLoop theLoop;
_MyppModule.AddMessageLoop(&theLoop);
if(m_pMyDlg == NULL) {
m_pMyDlg = new CMyDlg();
if(!IsWindow(*m_pMyDlg))
{
m_pMyDlg->Create(NULL);
m_pMyDlg->ShowWindow(SW_SHOW);
nRet = theLoop.Run();
_MyppModule.RemoveMessageLoop();
}
}
Button handler & child window creation:
LRESULT CMyDlg::OnButtonClicked(WORD wNotifyCode, WORD wID, HWND hWndCtl, BOOL& bHandled)
{
ChildWindowDlg childDlg;
childDlg.Create(m_hWnd);
childDlg.ShowWindow(SW_SHOW);
CMessageLoop _loop;
);
_loop.Run();
::DestroyWindow(childDlg);
return S_OK;
}
Now, if I click the Close button in my MyDlg window the button's handler will get called, inside it I do ::PostQuitMessage but that never reaches the theLoop messageloop from the first code snippet.
This happens after I exit the second loop, so _loop gets destroyed and the child dialog is destroyed.
What is happening here?
You have two message loops here, the child's one is nested. On the other hand, the message queue is one per thread, and is pumped by the most inner message loop (with GetMessage). So, WM_QUIT message gets retrieved by the inner message loop inside CMyDlg::OnButtonClicked.
The second code snippet is totally unnatural. If your goal is to have a window popped up, then closed and and then you want to complete execution of your button click handler, then modal dialog is what you need:
LRESULT CMyDlg::OnButtonClicked(WORD wNotifyCode, WORD wID, HWND hWndCtl,
BOOL& bHandled)
{
ChildWindowDlg childDlg; // Add constructor parameters if needed
// Additional initlaization calls might go here
const INT_PTR nResult = childDlg.DoModal(m_hWnd); // DoModal handles it all
if(nResult == IDOK) { ... } // Hey's we even have result coming from `EndDialog`
return 0; // No S_OK here
}
No message loops, no PostQuitMessage, no separate window creation/destruction calls needed. This is what modal dialogs are for.
If you don't want to block "calling" window, and the idea is to have both master and slave windows running side by side (or, one is a part of another, anyway both to be responsive at the same time), then you don't want to block your message handler. The handler will create window and set it up (.Create, .ShowWindow) and then exit from OnButtonClicked function.
Both windows are created, both are alive and have their message sent to them by top level message loop. This is the correct approach, you don't normally need more than one message loop per thread. Sometimes it might make sense for specific operations, but this is really rare. Windows are passive instances. They respond to messages with their message handlers. A thread message loop serves all thread windows, because what it does is DispatchMessage API call, which in turn looks for target window, takes its WndProc and calls it handing message details in.
I'm using Actionscript 2.0 for a mobile phone and can't get my head around Events.
I'm creating a class object with all my code and using a group of functions (all as direct 1st level children of the class). There's one function that creates a Movieclip with a square on it and sets the onPress event to another function called hit:
public function draw1Sqr(sName:String,pTL:Object,sSide:Number,rgb:Number){
// create a movie clip for the Sqr
var Sqr:MovieClip=this.canvas_mc.createEmptyMovieClip(sName,this.canvas_mc.getNextHighestDepth());
// draw square
Sqr.beginFill(rgb);
//etc ...more lines
//setup properties (these are accessible in the event)
Sqr.sSide=sSide;
Sqr.sName=sName;
//setup event
Sqr.onPress = hit; // this syntax seems to lead to 'this' within
// the handler function to be Sqr (movieclip)
//Sqr.onPress = Delegate.create(this, hit);
//I've read a lot about Delegate but it seems to make things harder for me.
}
Then in my event handler, I just cannot get the scope right...
public function hit(){
for (var x in this){
trace(x + " == " + this[x]);
}
//output results
//onPress == [type Function]
//sName == bSqr_7_4
//sSide == 20
trace(eval(this["._parent"])); //undefined
trace(eval(this["._x"])); //undefined
}
For some reason, although the scope is set to the calling object (Sqr, a Movieclip) and I can access properties I defined, I can't use the 'native' properties of a Movieclip object.
Any suggestions on how I can access the _x, _y and other properties of the Movieclip object that is pressed.
Use the array accessor or the dot accessor, but not both. For example:
trace(this._parent); // OR
trace(this["_parent"]);
As for the results of your iteration, I recall AS2 being screwy on this front. IIRC only dynamic properties are returned when looping with for ... in. This prevents Objects (which often serve as hash maps) from including their native properties when all you want are the key/value pairs you set yourself.
Also - the eval() function can be easily overused. Unless you absolutely must execute a String of AS2 that you don't have at compile-time I would recommend avoiding it. Happy coding!