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.
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.
Najpierw stworzymy sobie jakiś fajny interfejs graficzny. Formularz będzie posiadał jeden przycisk ;)
OK. Interfejs mamy już gotowy. Teraz pora na odpowiednie oprogramowanie przycisku.
function pushbutton1_Callback(hObject, eventdata, handles)
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.
/* 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;
}
mex 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.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>).
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.
| Brak komentarzy |
| Nie ma jeszcze żadnych komentarzy. Jeśli chcesz, wyraź pierwszy swoje zdanie na temat tego artykułu. |
Łukasz "Lukas" Wyporek
lukas.home.page@gmail.com