artykuły

Matlab - wywoływanie funkcji systemowych

20:36
pią, 29 październik 2010
Artykuł pokazuje na przykładzie problemu zmiany pozycji kursora na ekranie, jak ominąć niektóre braki środowiska Matlab, wykorzystując możliwość pisania rozszerzeń w języku C.

Wprowadzenie

Witam serdecznie. Program Matlab firmy Mathworks ma olbrzymie możliwości. Jednak co zrobić gdy w wyniku przeprowadzonych obliczeń chcemy aby nasz program poruszył odpowiednio kursor czy też wydał dźwięk z głośniczka systemowego? Przecież Matlab nie udostępnia takich funkcji. O tym m.in piszę w tym artykule.

Jaki jest pomysł

Matlab nie udostępnia funkcji pozwalających korzystać z systemowego Windows API.A jedynie za pomocą Windows API możemy się dorwać do pozycji kursora. Co więc zrobić? Musimy napisać do niego rozszerzenie w jezyku C, które będzie nam wywoływało odpowiednie funkcje. I tym właśnie się zajmiemy.

Zaczynamy!

Najpierw stworzymy sobie jakiś fajny interfejs graficzny. Formularz będzie posiadał jeden przycisk ;)

  1. Uruchamiamy Matlaba
  2. Klikamy na ikonkę GUIDE. Pojawia nam się okno w którym z listy wybieramy "Blank GUI (Default)" i klikamy na OK.
  3. Zostanie otwarty wizualny edytor nowowygenerowanego formularza. Kładziemy na nim przycisk (paleta po lewej).
  4. Zapisujemy plik formularza w jakimś folderze i zamykamy edytor wizualny.
  5. Otwiera się nam okno z kodem (plik z rozszerzeniem ".m") procedur Callback (czyli tzw. procedur zwrotnych) które wywoływane są gdy wystąpi jakieś zdarzenie.

OK. Interfejs mamy już gotowy. Teraz pora na odpowiednie oprogramowanie przycisku.

  1. W Matlabie, po lewej stronie na górze mamy okienko przeglądarki plików projektu. Z racji, że Matlab automatycznie nie przechodzi do folderu w którym zapisano interfejs graficzny musimy to zrobić sami. Przejdźmy więc do folderu w którym zapisaliśmy projekt, tak, aby w okienku przeglądarki plików widzieć listę stworzonych plików (jak na razie zostały wygenerowane dwa pliki - ".m" i ".fig".
  2. W edytorze kodu, który mamy otwarty odszukajmy linię zawierającą procedurę "pushbutton1_Callback". Jej prototyp wygląda następujaco:function pushbutton1_Callback(hObject, eventdata, handles)
  3. Dopiszmy bezpośrednio pod nią funkcję:rusz_kursorem(130,140)Tej funkcji jeszcze nie napisaliśmy. Będzie to funkcja wywoływana właśnie z rozszerzenia które opiszemy w języku C.
  4. Przyszedł czas na stworzenie kluczowego w naszym projekcie pliku rozszerzającego środowisko. Stwórzmy więc w naszym folderze z projektem plik o takiej samej nazwie jak wywoływana funkcja - czyli plik o nazwie "rusz_kursorem.c"
  5. Otwórzmy go i wprowadźmy następujący kod: /* Funkcja ustawia kursor na zadanej w parametrach pozycji */ /* */ /* Uwagi do kompilacji: */ /* Konfiguracja kompilacji - wpisz: mex -setup */ /* wpisz >> mex rusz_mysza.c user32.lib */ #include <windows.h> // Tu nam siedzi wspomniana funkcja (pamietac o podlinkowaniu user32.lib) #include "mex.h" // Ta biblioteka jest zawsze wymagana - pamiętać // To jest cos jak "main" void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]) { mxArray *tab; // parametry są w Matlabie przekazywane przez specjalna strukture mxArray (moze byc ona macierzą, łańcuchem albo właśnie liczbą - jak w tym przypadku) int X,Y; tab = prhs[0]; X=(int)(mxGetScalar(tab)); printf("Parametr X=%d\n",X); tab = prhs[1]; Y=(int)(mxGetScalar(tab)); printf("Parametr Y=%d\n\n",Y); SetCursorPos(X,Y); return; }
  6. Zapisujemy plik i w oknie komend Matlaba wydajemy poleceniemex rusz_kursorem.cPo tej operacji Matlab skompiluje plik (jeśli kompilujemy po raz pierwszy to powinien się zapytać jakiego kompilatora chcemy użyć - wybieramy domyślnie LCC.
  7. Gotowe! W oknie przeglądarki plików klikamy dwukrotnie na plik z rozszerzeniem ".fig" wywołując w ten sposób formularz. Jeśli wszystko poszło dobrze, po kliknięciu na przycisk znajdujący się na formularzu, kursor powinien zostać przeniesiony do ustalonego przy wywołaniu funkcji rusz_kursorem() punktu.

Kilka objaśnień co do kodu rozszerzenia w języku C

Po wywołaniu rozszerzenia, zostaje wywołana funkcja:void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[])Jest ona czymś w rodzaju głównej funkcji main(), choć ma nieco inny zestaw parametrów. Inny zestaw parametrów bierze się stąd, że w Matlabie można wywoływać funkcje w nietypowy sposób np.:[zmienna1,zmienna2] = funkcja(parametr1,parametr2)

Konieczne więc stało się przechowywanie zarówno parametrów funkcji, jak i parametrów do których zwracana będzie obliczona wartość (tych po lewej stronie). Parametry są przekazywane do naszej funkcji za pomocą struktur mxArray (a dokładniej za pomocą tablicy wskaźników na dane o typie tej struktury). Struktury mxArray zapewniają zgodność typów, gdyż mogą przechowywać zarówno złożone macierze, tekst jak i pojedyncze liczby. I tak: pierwszy parametr "nlhs" (number of left hand [parameters] structure) znaczy w wolnym tłumaczeniu tyle co liczba parametrów po lewej stronie (patrząc od nazwy funkcji) - czyli liczba parametrów które mają zostać zwrócone przez naszą funkcję - w typ wypadku mamy dwa (zmienna1 oraz zmienna2). Parametr "plhs" jest natomiast, jak już wspomniałem, tablicą wskaźników na struktury do których mamy zwrócić dane. Kolejny prametr "nrhs" - analogicznie - jest ilością argumentów przekazywanych do funkcji, natomiast "prhs" jest tablicą wskaźników na stałe struktury.
Wiedząc już co nieco o prototypie funkcji mamy przed sobą kolejny problem: jak "wyłuskać" ze struktury mxArray liczbę, w przypadku jeśli do funkcji przekazujemy parametry typu Integer (liczby całkowite). W przypadku naszej aplikacji będziemy potrzebować tego typu konwersji, gdyż jako parametry funkcji przekazujemy nową pozycję (X i Y) kursora.

Będziemy potrzebować wskaźnika na strukturę mxArray (nazwałem go "tab") do którego przypiszemy odpowiedni element tablicy parametrów podawanych do funkcji by później pskonwertować go na typ całkowitoliczbowy za pomocą funkcji mxGetScalar(). W tym wypadku "prhs[0]" przechowuje nam argument X, natomiast "prhs[1]" przechowuje argument Y. Tak przekonwertowane parametry podajemy jako argumenty funkcji SetCursorPos() mającej swoje korzenie w Windows API (znajduje się ona w systemowej bibliotece "User32.dll" - dlatego też należy włączyć plik nagłówkowy <windows.h>).

Zakończenie

Właśnie stworzyliśmy nasze (prawdopodobnie pierwsze) rozszerzenie Matlaba wykorzystując wbudowany kompilator języka C. Użyliśmy funkcji systemowych by ustalić nową pozycje kursora. Będąc rzetelnym, należy nadmienić, że twórcy Matlaba - firma Mathworks - nie polecają wywoływania funkcji systemowych z poziomu aplikacji tego pakietu. Sugerują, że takie działanie może spowodować nieprawidłową pracę programu. Być może rzeczywiście, funkcje które wywoływane są synchronicznie mogą powodować czasowe "zawieszanie się" programu (spowodowane zablokowaniem funkcji okienkowej odbierającej komunikaty systemowe). Być może, kłopoty może sprawiać nam również specyficzne funkcjonowanie środowiska które uniemożliwia nam (normalny) dostęp do uchwytu okna w którym pracujemy (należy posługiwać się systemową funkcją FindWindow()). W naszym przypadku nie należy się jednak martwić o nieporządane zachowanie. Przynajmniej nie spotkałem się z takowym. Kod tworzonego rozszerzenia (i cały projekt) możecie pobrać stąd.

12345
Matlab - wywoływanie funkcji systemowych Autor opinii: Czytelnicy, data przesłania: 0

Skomentuj

Aby zamieścić komentarz, proszę włączyć JavaScript - niestety roboty spamujące dają mi niezmiernie popalić.






Komentarze czytelników

    Nie ma jeszcze żadnych komentarzy.
    Dexter