I was somewhat surprised that can't easily access the properties of the WinForms class with functions you add as bublic, years ago with Borland VCL this wasn't an issue. Apparently 'delegates' is said to be the right keyword ... and I've been struggling with this for days now and can't get it to work. Is my approach beyond or is it just that the plug is not plugged in? Via the event handler, the forms property is successfully changed. Now i'm asking for a hint to transfer this capability down to sub1()?
#include "form1.h"
#include <Windows.h>
using namespace System;
using namespace System::Windows::Forms;
void sub1(void);
public delegate void Deleg(String^ st);
[STAThread]
void Main() // array<System::String^> ^args)
{
Application::EnableVisualStyles();
Application::SetCompatibleTextRenderingDefault(false);
App1::Form1 form;
Deleg^ Deleg1;
Application::Run(% form);
// Deleg1 += gcnew Deleg(form,&App1::Form1::newTxt); //?
}
void App1::Form1::button1_Click(System::Object^ s, System::EventArgs^ e)
{
String^ st = "ABC";
App1::Form1::newTxt(st);
Refresh();
sub1();
}
void sub1(void)
{
String^ s = "DEF";
// Deleg1(s);
}
I tried to copy some examples I found on the net, but apparently I don't hit the core.
Related
I have this code in my Managed C++/Cli in Visual Studio 2022, I want to update the progressBar value in different stages of my c++ function. So far I have 3 delegates UpdateUi(), UpdateUiDone() and UpdateProgress(int percent) which passes an int percent as an argument. These delegates have the methods UiDoSome(), UiDosomeDone() and UpdateProgressBar(int percent). How this code runs is that on a click of a button, a new thread starts which calls the function ThreadProc. SPP is the name of the windows form class. Here is my code:
private: System::Void button2_Click(System::Object^ sender, System::EventArgs^ e) {
Thread^ t = gcnew Thread(gcnew ThreadStart(this, &SPP::ThreadProc));
t->Start();
}
ThreadProc function:
public: System::Void ThreadProc() {
label6->Invoke(gcnew UpdateUi(this, &SPP::UiDoSome));
-> progressBar1->Invoke(gcnew UpdateProgress(this, &SPP::UpdateProgressBar(25)));
//My code goes in here......
label6->Invoke(gcnew UpdateUiDone(this, &SPP::UiDosomeDone));
}
Delegates definition:
public: delegate void UpdateUi();
public: delegate void UpdateUiDone();
public: delegate void UpdateProgress(int percent);
Delegates' methods:
public: void UiDoSome() {
label6->Text = "processing...";
}
public: void UiDosomeDone() {
label6->Text = "Done!!!";
}
public: void UpdateProgressBar(int percent) {
progressBar1->Value = percent;
}
The problem is that , when invoking the progressBar in the ThreadProc function and I pass a value to the UpdateProgressBar method, the compiler throws an error: "expression must be an lvalue or a function designator". How can I solve this, is this even possible in C++? I know C# has no such issues. I appreciate your help. Thanks in advance.
You need to use an array to pass arguments when using Invoke(), like this:
array<System::Object^>^ params = gcnew array<System::Object^>(1);
params[0] = 25;
Invoke(gcnew UpdateProgress(this, &SPP::UpdateProgressBar), params);
But, you cannot use Invoke() in the first place, since UI elements (buttons, labels etc) can be safely modified only from the thread they were created by. Therefore, you have to use BeginInvoke() here. Also, you can use BeginInvoke of the form itself:
public: System::Void ThreadProc() {
BeginInvoke(gcnew UpdateUi(this, &SPP::UiDoSome));
array<System::Object^>^ params = gcnew array<System::Object^>(1);
params[0] = 25;
BeginInvoke(gcnew UpdateProgress(this, &SPP::UpdateProgressBar), params);
BeginInvoke(gcnew UpdateUiDone(this, &SPP::UiDosomeDone));
}
I'm trying to get the text in my textbox tb_key to write to my std::string Key Variable by doing this:
std::string Key = TRIPRECOILWARE::LoginForm::tb_key->Text;
I get an error saying :
A non-static member reference must be relative to a specific
object
I tried to search but I couldn't find anything really that fixed it for me.
Minimal Reproducible Example:
LoginForm.h
namespace TRIPRECOILWARE {
using namespace System;
using namespace System::ComponentModel;
using namespace System::Collections;
using namespace System::Windows::Forms;
using namespace System::Data;
using namespace System::Drawing;
private: System::Void tb_key_TextChanged(System::Object^ sender, System::EventArgs^ e)
{
}
}
LoginForm.cpp
std::string Key = TRIPRECOILWARE::LoginForm::tb_key->Text;
I'm trying to use this in LoginForm.h
private: System::Void button1_Click(System::Object^ sender, System::EventArgs^ e) {
if (Authenticate(StringToChar(Key), (StringToChar(hwid)))) // Authenticates key & hwid
{
this->Hide();
Software^ soft = gcnew Software();
soft->Show();
}
Basically, I want to get Key from Textbox called tb_key and write
it to my Key variable defined above. Then use that key to
authenticate and perform code
Your real problem is a duplicate of How to turn System::String^ into std::string?
Corrected code:
#include <msclr\marshal.h>
#include <msclr\marshal_cppstd.h>
using namespace System;
using namespace msclr::interop;
void button1_Click(System::Object^ sender, System::EventArgs^ e)
{
std::string Key = marshal_as<std::string>(tb_key->Text);
if (Authenticate(Key.c_str(), hwid.c_str())) // Authenticates key & hwid
{
Hide();
Software^ soft = gcnew Software();
soft->Show();
}
}
I want to use C++/CLR to create a UI for my app. I need C++/CLR because I deal with a lot of native win32 C++ code. So I tried to make my app with the following steps, but they don't work:
Make an empty project
Unicode charset and enable /clr
Add refrences to PresentationCore, PresentationFramework, System, and WindowsBase
Add the App.xaml, App.xaml.h, MainWindow.xaml, MainWindow.xaml.h
Add the InitalizeComponent code to MainWindow.xaml.h (that
s where i'm having trouble.)
This is my mainwindow.xaml.h code
#pragma once
using namespace System::Windows;
using namespace System;
namespace Project2
{
public ref class MainWindow : Window
{
public:
MainWindow()
{
System::Uri ^resourceLocater = gcnew System::Uri("component\MainWindow.xaml", System::UriKind::Relative);
#line 1 "..\..\MainWindow.xaml"
System::Windows::Application::LoadComponent(this, resourceLocater);
}
};
}
My entry point code:
#include <Windows.h>
#include "App.xaml.h"
#include "MainWindow.xaml.h"
using namespace System;
using namespace System::Windows;
[STAThreadAttribute]
int WINAPI WinMain(HINSTANCE a, HINSTANCE b, LPSTR c, int d)
{
auto win = gcnew Project2::MainWindow();
auto app = gcnew Project2::App();
app->Run(win);
return 0;
}
And here's my app.xaml.h code:
#pragma once
using namespace System::Windows;
namespace Project2
{
public ref class App : Application
{
public:
};
}
The MainWindow.xaml and App.xaml all contain valid markup.
I tried chaning the values for the System::Uri resoucelocator but nothings chaning. I just get System.IO.IOException: The mainwindow.xaml was not found
Any ideas?
I may be way out of my depth here, so I'm sorry if I seem completely lost, but it's just because I am. (But, if I never went out of my depth, I guess I'd never learn anything)
I'm trying to figure out how to host a Win32 window in a WPF control but, being completely unknowledgable about the Windows API, I'm struggling to interact with it in basic ways.
Currently, I'm getting an access exception when I try to pass the parent window's HWND to the method "CreateWindow."
Here is my code:
///------------- VisualDerived.h -----------------
using namespace System::Runtime::InteropServices;
namespace POCPP
{
namespace WPF
{
namespace Controls
{
public ref class VisualDerived : System::Windows::Interop::HwndHost
{
private:
HWND *childWin;
protected:
virtual HandleRef BuildWindowCore(HandleRef trg) override;
virtual void DestroyWindowCore(HandleRef trg) override;
public:
VisualDerived();
};
}
}
}
// ------------------ VisualDerived.cpp -----------------------
#include "Stdafx.h"
#include <Windows.h>
#include <WinUser.h>
#include "VisualDerived.h"
#pragma comment(lib, "user32.lib")
HandleRef POCPP::WPF::Controls::VisualDerived::BuildWindowCore(HandleRef trg)
{
DWORD windowOptions = WS_CHILDWINDOW;
HWND *parentWindow = (HWND*)trg.Handle.ToPointer();
HWND chld = CreateWindow(NULL, NULL, windowOptions, 0, 0, 200, 200, *parentWindow, 0, 0, NULL); // throws access exception as is, returns null reference exception without the pointer to the parentWindow
return HandleRef(NULL, System::IntPtr(&chld));
}
void POCPP::WPF::Controls::VisualDerived::DestroyWindowCore(HandleRef trg)
{
}
POCPP::WPF::Controls::VisualDerived::VisualDerived()
{
}
Anyway, I'm sorry if my problem seems noobish to the seasoned professionals here. I'm pretty far outside my comfort zone not knowing either the Windows API well, nor C++/CLI.
But I'm determined to learn how to do this, so any help would be great.
HWND *parentWindow = (HWND*)trg.Handle.ToPointer();
is wrong because Handle is the HWND. Change it to:
HWND parentWindow = (HWND)trg.Handle.ToPointer();
You are passing NULL as the window class when you call CreateWindow. You have to provide a window class.
Your return statement is also wrong. You are returning the address of a local variable. It should be:
return HandleRef(NULL, System::IntPtr(chld));
I have created dialog in .dll project. Now I want to open that dialog from WPF application by clicking on button. Following is the code for dialog:
TestDialog.h:
class CTestDialog : public CDialogEx
{
DECLARE_DYNAMIC(CTestDialog)
public:
CTestDialog(CWnd* pParent = NULL); // standard constructor
virtual ~CTestDialog();
// Dialog Data
enum { IDD = 1000 };
protected:
virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support
DECLARE_MESSAGE_MAP()
};
TestDialog.cpp:
#include "stdafx.h"
#include "MFCDll.h"
#include "TestDialog.h"
#include "afxdialogex.h"
IMPLEMENT_DYNAMIC(CTestDialog, CDialogEx)
CTestDialog::CTestDialog(CWnd* pParent /*=NULL*/)
: CDialogEx(CTestDialog::IDD, pParent)
{
}
CTestDialog::~CTestDialog()
{
}
void CTestDialog::DoDataExchange(CDataExchange* pDX)
{
CDialogEx::DoDataExchange(pDX);
}
BEGIN_MESSAGE_MAP(CTestDialog, CDialogEx)
END_MESSAGE_MAP()
I have created export function which create object of dialog and open that dialog by calling the DoModel() function.
extern "C" void PASCAL EXPORT ShowDialogFromDLL()
{
CTestDialog dlg;
theApp.m_pMainWnd = &dlg;
dlg.DoModal();
}
After that I am calling this export function from WPF form following is the code for WPF Form.
MainWindow.xaml.vb:
namespace MainApp
{
public partial class MainWindow : Window
{
[DllImport("MFCDll.dll", CharSet = CharSet.Auto, SetLastError = false)]
public static extern void ShowDialogFromDLL();
public MainWindow()
{
InitializeComponent();
}
private void btnShow_Click(object sender, RoutedEventArgs e)
{
ShowDialogFromDLL();
}
}
}
But now when I call ShowDialogFromDLL(); after clicking button.It will throw me exception as
Microsoft Visual C++ Debug Library
Debug Assertion Failed!
Program: E:\EDR1\Test\MainApp\bin\Debug\MainApp.vshost.exe
File: f:\dd\vctools\vc7libs\ship\atlmfc\include\afxwin1.inl
Line: 24
For information on how your program can cause an assertion failure, see the Visual C++ documentation on asserts.
(Press Retry to debug the application)
Above error is coming when I call dlg.DoModal(); method.
This should work -
extern "C" __declspec(dllexport) void __stdcall ShowDialogFromDLL()
{
AFX_MANAGE_STATE(AfxGetStaticModuleState())
CTestDialog dlg;
dlg.DoModal();
}
When building a regular DLL that dynamically links to MFC, you need to use the macro AFX_MANAGE_STATE to switch the MFC module state correctly.