C++ Builder: Refresh FireMonkey Visual Component - c++

I have a problem with C++ Builder and FireMonkey. I am creating a mobile application connected with a Datasnap Rest WebService. Some requests are a little bit long so I want to display a waiting message. Here is my code:
lbl_testConnexion->Text = "Please Wait...";
lbl_testConnexion->TextSettings->FontColor = TAlphaColorRec::Red;
this->Invalidate();
//Call to the Web Service
list<Colis>* l = WS->getListeColis("00DP0097");
lbl_testConnexion->Text = "Success!";
I tried functions Form->Invalidate() and Label->Repaint() but only the last text is displayed.
What can I do to dynamically refresh the Label in my function?

The change of the text has to be handled by the main thread which is blocked by the request. If you don't want to use a seperate thread for long requests you have to call Application->ProcessMessages().
lbl_testConnexion->Text = "Please Wait...";
lbl_testConnexion->TextSettings->FontColor = TAlphaColorRec::Red;
Application->ProcessMessages();
//Call to the Web Service
list<Colis>* l = WS->getListeColis("00DP0097");
lbl_testConnexion->Text = "Success!";
Note:
You have to be carefull with Application->ProcessMessages(). You can find many articles and discussions about this in the internet. When you work with the VCL there exists the method Update for controls of Type TWinControl which calls the function UpdateWindow of the WinAPI. Firemonkey does have a similar function, but only for Windows.
Include FMX.Platform.Win.hpp and replace Application->ProcessMessages() with UpdateWindow(Platform::Win::WindowHandleToPlatform(Handle)->Wnd)

Related

CMDIFrameWnd::MDIGetActive returns null when called from external code

I have inherited some legacy code that i'm required to integrate with a modern c# GUI. The codebase is a MFC MDI application, that creates a type library and registers a COM component to expose the application API for external applications and scripting.
Throughout the MFC application (henceforth I will refer to the MFC code as "the application") there is a function that checks for an active MDI document and returns it, or null. This method is called from a "MainFrame" class which inherits CMDIFrameWnd. it looks something like this:
CMDIChildWnd * pChildFrame = MDIGetActive();
if (pChildFrame)
{
CDocument *pDoc = (CDocument *) pChildFrame->GetActiveDocument();
if (pDoc)
{
return(pDoc);
} else {
return NULL;
}
I have created a test c# console application and can successfully import the COM component and access the API, and make calls to it. The problem is that whenever I call something that requires an active document via the API, MDIGetActive() returns null. For example, I can open a document via the API, and I can visually confirm it opens in the running MFC application. But if I call the API method to save this file, the active document is null. But if I call the same method via the application GUI, this works fine. It is the same function call, the exposed API method is just a wrapper.
Strangely enough when I open a file via the API method, it eventually executes the same check for an active document which succeeds. After getting the active document, it calls CDocument::UpdateAllViews() to update the UI. Any calls made after this via the API will result in no active document.
I'm at a loss here, I can't understand why the active document is null. I'm still working my way through MFC documentation but I haven't found anything that would suggest why this is the case. Does anyone know?
Another way to avoid any GetActiveWhatever() method is the following code, which can be called from your CYourApp class:
POSITION posDoc, pos = GetFirstDocTemplatePosition();
while (NULL != pos)
{
CDocTemplate* pDocTemplate = (CDocTemplate*)GetNextDocTemplate(pos);
posDoc = pDocTemplate->GetFirstDocPosition();
while(NULL != posDoc)
{
CDocument* pDoc = pDocTemplate->GetNextDoc(posDoc);
if(NULL != pDoc)
pDoc->UpdateAllViews(pSender, lHint, pHint);
}
}
Of course, once you have the document, you'll have any view attached from that document.

XInputGetState hangs

I'm trying to use XInput API for my game engine (I'm using DirectX11 and C++). I just want to test if a controller is found so I #included and call XInputGetState but I get a strange behavior:
XINPUT_STATE state;
ZeroMemory(&state, sizeof(XINPUT_STATE));
DWORD result;
for (DWORD i = 0; i < XUSER_MAX_COUNT; i++)
{
result = XInputGetState(i, &state);
if (result == ERROR_SUCCESS)
ErrorBox(L"found controller on port ");
}
if I connect a controller the program hangs and freezes, while if I disconnect the controller the game launches. If I step into the code with the debugger the result is that the controller is found and the message box is displayed.
Why?
EDIT the problem seems to be in the call to ErrorBox: this function just displays a Message Box using Win32 API.
There is a performance hit when you check for a controller that wasn't attached last time you called it because it has to enumerate device, open driver connects, etc. Therefore, you are recommended to round-robin calls to check for new controllers. If you get ERROR_DEVICE_NOT_CONNECTED back, you shouldn't call XInputGetState again for that slot for a little while. For an example of this, see GamePad class in the Directx Tool Ki and the ThrottleRetry function.
In other words, the loop you wrote before is not a good idea to call every frame unless there are XUSER_MAX_COUNT controllers actually connected.

MFC WebBrowser Control: How many (normal) lines of code does it take to simulate Ctrl+N?

Update: Answer: Two normal lines of code required. Thanks Noseratio!
I banged my head on the keyboard for more hours than I would have cared to trying to simulate IEs Ctrl+N behavior in my hosted Browser control app. Unfortunately, due to complications which I've abstracted out of my code examples below, I can't just let IE do Ctlr+N itself. So I have to do it manually.
Keep in mind that I am running a hosted browser. So typically, opening links in new windows will actuall open it within a new "tab" within my application (it's not really a tab, but another window... but appearance-wise it's a tab). However, Ctrl+N is different -- here, it is expected a fully-fledged IE window will launch when pressed.
I think my problem is that of framing the questions -- admittedly I am new to WebBrowser control and I find it to be a lot of yucky. Regardless, I've scoured the Internet for the past day and couldn't come up with an elegant solution.
Basically, the ideal solution would be to call a "NewWindow" function within WebBrowser control or its affiliate libraries; however, all I was able to find where the *On*NewWindow methods, which were event handlers, not event signallers. Which I understand that most of the time, the user will be creating the events... but what about programmatic simulation?
I tried looking into an SENDMESSAGE approach where I could use the IDs that the OnNewWindow events use... that ended up in nothing than crashes. Perhaps I could go back to get it work, but I'd like confirmation is that approach is even worth my time.
The next approach, which should have been the most elegeant, but sadly didn't pan out, was like the following:
Navigate2(GetLocationURL().GetBuffer(), BrowserNavConstants::navOpenInNewWindow);
It would have worked marvelously if it weren't for the fact that the new window would open in the background, blinking in the taskbar. needing clicking to bring it to the front.
I tried to get around the limitation in a myriad of ways, including getting the dispatcher of the current context, then calling OnNewWindow2 with that IDispatch object. Then I would invoke QueryInterface on the dispatch object for an IWebBrowser control. The webBrowser control (presumably under the control of the new window) could then navigate to the page of the original context. However... this too was a pretty messy solution and in the end would cause crashes.
Finally, I resorted to manually invoking JavaScript to get the desired behavior. Really?? Was there really no more elegant a solution to my problem than the below mess of code?
if ((pMsg->wParam == 'N') && (GetKeyState(VK_CONTROL) & 0x8000) && !(GetKeyState(VK_SHIFT) & 0x8000) && !(GetKeyState(VK_MENU) & 0x8000))
{
LPDISPATCH pDisp = CHtmlView::GetHtmlDocument();
IHTMLDocument2 *pDoc;
if (SUCCEEDED(pDisp->QueryInterface(IID_IHTMLDocument2, (void **)&pDoc)))
{
IHTMLWindow2* pWnd;
pDoc->get_parentWindow(&pWnd);
BSTR bStrLang = ::SysAllocString(L"JavaScript");
CString sCode(L"window.open(\"");
sCode.Append(GetLocationURL().GetBuffer());
sCode.Append(L"\");");
BSTR bStrCode = sCode.AllocSysString();
COleVariant retVal;
pWnd->execScript(bStrCode, bStrLang, retVal);
::SysFreeString(bStrLang);
::SysFreeString(bStrCode);
pDoc->Release();
}
pDisp->Release();
I find it hard to believe that I must resort to such hackery as this to get something as simple as opening a new window when the user presses Ctrl+N.
Please stackoverflow, please point out the clearly obvious thing I overlooked.
Ctrl-N in IE starts a new window on the same session. In your case, window.open or webBrowser.Navigate2 will create a window on a new session, because it will be run by iexplore.exe process which is separate from your app. The session is shared per-process, this is how the underlying UrlMon library works. So you'll loose all cookies and authentication cache for the new window. On the other hand, when you create a new window which hosts WebBrowser control within your own app process, you'll keep the session.
If such behavior is OK for your needs, try first your initial Navigate2 approach, precededing it with AllowSetForegroundWindow(ASFW_ANY) call. If the new window still doesn't receive the focus correctly, you can try creating an instance of InternetExplorer.Application out-of-proc COM object, and use the same IWebBrowser2 interface to automate it. Below is a simple C# app which works OK for me, the new window is correctly brought to the foreground, no focus issues. It should not be a problem to do the same with MFC.
using System;
using System.Runtime.InteropServices;
using System.Windows.Forms;
namespace IeApp
{
public partial class MainForm : Form
{
// get the underlying WebBrowser ActiveX object;
// this code depends on SHDocVw.dll COM interop assembly,
// generate SHDocVw.dll: "tlbimp.exe ieframe.dll",
// and add as a reference to the project
public MainForm()
{
InitializeComponent();
}
private void NewWindow_Click(object sender, EventArgs e)
{
AllowSetForegroundWindow(ASFW_ANY);
// could do: var ie = new SHDocVw.InternetExplorer()
var ie = (SHDocVw.InternetExplorer)Activator.CreateInstance(Type.GetTypeFromProgID("InternetExplorer.Application"));
ie.Visible = true;
ie.Navigate("http://www.example.com");
}
const int ASFW_ANY = -1;
[DllImport("user32.dll")]
static extern bool AllowSetForegroundWindow(int dwProcessId);
}
}

When Skype ICallChannelManagerEvents gets fired

I am working on App to App communication using skype. My Requirement is When one skype user place Call/Video Call I wanted to use application stream to send message from One App Plugged in Skype to other App plugged in Skype.
In Separate Sample App I am able to send and receive message using Application Stream from One App to Other App but I wanted to Activate Application Stream When User place call.
Skype4COM expose these three event for ICallChannelManager
ICallChannelManagerEvents::Channels
ICallChannelManagerEvents::Created
ICallChannelManagerEvents::Message
I have registered these three events
hr = m_pCallChannelMgr.CreateInstance(__uuidof(CallChannelManager));
hr = SinkSkypeCallChannelMgrEvents::DispEventAdvise(m_pCallChannelMgr);
hr = m_pCallChannelMgr->CreateApplication(L"");
VARIANT_BOOL flag = m_pCallChannelMgr->GetCreated();
while(true )
{
if ( VARIANT_TRUE == flag) break;
flag = m_pCallChannelMgr->GetCreated();
Sleep(1000);
}
hr = m_pCallChannelMgr->Connect(m_Skypeptr);
when m_pCallChannelMgr->CreateApplication(); is called it fires ICallChannelManagerEvents::Created event.
I am Not sure about,When Other when two event ICallChannelManagerEvents::Channels and ICallChannelManagerEvents::Message gets fired.
Plz help me on this.
Problem Resolved when there is already a call in process and your plugin starts to hook in to Skype ICallChannelManagerEvents gets fired.

How to get event notification in an ATL ActiveX control when a specified registry value changes for use as a windows mobile ActiveX control

I have an activex control that I display in a webbrowser control on a windows mobile device using a C# forms app.
The activex control is working. I want to add a feature to the activex control where an event is raised in the activex control when a registry value changes state.
I have implemented the same (but reversed) functionality on the forms side using RegistryState with the following code. With this code my .net forms app gets notified when a registry value changes. The forms code is below.
private void TestContainer_Load(object sender, EventArgs e)
{
RegistryKey rk = Registry.LocalMachine.OpenSubKey("MyKey");
state = new RegistryState("HKEY_LOCAL_MACHINE\\MyKey", "MessageToHostForm");
state.Changed += new ChangeEventHandler(state_Changed);
}
void state_Changed(object sender, ChangeEventArgs args)
{
RegistryKey rk = Registry.LocalMachine.OpenSubKey("MyKey");
if (rk == null)
{
// No value available in the created/opened subkey
}
else
{
string strOut = (string)rk.GetValue("MessageToHostForm");
button3.Text = strOut;
rk.Close();
}
}
I would like to create the same functionality in the ActiveX control where an event in the control gets fired when a registry value changes.
The problen is ... from what I can tell ... Registry.State is not available in an ATL C++ app :(
How can I make my ATL ActiveX control respond to changes in registry values. (I don't want to use polling)
Is this posible?
Thanks for at least reading this... Long I know...
To avoid polling, you can use CRegKey::NotifyChangeKeyValue, which is in turn built on top of RegNotifyChangeKeyValue. You can have an event signaled with a change under the key. So your worker thread might be waiting for this event [possibly among others] and once your wait is satisfied you would do whatever you do in your state_Changed above.
You also have sample code there: http://msdn.microsoft.com/en-us/library/ms724892%28VS.85%29.aspx
UPD. I realized mobile platform is in question - things are somewhat different there, but still you have an event based option:
MSDN: CeFindFirstRegChange http://msdn.microsoft.com/en-us/library/aa914423.aspx
Code Snippet: Windows CE: Monitor for Registry Changes