How can I pause shutdown long enough for my app? I found an example, but it is for Delphi - I can't translate it to C++.
Here is a C++Builder VCL translation of the Delphi code:
class TForm1 : public TForm
{
..
protected:
void __fastcall WMQueryEndSession(TWMQueryEndSession &Message);
..
public:
..
BEGIN_MESSAGE_MAP
VCL_MESSAGE_HANDLER(WM_QUERYENDSESSION, TWMQueryEndSession, WMQueryEndSession)
END_MESSAGE_MAP(TForm)
};
...
void __fastcall TForm1::WMQueryEndSession(TWMQueryEndSession &Message)
{
Message.Result = TRUE;
if ((Message.Unused & ENDSESSION_CRITICAL) == 0)
{
ShutdownBlockReasonCreate(Handle, L"please wait while muting...");
Sleep(45000); // do your work here
ShutdownBlockReasonDestroy(Handle);
}
}
Related
Using C++Builder 2006.
I'm trying to modify a TCustomControl derived class, and i need that class to catch mouse wheel events (or messages).
I've tried to use the answer for this Delphi question but i don't get the event.
This is my relevant code:
TMouseWheelHandler.h
class PACKAGE TMouseWheelHandler : public TCustomControl
{
private:
typedef TCustomControl inherited;
protected:
virtual void __fastcall Paint();
void __fastcall WMSize (TWMSize &Message);
void __fastcall CMMouseEnter (TMessage &Message);
void __fastcall CMMouseLeave (TMessage &Message);
void __fastcall WMMouseMove (TMessage &Message);
BEGIN_MESSAGE_MAP
VCL_MESSAGE_HANDLER(WM_SIZE, TWMSize, WMSize)
VCL_MESSAGE_HANDLER(CM_MOUSEENTER , TMessage, CMMouseEnter)
VCL_MESSAGE_HANDLER(CM_MOUSELEAVE , TMessage, CMMouseLeave)
VCL_MESSAGE_HANDLER(WM_MOUSEMOVE , TMessage, WMMouseMove)
END_MESSAGE_MAP(TCustomControl)
virtual bool DoMouseWheel (TShiftState Shift, int WheelDelta, TPoint & MousePos);
virtual bool DoMouseWheelDown (TShiftState Shift, TPoint & MousePos);
virtual bool DoMouseWheelUp (TShiftState Shift, TPoint & MousePos);
void MouseWheelHandler (const TMessage &Message);
public:
__fastcall TMouseWheelHandler(TComponent* Owner);
__published:
__property OnMouseWheelUp;
__property OnMouseWheelDown;
__property OnMouseWheel;
__property OnClick;
};
TMouseWheelHandler.cpp
//===========================================================================
//===========================================================================
//===========================================================================
bool TMouseWheelHandler::DoMouseWheel (TShiftState Shift, int WheelDelta, TPoint & MousePos)
{
OutputDebugString(__FUNC__);
return inherited::DoMouseWheel(Shift,WheelDelta,MousePos);
}
//===========================================================================
bool TMouseWheelHandler::DoMouseWheelDown (TShiftState Shift, TPoint & MousePos)
{
OutputDebugString(__FUNC__);
return inherited::DoMouseWheelDown(Shift, MousePos);
}
//===========================================================================
bool TMouseWheelHandler::DoMouseWheelUp (TShiftState Shift, TPoint & MousePos)
{
OutputDebugString(__FUNC__);
return inherited::DoMouseWheelUp(Shift, MousePos);
}
//===========================================================================
// MOUSE MANAGEMENT TAKEN FROM STACKOVERFLOW DELPHI SOLUTION
//===========================================================================
void __fastcall TMouseWheelHandler::CMMouseEnter (TMessage &Message)
{
OutputDebugString(__FUNC__);
SetFocus();
MouseCapture = true;
Refresh();
}
//===========================================================================
void __fastcall TMouseWheelHandler::CMMouseLeave (TMessage &Message)
{
OutputDebugString(__FUNC__);
MouseCapture = false;
Refresh();
}
//===========================================================================
void __fastcall TMouseWheelHandler::WMMouseMove (TMessage &Message)
{
if (MouseCapture) {
TPoint pt;
POINTSTOPOINT(pt , MAKEPOINTS(Message.LParam) );
if (PtInRect(ClientRect, pt) ) {
OutputDebugString("MOUSE IN");
}else{
OutputDebugString("MOUSE OUT");
MouseCapture = false;
Refresh();
}
}else{
OutputDebugString("NO_CAPTURE");
}
}
//===========================================================================
void TMouseWheelHandler::MouseWheelHandler (const TMessage &Message)
{
OutputDebugString(__FUNC__);
TMessage MyMessage = Message; // In the DELPHI sample Message was'nt a const
MyMessage.Result = Perform(CM_MOUSEWHEEL, MyMessage.WParam, MyMessage.LParam);
if (MyMessage.Result == 0) {
inherited::MouseWheelHandler(MyMessage);
}
}
//===========================================================================
//===========================================================================
//===========================================================================
And this is how i use the Control in my Form:
WH = new TMouseWheelHandler(this);
WH->Parent = Panel1;
WH->Align = alTop;
WH->Height = Panel1->Height/2;
WH->OnMouseWheel = GGMouseWheel;
WH->OnMouseWheelDown = GGMouseWheelDown;
WH->OnMouseWheelUp = GGMouseWheelUp;
void __fastcall TTestForm::GGMouseWheel(TObject *Sender, TShiftState Shift, int WheelDelta, const TPoint &MousePos, bool &Handled)
{
OutputDebugString(__FUNC__);
}
//---------------------------------------------------------------------------
void __fastcall TTestForm::GGMouseWheelDown(TObject *Sender, TShiftState Shift, const TPoint &MousePos, bool &Handled)
{
OutputDebugString(__FUNC__);
}
//---------------------------------------------------------------------------
void __fastcall TTestForm::GGMouseWheelUp(TObject *Sender, TShiftState Shift, const TPoint &MousePos, bool &Handled)
{
OutputDebugString(__FUNC__);
}
//---------------------------------------------------------------------------
What i see from the debug prints are that none of the DoMouse* functions and also the MouseWheelHandler function are never called, while the Form GGMouseWheel* functions are.
All i'd need is to manage some variables in the DoMouse* functions.
What am i doing wrong?
Your MESSAGE_MAP should be declared public not protected, since it overrides the virtual Dispatch() method which is public. Personally, I prefer to override the virtual WndProc() method instead of using MESSAGE_MAPs.
That being said, there is no need to handle the mouse wheel messages directly, simply override the virtual DoMouseWheel...() methods. Note that your DoMouseWheel...() and MouseWheelHandler() methods are all declared incorrectly, so they are NOT overriding the virtual methods of the same names.
Try these declarations instead (you could have looked in Controls.hpp to get these, or read the documentation):
DYNAMIC bool __fastcall DoMouseWheel(TShiftState Shift, int WheelDelta, const TPoint &MousePos);
DYNAMIC bool __fastcall DoMouseWheelDown(TShiftState Shift, const TPoint &MousePos);
DYNAMIC bool __fastcall DoMouseWheelUp(TShiftState Shift, const TPoint &MousePos);
DYNAMIC void __fastcall MouseWheelHandler(TMessage &Message);
I am using RAD Studio 10 working on a Windows VCL application. I have two Forms, Form1 (the MainForm in Unit1.cpp) and a secondary Form2 (in Unit2.cpp). I managed to embed Form2 inside of Form1. This is just a setup to illustrate the problem. My real project has multiple Forms.
When closing Form2, the VCL triggers the Form2::OnClose() event. Knowing that Form2 was created dynamically in Form1 (the MainForm), is there a Form1 event that will fire upon Form2 being closed? Or something inside Form1 to know that Form2 is closing?
I was thinking of customizing an event handler like OnChildFormClose but I couldn't make it.
I tried to wrap the code that I wanted to execute on Form1 when Form2 is closed in a public function and call it in the Form2::OnClose() event, and it worked to some extent, but it is not a good approach if you have multiple Forms.
//FROM THE unit1.cpp
#include <vcl.h>
#pragma hdrstop
#include "Unit1.h"
#include "Unit2.h"
//-----------------------------------------------------------------------
#pragma package(smart_init)
#pragma resource "*.dfm"
TForm1 *Form1;
//-----------------------------------------------------------------------
__fastcall TForm1::TForm1(TComponent* Owner)
: TForm(Owner)
{
}
//-----------------------------------------------------------------------
void __fastcall TForm1::FormCreate(TObject *Sender)
{
TForm2 *form2 = new TForm2(this);
form2->ManualDock(container);
form2->Show();
}
//FROM unit2.cpp
#include <vcl.h>
#pragma hdrstop
#include "Unit2.h"
//-----------------------------------------------------------------------
#pragma package(smart_init)
#pragma resource "*.dfm"
TForm2 *Form2;
//-----------------------------------------------------------------------
__fastcall TForm2::TForm2(TComponent* Owner)
: TForm(Owner)
{
}
//-----------------------------------------------------------------------
void __fastcall TForm2::Button1Click(TObject *Sender)
{
Close();
}
//-----------------------------------------------------------------------
Can I implement something like an OtherFormsonClose(*Sender) event in Form1 with a Sender that we can dynamically cast to check if it is Form2, or maybe I am wrong? I would appreciate some guidance.
You can declare a common event handler of type TCloseEvent, e.g. OtherFormClose(TObject *Sender, TCloseAction &Action); in the main form:
private: // User declarations
void __fastcall TForm1::OtherFormClose(TObject *Sender, TCloseAction &Action);
implementation
void __fastcall TForm1::OtherFormClose(TObject *Sender, TCloseAction &Action)
{
Action = caFree;
TForm2 *f2 = dynamic_cast<TForm2 *>(Sender);
if (f2) {
ShowMessage(String("Form2 closing")); //Do stuff
}
}
(or use Sender to inspect which form)
Then when you create other forms in code, e.g. Form2, you assign
TForm2 *form2 = new TForm2(this);
form2->OnClose = OtherFormClose;
// etc
Ok I found something interesting after reading this, this, this, and this.
So basically, a VCL Delphi/C++Builder application uses Windows Form Messages for comunication, and we can override the virtual function WndProc to catch a specific message, but it must be some unique message because VCL uses a lot of messages and if you don't tread carefully things might blow up; This will translate to a custom event handler on the main form.
So what I did is :
Passed the MainForm handle to Form2 in the constructor to be saved on a Form2 private var and to be used only for the messaging.
Generate a specific ID that I use to tag the message to make it stand out
overriding the WndProc and filtering messages with a specific ID so we know that Form2 is closing.
Test it and it worked, maybe someone have a better idea.
//From unit2.h---------------------------------------------------------
class TForm2 : public TForm
{
__published: // IDE-managed Components
TButton *Button1;
void __fastcall Button1Click(TObject *Sender);
void __fastcall FormClose(TObject *Sender, TCloseAction &Action);
private: // User declarations
HWND mfhandle;
public: // User declarations
__fastcall TForm2(TComponent* Owner, HWND mainformhandle);
};
//From unit2.cpp---------------------------------------------------------
#include <vcl.h>
#pragma hdrstop
#include "Unit2.h"
#pragma package(smart_init)
#pragma resource "*.dfm"
TForm2 *Form2;
const UINT uiMyCopyDataID = RegisterWindowMessage(TEXT("MyCopyDataID"));
__fastcall TForm2::TForm2(TComponent* Owner,HWND mainformhandle)
: TForm(Owner)
{
mfhandle = mainformhandle;
}
void __fastcall TForm2::Button1Click(TObject *Sender)
{
Close();
}
void __fastcall TForm2::FormClose(TObject *Sender, TCloseAction &Action)
{
//Notify the mainForm and say Hey I am closing now
PostMessage(mfhandle, uiMyCopyDataID, 0, 0);
}
//From unit1.h---------------------------------------------------------
class TForm1 : public TForm
{
__published: // IDE-managed Components
TPanel *container;
void __fastcall FormCreate(TObject *Sender);
void __fastcall FormUnDock(TObject *Sender, TControl *Client, TWinControl *NewTarget,
bool &Allow);
private: // User declarations
protected:
void __fastcall TForm1::WndProc(TMessage &Message); //Added THIS
public: // User declarations
__fastcall TForm1(TComponent* Owner);
};
//From unit1.cpp-------------------------------------------------------
const UINT uiMyCopyDataID = RegisterWindowMessage(TEXT("MyCopyDataID"));
void __fastcall TForm1::WndProc(TMessage &Message)
{
if (Message.Msg == uiMyCopyDataID)
{
//Do SomeThing here
ShowMessage("Form2 is closing");
}
TForm::WndProc(Message);
}
Ok, So far it works and custom messages MUST be in the WM_USER (0x0400 - 0x7FFF) range.
I really need your help again.
I trying to building a tiny download manager application by using TIdHTTP of Indy 10.6.2.5263 (shipped with XE8 Update 1) on C++ Builder XE8.
But, I always get errors Socket Error #11001 - Host not found when the target download address is http://www.rarlab.com/rar/wrar53b1.exe. Also, Socket Error #10051 - Network is unreachable when the download address is changed to http://5.135.104.98/rar/wrar53b1.exe.
I didn't know why I always keep getting those errors since all my other installed applications (Firefox, YM, IDM, etc..) are normally connected to Internet.
I'm using the following simple code.
UNIT1.CPP
//---------------------------------------------------------------------------
#include <vcl.h>
#pragma hdrstop
#include "Unit1.h"
//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma resource "*.dfm"
TForm1 *Form1;
//---------------------------------------------------------------------------
__fastcall TForm1::TForm1(TComponent* Owner) : TForm(Owner)
{
}
//---------------------------------------------------------------------------
void __fastcall TForm1::DownloadClick(TObject *Sender)
{
String FileName;
String IB = InputBox("Download Manager", "Address", "");
TFileStream* FStream = new TFileStream(FileName, fmCreate | fmOpenWrite);
try
{
IdHTTP->ConnectTimeout = 1000;
IdHTTP->ReadTimeout = 1000;
IdHTTP->Get(IB, FStream);
ShowMessage("Download Complete");
}
__finally
{
delete FStream;
}
}
//---------------------------------------------------------------------------
void __fastcall TForm1::IdHTTPWork(TObject *ASender, TWorkMode AWorkMode, __int64 AWorkCount)
{
if (ProgressBar->Max > 0)
{
DownloadStatus->Caption = IntToStr(AWorkCount) + "bytes of" + IntToStr(ProgressBar->Max) + "bytes.";
ProgressBar->Position = AWorkCount;
}
else
DownloadStatus->Caption = IntToStr(AWorkCount) + "bytes.";
}
//---------------------------------------------------------------------------
void __fastcall TForm1::IdHTTPWorkBegin(TObject *ASender, TWorkMode AWorkMode, __int64 AWorkCountMax)
{
ProgressBar->Position = 0;
ProgressBar->Max = AWorkCountMax;
if (AWorkCountMax > 0)
DownloadStatus->Caption = "Transfering: " + IntToStr(AWorkCountMax);
}
//---------------------------------------------------------------------------
void __fastcall TForm1::IdHTTPWorkEnd(TObject *ASender, TWorkMode AWorkMode)
{
if (AWorkMode != wmRead)
return;
DownloadStatus->Caption = "Done";
ProgressBar->Position = 0;
}
//---------------------------------------------------------------------------
I need to fire an event written in C++ / CLI from an unmanned function in c++.
What is the best way to do this?
Thanks in advance.
I figured out with some help from some help posts on codeproject
Thought of posting it here could be useful for others
#include "stdafx.h"
#include "windows.h"
using namespace System;
using namespace System::Runtime::InteropServices;
class Camera
{
public:
Camera()
{
}
~Camera(){}
void (*test)(void);
void OnNewCameraData();
void StartDataAcquisition();
};
void Camera::StartDataAcquisition()
{
int i;
while(i<10)
{
test();
i++;
Sleep(1000);
}
}
delegate void FunctionToCallDelegate();
ref class CameraAdapter
{
private:
Camera *_camera;
FunctionToCallDelegate ^_Function;
public:
CameraAdapter(FunctionToCallDelegate ^handler)
{
_Function = handler;
}
void Init()
{
_camera = new Camera();
pin_ptr<FunctionToCallDelegate^> tmp = &_Function;
_camera->test = (void (__cdecl *)(void))(Marshal::GetFunctionPointerForDelegate(_Function).ToPointer());
_camera->StartDataAcquisition();
}
~CameraAdapter()
{
delete _camera;
_camera = 0;
}
void OnNewCameraData()
{
Console::WriteLine("Received Frame \n");
}
};
int main(array<System::String ^> ^args)
{
FunctionToCallDelegate ^dsi;
dsi += gcnew FunctionToCallDelegate(gcnew CameraAdapter(dsi), &CameraAdapter::OnNewCameraData);
CameraAdapter ^camera = gcnew CameraAdapter(dsi);
camera->Init();
Console::ReadKey();
return 0;
}
[RAD Studio XE3 / C++]
I have a FMX project running in Windows only at this stage, but I need to detect events when USB devices are connected and disconnected. I have a similar VCL app that can do this fine, but the Application->HookMainWindow is not exposed in FMX (only VCL).
Is there an elegant way to handle this? Or do I have to hack some VCL stuff into my FMX app to make that work? I'd imagine I have to abstract it so I can support other platforms down the track. For the meantime though I need to get the Windows solution working.
If the 'VCL hack' thing is required, how would I reference the vcl::Forms::Application from within my Fmx app?
Cheers.
This could help, using the TMessage way?
type
TMyMessageClass = class(TMessage)
MyProp1 : Integer;
MyProp2 : string;
end;
procedure MyForm.FormCreate(Sender: TObject);
begin
TMessageManager.DefaultManager.SubscribeToMessage(TMyMessageClass, Self.ProcessMessage);
end;
procedure MyForm.ProcessMessage(Sender : TObject; M : TMessage);
begin
if M is TMyMessageClass then
begin
//Do something
end;
end;
From the thread I do something like...
procedure TMyThread.Execute;
var
FMyMessage : TMyMessageClass;
begin
//stuff
Synchronize(
procedure
begin
FMyMessageClass := TMyMessageClass.Create;
FMyMessageClass.MyProp1 := 1;
FMyMessageClass.MyProp2 := 'Hello';
TMessageManager.DefaultManager.SendMessage(nil, FMyMessageClass);
end);
Hope this helps
I have found a solution, thanks to http://www.haogongju.net/art/1480814
It'd be nice to be able to attach some files but it looks like it's going to have to go inline.
SystemEvents.h
#ifndef SystemEventsH
#define SystemEventsH
#include <System.Classes.hpp>
#include <FMX.Controls.hpp>
#include <FMX.Forms.hpp>
#include "DeviceChanged.h"
//---------------------------------------------------------------------------
class TSystemEvents : TObject
{
private:
TDeviceChangedMethod pDeviceChangeHandler;
TForm *pOwnerForm;
#ifdef _Windows
HWND Hwnd; // Save the window handle
LONG OldWndProc;// And remember the old WndProc so we can put it back later
#endif
public:
__fastcall TSystemEvents(TForm *_pForm);
__fastcall ~TSystemEvents();
__property TForm *OwnerForm = {read=pOwnerForm};
#ifdef _Windows
LRESULT __stdcall MessageHandler(Winapi::Messages::TMessage &Message);
#endif // _Windows
__property TDeviceChangedMethod DeviceChangeHandler={read=pDeviceChangeHandler,write=pDeviceChangeHandler};
};
extern TSystemEvents *SystemEvents;
#endif
SystemEvents.cpp
#include <fmx.h>
#include <FMX.Platform.Win.hpp>
#pragma hdrstop
#include "SystemEvents.h"
//---------------------------------------------------------------------------
#pragma package(smart_init)
#ifdef _Windows
LRESULT __stdcall WindowProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
if (SystemEvents == NULL)
{
return 0;
}
// This routine can't be a closure because the winapi needs to call it as
// a LONGPTR. So from here I can pass it into the SystemEvents object.
Winapi::Messages::TMessage _Message;
_Message.Msg = msg;
_Message.WParam = wParam;
_Message.LParam = lParam;
return (LRESULT)SystemEvents->MessageHandler(_Message);
}
#endif //_Windows
__fastcall TSystemEvents::TSystemEvents(TForm *_pForm)
{
pOwnerForm = _pForm;
pDeviceChangeHandler = NULL;
#ifdef _Windows
// Owner form handle is in FMX framework, but we want a Hwnd handle:
Hwnd = FmxHandleToHWND(pOwnerForm->Handle);
// Save the original WindowProc address
OldWndProc = GetWindowLongPtr(Hwnd, GWL_WNDPROC);
// Redirect the messages to my own function
SetWindowLongPtr(Hwnd, GWL_WNDPROC, (LONG_PTR)&WindowProc);
#endif
}
__fastcall TSystemEvents::~TSystemEvents()
{
#ifdef _Windows
// Very important we undo our hack before the app finishes
SetWindowLongPtr(Hwnd, GWL_WNDPROC, OldWndProc);
#endif
}
LRESULT __stdcall TSystemEvents::MessageHandler(Winapi::Messages::TMessage &Message)
{
#ifdef _Windows
if (Message.Msg == WM_DEVICECHANGE)
{
if (DeviceChangeHandler != NULL)
{
DeviceChangeHandler(this, new TDeviceChangedMessage(TDeviceChangedMessage::ParamForWin32wParam(Message.WParam)));
return 1;
}
}
return CallWindowProc((WNDPROC)OldWndProc, Hwnd, Message.Msg, Message.WParam, Message.LParam);
#endif
return 0;
}
DeviceChanged.h
#ifndef DeviceChangedH
#define DeviceChangedH
//---------------------------------------------------------------------------
typedef enum {Unknown = 0, DeviceNodesChanged} DeviceChangedParam;
class TDeviceChangedMessage
{
private:
DeviceChangedParam eParam;
public:
TDeviceChangedMessage(DeviceChangedParam _eParam)
{
eParam = _eParam;
}
__property DeviceChangedParam Param={read=eParam};
static DeviceChangedParam __fastcall ParamForWin32wParam(WPARAM _wParam);
};
typedef void __fastcall (__closure *TDeviceChangedMethod)(System::TObject* Sender, TDeviceChangedMessage* M);
#endif
DeviceChanged.cpp
#include <fmx.h>
#include <Dbt.h>
#pragma hdrstop
#include "DeviceChanged.h"
//---------------------------------------------------------------------------
#pragma package(smart_init)
DeviceChangedParam __fastcall TDeviceChangedMessage::ParamForWin32wParam(WPARAM _wParam)
{
if (_wParam == DBT_DEVNODES_CHANGED)
return DeviceChangedParam::DeviceNodesChanged;
return DeviceChangedParam::Unknown;
}
To use it:
#include <SystemEvents.h>
TSystemEvents *SystemEvents;
// In Constructor:
{
SystemEvents = new TSystemEvents(this);
SystemEvents->DeviceChangeHandler = OnDeviceChanged;
}
// In Destructor:
{
deletenullify(SystemEvents);
}
// Handler:
void __fastcall TMainForm::OnDeviceChanged(System::TObject* Sender, TDeviceChangedMessage *M)
{
if (M->Param == DeviceChangedParam::DeviceNodesChanged)
{
OnUSBDeviceChanged();
}
}
Works for me. :)