Kilka pytań odnośnie C#

0

1.) Czy wydajność (i szybkość uruchamiania) dość rozbudowanej aplikacji okienkowej - kilkanaście okien i po kilkadziesiąt kontrolek w każdym - jest aż na tyle niższa w stosunku do takiej samej aplikacji napisanej w C++ by dało się to odczuć?

2.) Wszyscy pewnie kojarzą funkcję CreateWindow / CreateWindowEx z WinAPI. Tworząc nowe okno lub kontrolkę musieliśmy podawać nazwę klasy okna jako drugi parametr. Czy w C# da się stworzyć okno lub kontrolkę podając własną nazwę klasy bez automatycznie dodawanych prefixów lub sufixów? Jak to się robi? Pokażcie proszę fragment kodu.

3.) Ile MB pamięci RAM zajmie uruchomiona aplikacja posiadająca jedno okno bez żadnych kontrolek? ~ 1 MB podobnie jak aplikacja napisana w C++?

4.) Jak wygląda konwersja liczba<->string? Jakieś metody w stylu toString(), toInt()?

5.) Czy wszystkie natywne w C# okna i kontrolki posiadają zaimplementowany mechanizm podwójnego buforowania, dzięki czemu są tzw. flicker-free? (Zakładam, że tak)

6.) To prawda, że w C# nie da się ręcznie zarządzać zwalnianiem pamięci bo wszystko wykonuje za nas GC? Czy można chociaż wpłynąć na to, kiedy się on uruchomi / na jak długo / ile pamięci zwolni / jakie obiekty zwolni / inne opcje?

0
Goodrock napisał(a):

1.) Czy wydajność (i szybkość uruchamiania) dość rozbudowanej aplikacji okienkowej - kilkanaście okien i po kilkadziesiąt kontrolek w każdym - jest aż na tyle niższa w stosunku do takiej samej aplikacji napisanej w C++ by dało się to odczuć?

Zależy jak jest napisana ta aplikacja, jeśli nie jest spierniczona, to na w miarę nowoczesnym komputerze dużej różnicy nie będzie.

2.) Wszyscy pewnie kojarzą funkcję CreateWindow / CreateWindowEx z WinAPI. Tworząc nowe okno lub kontrolkę musieliśmy podawać nazwę klasy okna jako drugi parametr. Czy w C# da się stworzyć okno lub kontrolkę podając własną nazwę klasy bez automatycznie dodawanych prefixów lub sufixów? Jak to się robi? Pokażcie proszę fragment kodu.

Nie, nie wszyscy. Niektórzy mają tę funkcję głęboko gdzieś.
Obiekty okien i kontrolek tworzy się tak samo jak obiekty każdego innego typu.

3.) Ile MB pamięci RAM zajmie uruchomiona aplikacja posiadająca jedno okno bez żadnych kontrolek? ~ 1 MB podobnie jak aplikacja napisana w C++?

Zależy od tego, ile CLR uzna za stosowne, wartość będzie się różniła w zależności od komputera.

4.) Jak wygląda konwersja liczba<->string? Jakieś metody w stylu toString(), toInt()?

Są.

6.) To prawda, że w C# nie da się ręcznie zarządzać zwalnianiem pamięci bo wszystko wykonuje za nas GC? Czy można chociaż wpłynąć na to, kiedy się on uruchomi / na jak długo / ile pamięci zwolni / jakie obiekty zwolni / inne opcje?

Można ręcznie wywołać np. GC.Collect(), ale na to co i ile zwolni nie ma się wpływu. I słusznie.

0

Nie, nie wszyscy. Niektórzy mają tę funkcję głęboko gdzieś.
Obiekty okien i kontrolek tworzy się tak samo jak obiekty każdego innego typu.

Źle mnie zrozumiałeś. Wiem, że w C# nie używa się tej funkcji. Ale chcę wiedzieć czy da się stworzyć okno tak, by jego klasa miała dokładnie taką nazwę jaką poda programista.

Można ręcznie wywołać np. GC.Collect(), ale na to co i ile zwolni nie ma się wpływu. I słusznie.

Czyli w C# też może zdarzyć się sytuacja, że GC odpali się w najmniej odpowiednim momencie powodując niechciany "freeze" aplikacji tak jak zdarza się to podobno w Javie?

0
Goodrock napisał(a):

Źle mnie zrozumiałeś. Wiem, że w C# nie używa się tej funkcji. Ale chcę wiedzieć czy da się stworzyć okno tak, by jego klasa miała dokładnie taką nazwę jaką poda programista.

Nie rozumiem. :)
Okno tworzysz tak:

MojForm mf = new MojForm();

MojForm to nazwa klasy okna.

Czyli w C# też może zdarzyć się sytuacja, że GC odpali się w najmniej odpowiednim momencie powodując niechciany "freeze" aplikacji tak jak zdarza się to podobno w Javie?

Podobno. A jaki to najmniej oczekiwany moment?

0

Nie rozumiem.

Ok, ale zapewne kojarzysz np. nazwę Shell_TrayWnd? Albo inaczej: tworząc jakieś okno tak jak podałeś, C# wygeneruje coś w stylu:
WindowsForms10.Window.8.app.0.33c0d9d

EDIT: Wg informacji z tej strony nie da się:
http://stackoverflow.com/questions/2937888/winform-friendly-class-name

Podobno. A jaki to najmniej oczekiwany moment?

No jakiś zupełnie przypadkowy. Np. aplikacja wykonuje właśnie jakieś zadanie, które powinno się wykonać jak najszybciej, a tu nagle jep - GC robi nam niespodziankę :-) Wiem, że to już trochę czepianie się, ale interesuje mnie ta kwestia. A da się jakoś oszacować jak często odpala się GC? Kwestia sekund / minut czy raczej o tym decyduje ilość zajmowanej pamięci?

0

Ja też nie bardzo rozumiem o co chodzi i czemu się uparłeś na CreateWindow i te dodatki znane z C++. W C# piszesz po prostu

 
MojeOkienko okienko = new MojeOkienko();

Koniec, okienko utworzono, a słowo 'MojeOkienko' jest wprost skopiowane z nazwy klasy którą samemu można utworzyć, albo wspomóc się środowiskiem. Teraz wystarczy wywołać funkcję która pokazuje je na ekranie. W WPF będzie to:

 okienko.Show(); 

albo (w zależności od potrzeby)

 okienko.ShowDialog(); 

i wszystko działa.

Co do GC, to ja bym się na Twoim miejscu nie przejmował. To w miarę inteligentne narzędzie, które bez potrzeby nie uruchamia się (w Javie i mi się zdarzyło że tamtejszy GC potrafił włączyć się w dziwnym momencie, ale to też nie było zbyt częste, tutaj w sumie nie widać zbytnio jego działania). Jeżeli tak się o to dopytujesz, bo właśnie skończyłeś zabawę z C++ i czujesz potrzebę własnego zarządzania pamięcią, to to jest kwestia przyzwyczajenia się, że 'delete' coś robi za Ciebie. Mnie też to na początku irytowało, ale teraz widzę, że dzięki temu można nieraz fajne skróty w kodzie stosować, bo nie potrzeba myśleć o kasowaniu, przechowywania wskaźnika, sprawdzania czy nie jest NULL itd. Własne uruchamianie GC jest często zbędne, bo jeśli CLR przydziela odpowiednią ilość zasobów, to może się okazać, że GC uruchomi się raz przy wyłączaniu aplikacji (oczywiście, wszystko kwestia złożoności aplikacji).

0
Goodrock napisał(a):

Ok, ale zapewne kojarzysz np. nazwę Shell_TrayWnd?

Nie, a po co?
Nie każdy miał nieprzyjemność pisania w durnym C++.

Albo inaczej: tworząc jakieś okno tak jak podałeś, C# wygeneruje coś w stylu:
WindowsForms10.Window.8.app.0.33c0d9d

Na poziomie WinAPI czy czegoś takiego może tak. Ale jakie to ma znaczenie?

Np. aplikacja wykonuje właśnie jakieś zadanie, które powinno się wykonać jak najszybciej, a tu nagle jep - GC robi nam niespodziankę :-) Wiem, że to już trochę czepianie się, ale interesuje mnie ta kwestia. A da się jakoś oszacować jak często odpala się GC? Kwestia sekund / minut czy raczej o tym decyduje ilość zajmowanej pamięci?

Raczej liczba utworzonych obiektów. GC chyba domyślnie pracuje w trybie współbieżnym, pracując jednocześnie z aplikacją, więc nie powinien powodować jakichś dużych przerw, ale wszystko zależy od aplikacji.

0

Ok to temat GC uznajmy już za zakończony :-)

Wracając do klasy. Mylisz słowo kluczowe "class" służące do zdefiniowania nowej klasy z nazwą klasy windowsowego okna, która jest zwykłym stringiem. Używając RegisterClass() i CreateWindow zawsze trzeba było jako nazwę klasy podać tego samego stringa. W C# też jest to wykonywane (bo MUSI! - tak jest skonstruowany Windows) tyle, że niejawnie - jest to niewidoczne dla użytkownika i nie musi sobie zawracać tym głowy - i słusznie (w 99% przypadków) bo jest to wygodne.

Tworząc okno tak jak podałeś mogę Ci zagwarantować (choć nigdy nie pisałem w C#), że windowsowa klasa okna nie będzie się nazywać "MojeOkienko" lecz przyjmie postać podobną do "WindowsForms10.Window.8.app.0.33c0d9d". Widocznie C# silnie opiera się na tej nazwie zapisując w niej potrzebne informacje, co powoduje, że nie można i nie wolno jej zmieniać.

Teraz uruchom np. spy++ i sprawdź jakie nazwy klasy mają różne okna w systemie. Klasyczne kontrolki typu przycisk będą miały klasę BUTTON (w C# być może inną - jeśli te kontrolki zostały stworzone od nowa), inne np. EDIT, itp. Czasami pisząc aplikacje używało się funkcji FindWindow podając nazwę tej klasy by odnaleźć konkretne okno innej aplikacji (zakładając, że utworzona została tylko jedna instancja tegoż okna).

Ja jednak chciałbym napisać dość specyficzną aplikację, która z pewnych przyczyn technicznych (nie zależnych ode mnie) musi mieć w kilku oknach z góry narzucone nazwy klas. Wygląda na to, że pisząc GUI w C# musiałbym najpierw utworzyć za pomocą WinAPI te okna, a następnie kierować komunikaty do okien stworzonych przy użyciu C# czyli np. do MojeOkienko jak podałeś.

Post napisany w odniesieniu do posta Lena(R).

0
Goodrock napisał(a):

Wracając do klasy. Mylisz słowo kluczowe "class" służące do zdefiniowania nowej klasy z nazwą klasy windowsowego okna, która jest zwykłym stringiem.

Słowo klasa w kontekście paradygmatu programowania obiektowego ma bardzo precyzyjne znaczenie, i ani @lena(R), ani ja źle go tutaj nie użyliśmy.

Ja jednak chciałbym napisać dość specyficzną aplikację, która z pewnych przyczyn technicznych (nie zależnych ode mnie) musi mieć w kilku oknach z góry narzucone nazwy klas.

No cóż, ta potrzeba jest tak ekscentryczna i bez praktycznego znaczenia dla ogółu programistów, że faktycznie nie jest to obsługiwane w C#.

0

1.) Czy wydajność (i szybkość uruchamiania) dość rozbudowanej aplikacji okienkowej - kilkanaście okien i po kilkadziesiąt kontrolek w każdym - jest aż na tyle niższa w stosunku do takiej samej aplikacji napisanej w C++ by dało się to odczuć?

Nie ma dużej różnicy.

2.) Wszyscy pewnie kojarzą funkcję CreateWindow / CreateWindowEx z WinAPI. Tworząc nowe okno lub kontrolkę musieliśmy podawać nazwę klasy okna jako drugi parametr. Czy w C# da się stworzyć okno lub kontrolkę podając własną nazwę klasy bez automatycznie dodawanych prefixów lub sufixów? Jak to się robi? Pokażcie proszę fragment kodu.

Nie da się. Po co Ci to? :)

3.) Ile MB pamięci RAM zajmie uruchomiona aplikacja posiadająca jedno okno bez żadnych kontrolek? ~ 1 MB podobnie jak aplikacja napisana w C++?

Przed chwilą stworzyłem, uruchomiłem i zjada 3060 KB (wg Windowsowskiego Menedżera Zadań). Wg Process Explorer zjada 12352 KB (kolumna Private Bytes). Nie wiem dlaczego taka różnica.

4.) Jak wygląda konwersja liczba<->string? Jakieś metody w stylu toString(), toInt()?

const int I = 102;
string str = I.ToString(CultureInfo.InvariantCulture);

6.) To prawda, że w C# nie da się ręcznie zarządzać zwalnianiem pamięci bo wszystko wykonuje za nas GC? Czy można chociaż wpłynąć na to, kiedy się on uruchomi / na jak długo / ile pamięci zwolni / jakie obiekty zwolni / inne opcje?

Nigdy tego nie używałem :).

GC.Collect();

http://msdn.microsoft.com/en-us/library/xe0c2357.aspx

3

Nie da się. Po co Ci to?
oj tam od razu się nie da.

        protected override CreateParams CreateParams
        {
            get
            {
                const int CS_GLOBALCLASS = 0x4000;
                CreateParams cp = base.CreateParams;
                cp.ClassName = "ToJestNazwaKlasy";
                cp.ClassStyle = cp.ClassStyle | CS_GLOBALCLASS;
                return cp;
            }
        }

Tylko że klasa musi już (globalnie) istnieć. Można się pobawić w wywołanie RegisterClass() przed utworzeniem okna.

somekind napisał(a)

Powód przeniesienia: Wątek dotyczący podstaw
Pytanie o klasę okna zdecydowanie podstaw nie dotyczy.

2
Azarien napisał(a)

Można się pobawić w wywołanie RegisterClass() przed utworzeniem okna.

using System;
using System.Windows.Forms;
using System.Runtime.InteropServices;

namespace WindowsFormsApplication4
{
    
    public partial class Form1 : Form
    {
        const int CS_GLOBALCLASS = 0x4000;
        const string nazwaKlasy = "ToJestNazwaKlasy";

        [UnmanagedFunctionPointer(CallingConvention.StdCall, SetLastError = true)]
        delegate IntPtr TWndProc(IntPtr hWnd, uint msg, IntPtr wParam, IntPtr lParam);

        [DllImport("user32.dll", SetLastError = true, CharSet=CharSet.Unicode)]
        static extern IntPtr DefWindowProc(IntPtr hWnd, uint msg, IntPtr wParam, IntPtr lParam);

        [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
        struct WNDCLASS
        {
            public uint style;
            public TWndProc lpfnWndProc;
            public int cbClsExtra;
            public int cbWndExtra;
            public IntPtr hInstance;
            public IntPtr hIcon;
            public IntPtr hCursor;
            public IntPtr hbrBackground;
            public string lpszMenuName;
            public string lpszClassName;
        }

        [DllImport("user32.dll", SetLastError = true, CharSet=CharSet.Unicode)]
        static extern ushort RegisterClass([In] ref WNDCLASS lpWndClass);

        public static void ZarejestrujKlasę()
        {
            WNDCLASS wc = new WNDCLASS();
            wc.lpszClassName = nazwaKlasy;
            wc.lpfnWndProc = DefWindowProc;
            wc.style = CS_GLOBALCLASS;
            RegisterClass(ref wc);
            int error = Marshal.GetLastWin32Error();
            if (error != 0)
                throw (new Exception(String.Format("Cannot register window class, GetLastError={0}", error)));
        }

        public Form1()
        {
            InitializeComponent();
        }

        protected override CreateParams CreateParams
        {
            get
            {
                CreateParams cp = base.CreateParams;
                cp.ClassName = nazwaKlasy;
                cp.ClassStyle = cp.ClassStyle | CS_GLOBALCLASS;
                return cp;
            }
        }
    }  
}

...

using System;
using System.Windows.Forms;

namespace WindowsFormsApplication4
{
    static class Program
    {
        [STAThread]
        static void Main()
        {
            Application.EnableVisualStyles();
            Application.SetCompatibleTextRenderingDefault(false);
            Form1.ZarejestrujKlasę(); // ### tutaj ###
            Application.Run(new Form1());
        }
    }
}
0
Goodrock napisał(a):

1.) Czy wydajność (i szybkość uruchamiania) dość rozbudowanej aplikacji okienkowej - kilkanaście okien i po kilkadziesiąt kontrolek w każdym - jest aż na tyle niższa w stosunku do takiej samej aplikacji napisanej w C++ by dało się to odczuć?

Wg mnie tak. Widziałem aplikację (bardzo rozbudowaną) napisaną w WPF + EDM oraz realizującą podobną logikę napisaną w MFC + czyste Ado.net, różnica była ogromna - odświeżenie grida z kilkudziesięcioma rekordami w MFC było praktycznie niezauważalne, w WPFie trwało to kilka sekund.

0

Ściągnąłem sobie Visual C# 2010 Express i wykorzystałem kod tej klasy (2gi post):
http://stackoverflow.com/questions/128561/registering-a-custom-win32-window-class-from-c-sharp?answertab=votes#tab-top
Działa OK i na razie mi to wystarcza, ale dzięki Azarien za przedstawienie pozostałych rozwiązań - pewnie przyda mi się to później.

Nie da się. Po co Ci to?

Nie mogę napisać bo dyskusja pójdzie w złą stronę. Ale mam swoje powody.

Teraz zastanawiają mnie jeszcze inne kwestie:
1.) Co z tzw. Activation Contexts - C# ma jakieś wbudowane obiekty do obsługi tego czy znowu trzeba się bawić Windows API? Potrzebuję załadować obiekty shella, które tego wymagają.
2.) Jak zrzutować IntPtr by móc bezpośrednio wykonać np. "->zmiennaZeStruktury = 10;" czyli bez tworzenia jej kopii?

1

Coś mi się wydaje, że
albo wcale nie potrzebujesz pisać tak niskopoziomowo, tylko ci się wydaje;
albo wiesz co robisz (i nie mylisz się), ale C# nie jest najlepszym wyborem jeśli chodzi o język w takim razie.

0

@Goodrock, to czemu interfejsu nie napiszesz w C#, a logiki niskopoziomowej w C++/CLI?

0

Opiera się to głównie na wykorzystywaniu różnorakich funkcji "shell api"
No to możesz używać, ale ograniczając to do wymaganego minimum — po co chcesz tworzyć okno od początku w WinAPI?

0

Na razie chyba będę dalej kodował w WinAPI bo już daleko zaszedłem i aplikacja zaczyna powoli coś sobą reprezentować.

to czemu interfejsu nie napiszesz w C#, a logiki niskopoziomowej w C++/CLI?

Bo aplikacja, którą tworzę wymaga sporego nakładu pracy i ostrożności. Nie znam ani C# (dopiero wczoraj i dziś zacząłem mu się przyglądać) ani C++/CLI. Mam obawę, że jak dorzucę sobie jeszcze konieczność używania dodatkowo C# i C++/CLI nie znając ich dobrze to skomplikuję sobie sprawę jeszcze bardziej i przez to znacząco wydłużę czas pracy. Poza tym dochodzi jeszcze reverse-engineering.

No to możesz używać, ale ograniczając to do wymaganego minimum

Cały czas staram się to ograniczać do minimum, ale pewne funkcjonalności i tak muszę oprzeć na tych funkcjach.

po co chcesz tworzyć okno od początku w WinAPI?

Nie chcę. I mogę zastosować drugie rozwiązanie jakie podałeś. Ale to już nie chodzi o to, bo teraz pojawiła się kwestia wczytywania tych obiektów COM. Potem mogą się pojawić inne niskopoziomowe sprawy...

0

Ja potrzebuję móc wywołać funkcje:

CreateActCtxW();
ActivateActCtx();
DeactivateActCtx();
ReleaseActCtx();

itp. Da się bez WinAPI?

1 użytkowników online, w tym zalogowanych: 0, gości: 1