|
I tend to use only one canvas (I prefer a Panel for that) and paint all the objects on it, in the right order. Transparancy in GDI/GDI+ is a mess.
Luc Pattyn
I only read code that is properly indented, and rendered in a non-proportional font; hint: use PRE tags in forum messages
Local announcement (Antwerp region): Lange Wapper? 59.24% waren verstandig genoeg om NEEN te stemmen; bye bye viaduct.
|
|
|
|
|
Good evening all,
I need some assistance invoking MFC COM objects from a C++/CLI application.
My COM's are based on "Automation of COM Dialogs in a DLL" by intensely_radioactive from this site, and were originally written in VC++ 6.0
I am reworking my calling application as a Windows Forms using C++/CLI 9.0 module
The COM call is successfull in that I get the "Logon Called" message on screen (See extracts below), but I need something in .NET to play the role of pDlg (from my MFC module) so that I can invoke DoModal in the COM object.
I would prefer not to have to modify the COM, but I appreciate suggestions around that too.
Extract from COM object's module LogonFactory.cpp
LPDISPATCH CLogonFactory::GetDialog()
{
// TODO: Add your dispatch handler code here
AfxMessageBox("Logon Called", MB_OK|MB_ICONINFORMATION);
CLogon *dlg = new CLogon();
// Set the argument to true to increase the ref count
return dlg->GetIDispatch(TRUE);
}
Extract from COM Object's module Logon.cpp
void CLogon::Logon()
{
// TODO: Add your dispatch handler code here
DoModal();
}
Extract from MFC appliction's code that invokes it:
HRESULT hrx;
hrx = CoInitialize(0);
// Use smart pointers to create an instance of the pointers
ILogonFactoryPtr pFactory;
hrx = pFactory.CreateInstance(__uuidof(LogonFactory));
ASSERT(SUCCEEDED(hrx));
if (SUCCEEDED(hrx))
{
// Get the factory to show the dialog
ILogonPtr pDlg;
pDlg = pFactory->GetDialog();
// And activate the button through COM
do
{
pDlg->Logon(); // This function contains the DoModal call in the COM
// and as such actually displays the form
}
}
Extract from C++/CLI calling module
LogonFactory^ GetLogon;
GetLogon = gcnew LogonFactory();
GetLogon->GetDialog();
Ger
|
|
|
|
|
Hi, i am new to Visual C++ and facing problem with combo boxes.
Here is what i need:
Combobox1
Choice: Metal, Plastic
Combobox2
Choice: if Metal in Combobox1: 2,3,4,5,6
Choice: if Plastic in Combobox1: 8,10,15
I am unable to write code for the event, can any one help me out with the hints or links or code!...any help is highly appreciated...!
#pragma once
namespace PR {
using namespace System; using namespace System::ComponentModel; using namespace System::Collections;
using namespace System::Windows::Forms; using namespace System::Data; using namespace System::Drawing;
public ref class Form1 : public System::Windows::Forms::Form
{
public:
Form1(void)
{ InitializeComponent();
}
protected:
~Form1()
{
if (components)
{
delete components;
}
}
private: System::Windows::Forms::ComboBox^ comboBox1;
protected:
private: System::Windows::Forms::ComboBox^ comboBox2;
private:
System::ComponentModel::Container ^components;
#pragma region Windows Form Designer generated code
void InitializeComponent(void)
{
this->comboBox1 = (gcnew System::Windows::Forms::ComboBox());
this->comboBox2 = (gcnew System::Windows::Forms::ComboBox());
this->SuspendLayout();
this->comboBox1->FormattingEnabled = true;
this->comboBox1->Items->AddRange(gcnew cli::array< System::Object^ >(2) {L"METAL", L"PLASTIC"});
this->comboBox1->Location = System::Drawing::Point(81, 80);
this->comboBox1->Name = L"comboBox1";
this->comboBox1->Size = System::Drawing::Size(121, 21);
this->comboBox1->TabIndex = 0;
this->comboBox1->Text = L"METAL";
this->comboBox2->FormattingEnabled = true;
this->comboBox2->Items->AddRange(gcnew cli::array< System::Object^ >(5) {L"2", L"3", L"4", L"5", L"6"});
this->comboBox2->Location = System::Drawing::Point(81, 126);
this->comboBox2->Name = L"comboBox2";
this->comboBox2->Size = System::Drawing::Size(121, 21);
this->comboBox2->TabIndex = 1;
this->comboBox2->Text = L"2";
this->comboBox2->SelectedIndexChanged += gcnew System::EventHandler(this, &Form1::comboBox2_SelectedIndexChanged);
this->AutoScaleDimensions = System::Drawing::SizeF(6, 13);
this->AutoScaleMode = System::Windows::Forms::AutoScaleMode::Font;
this->ClientSize = System::Drawing::Size(292, 266);
this->Controls->Add(this->comboBox2);
this->Controls->Add(this->comboBox1);
this->Name = L"Form1";
this->Text = L"Form1";
this->ResumeLayout(false);
}
#pragma endregion
private: System::Void comboBox2_SelectedIndexChanged(System::Object^ sender, System::EventArgs^ e) {
}
};
}
|
|
|
|
|
Invinci wrote: private: System::Void comboBox2_SelectedIndexChanged(System::Object^ sender, System::EventArgs^ e) {
Should'nt this be an event for comboBox1 (comboBox1_SelectedIndexChanged ) ? You need to change/update comboBox2 when comboBox1 changes.
I'm not quite familiar with the exact syntax of ManagedC++/CLI (and the .net framework, so I will only give you hints.
In the handler for comboBox1:
- You need to clear the content of comboBox2 (remove the Items in it)
- Get the currently selected value of comboBox1
- Check the selected value to see if you need to fill comboBox2 with either "2,3,4,5,6" or "8,10,15".
- Fill in the values in comboBox2.
in pseudocode:
comboBox2.clearContent();
string s = comboBox1.GetStringValue();
if ( s == "Metal")
this->comboBox2->Items->AddRange(gcnew cli::array< System::Object^ >(5) {L"2", L"3", L"4", L"5", L"6"});
else if ( s == "Platic")
this->comboBox2->Items->AddRange(gcnew cli::array< System::Object^ >(5) {L"8", L"10", L"15" });
Max.
This signature was proudly tested on animals.
|
|
|
|
|
You haven't hooked event handler for combo box 1. You need to hook event handler for that and do something like:
if(comboBox1->Text == "METAL")
{
this->comboBox2->Items->Clear();
this->comboBox2->Items->AddRange(gcnew cli::array<int>(5) {2, 3, 4, 5, 6});
}
else if(comboBox1->Text = "PLASTIC")
{
this->comboBox2->Items->Clear();
this->comboBox2->Items->AddRange(gcnew cli::array<int>(5) {8, 10, 15});
} You also need to remove code that adds items to combobox2 from InitializeComponent method.
Best wishes,
Navaneeth
|
|
|
|
|
Thanks Navaneeth and Maximilien for your inputs and code!
Haven't yet solved with the given information, by using the Navaneeth code the combobox2 event is not functioning!
private: System::Void comboBox2_SelectedIndexChanged(System::Object^ sender, System::EventArgs^ e)
{
if(comboBox1->Text == L"METAL")
{
this->comboBox2->Items->Clear();
this->comboBox2->Items->AddRange(gcnew cli::array< System::Object^ >(5) {L"2", L"3", L"4", L"5", L"6"});
}
else if(comboBox1->Text == L"PLASTIC")
{
this->comboBox2->Items->Clear();
this->comboBox2->Items->AddRange(gcnew cli::array< System::Object^ >(3) {L"8", L"10", L"15"});
}
} Additionally removed the add items code from Combobox2 as suggested by Navaneeth. I think something is still missing in using the code but the logic is correct!.
|
|
|
|
|
As I said in my last post, you still haven't hooked combox1's SelectedIndexChanged event. Hook it and write the code which I provided in that event handler. You don't need to handle second combobox's SelectedIndexChanged .
Best wishes,
Navaneeth
|
|
|
|
|
Wow, you are right! It worked perfectly. Thanks appreciated!
|
|
|
|
|
Problem on charset encoding
obj_db->query("UPDATE PATIENTS_DATA SET FIRST_NAME='flkسؤ' WHERE COD_PATIENT=2 ");
give me a warning:
1>.\globalConfiguration.cpp(151) : warning C4566: character represented by universal-character-name '\u0633' cannot be represented in the current code page (1252)
1>.\globalConfiguration.cpp(151) : warning C4566: character represented by universal-character-name '\u0624' cannot be represented in the current code page (1252)
and the real string in database is flk??
----------edit-----------
here i didn't pointed out the real problem...see my second post
modified on Thursday, October 15, 2009 6:14 AM
|
|
|
|
|
barbetto80 wrote: obj_db->query("UPDATE PATIENTS_DATA SET FIRST_NAME='flkسؤ' WHERE COD_PATIENT=2 ");
You have two Arabic characters at the end of the name, and the compiler is merely warning that the current code page does not support correct representation of them.
|
|
|
|
|
Ok now i pointed out exactly which is my problem ant it's a charset encoding going from std::string to System::String and viceversa:
i query my database and i get the following
string tmp_result_string= // in hexadecimal its value is C2 A3
then i convert using:
String ^LAST_NAME=tmp_result_string.c_str();
when i set last_name_textBox->Text=LAST_NAME;
the visual representation i get in the form is £ which is the ANSII encoding of C2 A3, but what i want is the textbox to display £ which is the utf8 encoding of C2 A3...any help?
tha same problem i have doing the inverted thing getting text from textbox and putting it on database.
modified on Thursday, October 15, 2009 9:22 AM
|
|
|
|
|
ok..i find answer to the problem:
String^ databaseManagedWrapper::unMarshalStringUTF8(string %os) {
char const* buffer = os.c_str();
cli::array<System::Byte>^ a = gcnew cli::array<System::Byte>(os.length());
int i = os.length();
while (i-- > 0) {
a[i] = buffer[i];
}
return System::Text::Encoding::UTF8->GetString(a);
}
now i need the inverse...
string databaseManagedWrapper::MarshalStringUTF8( String ^ s) {
System::Text::UTF8Encoding^ utf8 = gcnew System::Text::UTF8Encoding;
array<Byte>^encodedBytes = utf8->GetBytes(s);
string os="";
for (int i=0;i<encodedBytes->Length;i++) {
os+=encodedBytes[i];
}
return os;
}
modified on Thursday, October 15, 2009 9:19 AM
|
|
|
|
|
System::String is Unicode compatible. You don't need to do any encoding here. Also I think your databaseManagedWrapper::unMarshalStringUTF8 function's implementation is wrong. Here is a version that converts string contains Unicode characters to System::String . std::wstring is used instead of std::string .
String^ UnicodeNativeStringToManagedString(wstring& os)
{
const wchar_t* buffer = os.c_str();
return gcnew String(buffer);
} Here is the function for inverse. You need to work with methods in the Marshal class.
std::wstring UnicodeManagedStringToNative(String^ str)
{
using namespace System::Runtime::InteropServices;
wchar_t* chr = (wchar_t*) Marshal::StringToHGlobalAnsi(str).ToPointer();
std::wstring result(chr);
Marshal::FreeHGlobal(IntPtr(chr));
return result;
}
Best wishes,
Navaneeth
|
|
|
|
|
preamble: i'am using a database that can use UTF8 as best support for multi-language, so i started out from it. UTF8 is a variable-length character encoding for Unicode. The wrapper for the database id written in c++ and uses std::string as variables input method.
Well my problem is that i need a std::string to store to the DB, and not wstring... that's why i create these methods. Maybe i didn't get your help as i see you are creating a wstring...
ps thank you i really appreciate your answer to my various problem in this forum. You are helping me growing up learning and skilling this language
|
|
|
|
|
Well, its easy to convert my code to support std::string . You need char* instead if wchar_t* . Windows uses wchar_t for Unicode and it is 2 bytes wide with UTF-16 encoding. So when programming on windows, it is a better to use wchar_t . wstring is a typedef for basic_string templated using wchar_t .
However, I tried to convert a UTF-8 encoded string to and from managed code. But it never worked until I changed to wstring . Perhaps I may need to investigate more.
Best wishes,
Navaneeth
|
|
|
|
|
I have a function in a wrapper DLL that points to a native function. The native function returns a struct and I am looking for a solution to Marshall the struct to be called by C# Winform app.
The managed function:
M_USB_DEVICE_DESCRIPTOR SXManaged::M_GetDeviceInfo(void)
Where:
M_USB_DEVICE_DESCRIPTOR is a managed struct that is virutally the same as the native struct
SXManaged is the managed class in the wrapper DLL.
Inside the managed function I call the native function:
usb_dd = umc->GetDeviceInfo();
Where:
usb_dd is a native struct variable of type USB_DEVICE_DESCRIPTOR. The members of that are very blittable - bytes and unsigned short.
umc is an object that is a pointer to the native class that holds native function GetDeviceInfo()
I can't leave the return type as a native struct type as it's being called in C#. I've looked as far as I can to try and see how to do this but coming up short.
Any help greatly appreciated.
Al
Jer 29:11
|
|
|
|
|
Native struct and managed struct is different. Your best bet would be to create a managed class with necessary details and fill it with the values from native function. This instance can be consumed from C#.
Best Wishes,
Navaneeth
|
|
|
|
|
The "managed" function shown in the illustration IS from a managed class.
Jer 29:11
|
|
|
|
|
Well, your return type is M_USB_DEVICE_DESCRIPTOR which is a managed type, right? If yes, what is the problem ate you facing in using it from C#?
|
|
|
|
|
Hi,
I have a managed version of the struct on the C# side which is easy because the struct contains primitive members. The issue is marshalling the struct from the managed function to the native function that is called by the managed one.
Jer 29:11
|
|
|
|
|
I am migrating a C++ application to .NET.
In C++ ,I have an template class which uses some ATL library classes
for eg.
template< class T >
class MyBaseClass:
public IConnectionPointContainerImpl<t>,
public IPersistStorageImpl<t>,
public IPersistPropertyBagImpl<t>,
{
}
Now i need to use this call in my new C# .net project where my new .NET call will get derive from above MyBaseClass .
Please let me know how can i archive this ???
Is this possible to use a template class which uses some ATL libraray classes directly in C# ?
`chiman
|
|
|
|
|
There is no straightforward method to use template classes in other CLI languages like C#. This is because of the difference in how C++ templates and CLI generics works. C++ templates will be instantiated at compile time and CLI generics will be on runtime. C++/CLI also supports managed templates, but unfortunately it is not portable to other CLI languages.
If you want to use inheritance, you may need to create managed classes that calls the template class for each known type. Like MyBaseClassInt which use MyBaseClass<int> etc. This will not be the correct method as you will have class explosion when you have several types to be used.
Prefer composition over inheritance. In such case, this can be easily solved by providing a factory class which checks the type and instantiates respective template instance. Any new types can be easily added to the factory method without recompiling the whole application. We are taking the capability of C++/CLI to mix generic and template type parameters. To see how this can be done, consider the following code:
template< class T >
class MyBaseClass:
public IConnectionPointContainerImpl,
public IPersistStorageImpl,
public IPersistPropertyBagImpl,
{
public:
void DoSomething();
};
generic<typename T>
public interface class IManagedBase
{
public:
void DoSomething();
};
template<typename T>
ref class MyBaseClassWrapper : IManagedBase<T>
{
public:
virtual void DoSomething()
{
MyBaseClass<T> native;
native.DoSomething();
}
};
public ref class NativeObjectBuilder
{
public:
generic<typename T> virtual IManagedBase<T> GetBaseObject()
{
if(T::typeid == int::typeid)
return (IManagedBase<T>^) gcnew MyBaseClassWrapper<int>();
else if(T::typeid == double::typeid)
return (IManagedBase<T>^) gcnew MyBaseClassWrapper<double>();
}
}; From C#, you can use it like
NativeObjectBuilder objectBuilder = new NativeObjectBuilder();
IManagedBase<int> ib = objectBuilder.GetBaseObject<int>();
ib.DoSomething(); This trick works well for primitive types. But for other complex types, you may need to write wrappers and use it.
Hope that helps
PS: I wrote this code directly on CP editor and you may get some minor syntax error.
modified on Saturday, October 10, 2009 1:03 AM
|
|
|
|
|
Hi all,
I want convert System::String* str[] to const char* chars[] array for one of mu application!
System::String* str[] is a parameter to function. And this function is called from c#
any have idea how this conversion happens?
|
|
|
|
|
SaveTigers wrote: System::String* str[]
Does that even compile? I don't think you can write System::String* str[] . Do you want to convert managed string to const char* ?
|
|
|
|
|
Hey thanks for reply Navaneeth,
Got it!
I am doing something like this
char *abc[100];
for(int i = 0; i < ss->Count; i++)
{
abc[i] = (char*)(System::Runtime::InteropServices::Marshal::StringToHGlobalAnsi(ss[i])).ToPointer();
}
the above code is working file where ss is System::String* ss[] as function argument
I spend 2 days to get it working!!!
Now the problem is with System::Double dd[][] I want to convert it to double[][] used in Unmanaged C++
how should I use System::Double dd[][] in managed C++
I am getting this sort of error
error C2440: 'initializing' : cannot convert from 'double __gc *' to
'double'
I tried many permutation but could n0t get through!!
Navaneeth any idea how to do this conversion!
Thanks in advance!
|
|
|
|