Windows.  Virus.  Bärbara datorer.  Internet.  Kontor.  Verktyg.  Förare

Den här artikeln riktar sig till dem som, precis som jag, är nybörjare inom C++-programmering och som av en slump eller önskan bestämde sig för att lära sig WinAPI.
Jag vill genast varna dig:
Jag gör inte anspråk på att vara en C++- eller WinAPI-guru.
Jag håller just på att lära mig och jag vill här ge några exempel och tips som gör det lättare för mig att lära mig funktionerna och mekanismerna i WinAPI.

I den här artikeln antar jag att du redan har blivit tillräckligt bekant med C++ för att kunna skapa klasser och överbelasta olika operatorer för dem, och att du redan har "gömt" några av dina mekanismer i klassen.

Skapa och använda konsolen

För att felsöka en Win32-applikation eller bara för att se hur allt händer inuti använder jag alltid konsolen.
Eftersom du skapar en GUI-applikation och inte en konsolapplikation, är konsolen inte ansluten. För att kalla det, hittades denna kod i djupet av Internet

If (AllocConsole())
{



std::ios::sync_with_stdio();
}
För enkelhetens skull råder jag dig att slå in den i en funktion. Till exempel:
void CreateConsole()
{
if (AllocConsole())
{
int hCrt = _open_osfhandle((long)GetStdHandle(STD_OUTPUT_HANDLE), 4);
*stdout = *(::_fdopen(hCrt, "w"));
::setvbuf(stdout, NULL, _IONBF, 0);
*stderr = *(::_fdopen(hCrt, "w"));
::setvbuf(stderr, NULL, _IONBF, 0);
std::ios::sync_with_stdio();
}

Den anropade konsolen fungerar bara i utgångsläge och den fungerar på samma sätt som i konsolapplikationer. Utdatainformation som vanligt - cout/wcout.
För att den här koden ska fungera måste du inkludera följande filer i projektet:
#omfatta
#inkludera #inkludera
och inkludera std-namnområdet i det globala namnområdet:
använder namnutrymme std;
Naturligtvis, om du inte vill göra detta, lägg helt enkelt till std:: till alla enheter som finns i den.

Arv av objekt för utdata och aritm. operationer

När jag skapade och studerade själva "fönstren" behövde jag alltid mata ut något värde till konsolen.
Till exempel:
Du får storleken på fönstrets klientområde med hjälp av GetClientRect-funktionen, där adressen till ett RECT-strukturobjekt skickas som en parameter för att fylla detta objekt med data. Om du behöver veta storleken på det mottagna klientområdet kan du helt enkelt visa det i den redan anslutna konsolen

Cout<

Men att göra detta varje gång (speciellt om du ofta måste göra något sådant här) är väldigt obekvämt.
Det är här arvet kommer till vår hjälp.
Skapa en klass som öppet ärver från RECT-strukturen och överbelasta utdataoperatören<< так, как вам угодно.
Till exempel:

Klass newrect:public RECT
{
offentlig:
vän ostream& operatör<<(ostream &strm,newrect &rect)
{
strm<<"Prtint RECT object:\n";
strm<retur strm;
}
};

Nu är det bara att mata ut objektet med cout/wcout:

Cout<

Och allt kommer att visas för dig i en bekväm form som du behöver.
Du kan göra detsamma med alla operatörer du behöver.
Till exempel, om du behöver jämföra eller tilldela strukturer (till exempel RECT eller POINT), överbelastningsoperatör==() respektive operator=().
Om du vill implementera mindre än-operatören< что бы быстро сравнивать размеры окна и т.д. перегрузите operator<().
Du kan göra detta, antar jag, med nästan vilken struktur som helst, och det viktigaste är att alla funktioner som fungerar med ett vanligt RECT-strukturobjekt kommer att fungera lika bra med dess arvtagare.
Och jag rekommenderar också att du lägger all denna skönhet i en separat medföljande fil och använder den om det behövs.

Din klass

Jag vet inte om andra, men eftersom jag är helt grön bestämde jag mig för att skapa ett nytt projekt för varje funktion jag studerade eller för varje kapitel/delkapitel i en bok, så att allt skulle finnas på hyllorna och jag kunde komma tillbaka när som helst och fräscha upp mitt minne av de nödvändiga punkterna.
Eftersom i WinAPI, även för att skapa det enklaste fönstret, måste du fylla i en klassstruktur, registrera den och skriva en trivial fönsterprocedur, efter det tredje eller fjärde projektet kom jag ihåg att jag fortfarande skrev i C++.
Till slut gömde jag allt i ett enkelt klassrum. Fönsterhandtaget, dess namn, klassnamn, adress till fönsterproceduren, fönsterklass (WNDCLASS) är alla dolda i den privata delen av klassen.
För att få dem räcker det att beskriva enkla Get-metoder, till exempel:
HWND GetHWND()
LPCTSTR GetClsName() etc.
Att fylla och registrera en fönsterklass, skapa själva fönstret och visa det görs i konstruktorn.
För enkelhetens skull kan du överbelasta konstruktorn och dölja fyllningen och registreringen av fönsterklassen i en separat privat klassfunktion och anropa den i var och en av konstruktörerna. Bekvämligheten med överbelastning är att jag ibland behöver skapa ett mycket enkelt fönster och jag ringer konstruktorn med två parametrar - fönsternamnet och applikationshänvisningen.
Andra gånger behöver jag skapa ett fönster med en speciell storlek, inte med standardfönsterproceduren och med någon annan specifik stil - jag anropar konstruktorn med de medföljande parametrarna.
Denna klass definieras i en separat include-fil, som finns i mappen include i IDE.
En mall för den här klassen:
klass BaseWindow
{
WNDCLASSEX_wcex;
TCHAR_klassnamn;
TCHAR_windowName;
HWND_hwnd;
bool _WindowCreation();
offentlig:
BaseWindow(LPCTSTR fönsternamn, HINSTANCE hInstance, DWORD-stil, UINT x, UINT y, UINT höjd, UINT bredd);
BaseWindow(LPCTSTR fönsternamn,HINSTANCE hInstance);
const HWND GetHWND()const(retur HWND;)
LPCTSTR GetWndName()const(return _windowName;)
};

När du väl har tänkt igenom och skrivit en sådan klass kommer du att göra ditt liv enklare och kommer att lägga mer tid på att lära dig och finslipa dina färdigheter än att skriva samma sak varje gång. Dessutom tror jag att det är väldigt användbart att själv skapa en sådan klass och komplettera den vid behov.

P.S.

Allt som beskrivs är sant för:
Plattform - Windows 7 32 bit
IDE - Visual Studio 2010
Kanske kommer dessa tips att orsaka skratt och ironi för vissa, men ändå var vi alla en gång nybörjare/praktikanter/juniorer i något.
Behandla detta inlägg med förståelse. Konstruktiv kritik är naturligtvis välkommen.

Slutligen! Slutligen! Idag börjar vi skapa ett fullfjädrat Windows-fönster. Hejdå stackars konsol!!!

Vid det här laget bör du redan ha goda kunskaper i C++ syntax, kunna arbeta med grenar och loopar och ha en god förståelse för hur funktioner fungerar. Om du har bemästrat sjöstriden kan du anse att du har lärt dig allt detta.

Ungerskt inspelningsformulär

All kod som vi kommer att stöta på i WinAPI är skriven i ungersk form. Detta är en kodningskonvention.

I det här fallet föregås variabelnamnet av typens initiala bokstav. Alla ord i variabel- och funktionsnamn börjar med stor bokstav.

Här är några prefix:

b är en variabel av typen bool.
l är en variabel av lång heltalstyp.
w - från ord (ord) - 16 bitar. Variabel av typ osignerad kort.
dw - från dubbelord (dubbelord) - 32 bitar. Variabel av typ osignerad lång.
sz - sträng avslutad noll. Bara en vanlig linje som vi använde hela tiden.
p eller lp - pekare (från pekare). lp (från long pointer) - dessa pekare har kommit från det förflutna. Nu betyder lp och p samma sak.
h - deskriptor (från handtag).

Till exempel kommer pekaren att kallas så här:

void* pData;

Detta inspelningsformulär används av Microsoft. Många människor kritiserar detta sätt att namnge variabler. Men sådana här saker (kodningsavtal) är avgörande i stora företag.

Låt mig påminna dig om att konstanta identifierare vanligtvis endast består av stora bokstäver: WM_DESTROY. WM_DESTOY är 2, konstanten definieras via definiera.

Dessutom använder winAPI många åsidosatta typer. Här på denna sida - http://msdn.microsoft.com/en-us/library/aa383751(VS.85).aspx, kan du hitta beskrivningar av alla typer av Windows (på engelska).

Och en sak till som vi inte förstod. Pekare tilldelas ofta värdet NULL. Tänk på att det bara är 0 och pekare som tilldelas värdet NULL (noll) pekar inte på någon minnesplats.

Windows API (WinAPI)

Alla Windows-program använder ett speciellt programmeringsgränssnitt, WinAPI. Det är en uppsättning funktioner och strukturer i C-språket som gör ditt program kompatibelt med Windows.

Windows API har enorma möjligheter för att arbeta med operativsystemet. Man kan till och med säga obegränsat.

Vi kommer inte att överväga ens en procent av alla WinAPI-funktioner. Från början ville jag ta mer material, men det skulle ta för mycket tid, och när vi fastnade i WinAPI-träsket skulle vi komma till DirectX om ett par år. Beskrivningen av WinAPI kommer att ta två lektioner (inklusive den här). . I dem kommer vi bara att titta på ramen för programmet under Windows.

Ett program för Windows har precis som ett program för DOS en huvudfunktion. Här kallas denna funktion WinMain.

WinMain funktion

Windows-programmet består av följande delar (allt detta händer i WinMain):

Skapa och registrera en fönsterklass. Ej att förväxla med C++-klasser. WinAPI är skrivet i C, det finns inga klasser i vår vanliga mening av ordet.
Skapa ett programfönster.
Huvudslingan där meddelanden behandlas.
Bearbetar programmeddelanden i en fönsterprocedur. En fönsterprocedur är en vanlig funktion.
Dessa fyra punkter är grunden för Windows-programmet. Under denna och nästa lektion kommer vi att titta på allt detta i detalj. Om du blir förvirrad i beskrivningen av programmet, gå tillbaka till dessa punkter.

Låt oss nu titta på allt detta i detalj:

WinAPI: WNDCLASS-struktur

Först och främst måste du skapa och fylla strukturvariabeln WNDCLASS och sedan registrera en fönsterklass baserad på den.

Så här ser strukturen ut:

C++-kod typedef struct ( UINT-stil; // fönsterstil WNDPROC lpfnWndProc; // pekare till fönsterproceduren int cbClsExtra; // extra bytes efter klassen. Alltid inställd på 0 int cbWndExtra; // extra bytes efter fönsterinstansen. Alltid inställd på 0 HINSTANCE hInstance;

WNDCLASS-strukturen som en del av WinAPI bestämmer de grundläggande egenskaperna för det skapade fönstret: ikoner, typ av muspekare, om fönstret har en meny, vilket program fönstret kommer att tillhöra...

När du har fyllt i den här strukturen kan du registrera en fönsterklass baserad på den. Vi pratar inte om klasser som de i C++. Snarare kan vi tänka på fönsterklassen som en mall du registrerade den i systemet, och nu kan du skapa flera fönster baserat på denna mall. Och alla dessa fönster kommer att ha de egenskaper som du definierade i strukturvariabeln WNDCLASS.

WinAPI: CreateWindow-funktion

Efter registrering av fönsterklassen skapas huvudapplikationsfönstret på grundval av den (vi har nu gått vidare till den andra punkten). Detta görs med hjälp av CreateWindow-funktionen. Den har följande prototyp:

C++-kod HWND CreateWindow(LPCTSTR lpClassName, // klassnamn LPCTSTR lpWindowName, // fönsternamn (visas i titeln) DWORD dwStyle, // fönsterstil int x, // horisontell koordinat från skärmens vänstra kant int y, // vertikal koordinat från skärmens övre kant int nWidth, // fönsterbredd int nHeight, // fönsterhöjd HWND hWndParent, // överordnat fönster HMENU hMenu, // menyhandtag HINSTANCE hInstance, // applikationsinstans LPVOID lpParam // alltid inställd på NULL );

Om i fönsterklassen (WNDCLASS-struktur) fönstrets grundläggande egenskaper är inställda, så är de här mer specifika för varje fönster: fönsterstorlek, koordinater...

Denna funktion returnerar ett handtag till fönstret. Med hjälp av ett handtag kan du referera till ett fönster, det är ungefär som en identifierare.

Observera att det finns många nya typer här. Faktum är att de alla är gamla, bara omdefinierade. Till exempel: HWND är en åsidosättning av HANDLE, som i sin tur är en åsidosättning av PVOID, som i sin tur är en åsidosättande av void*. Hur djupt ligger sanningen begravd! Men ändå är HWND-typen en pekare till ogiltigförklaring.

Fönstret består av flera delar. I nästan alla program kommer du att se: en fönstertitel, en systemmeny (om du klickar på programikonen i den övre vänstra delen av fönstret), tre systemknappar för att arbeta med fönstret: minimera, expandera till helskärm och stäng . Dessutom finns det nästan alltid en meny i applikationen. Vi kommer definitivt inte ha det sistnämnda. Och, naturligtvis, är det mesta av fönstret upptaget av den så kallade. det klientområde där användaren vanligtvis arbetar.

Detta gäller för fönsterläge. Under ganska lång tid kommer vi att träna med DiectX i ett fönster - vi kommer inte att använda helskärmsläge.

Meddelandehantering

Den största skillnaden mellan alla våra tidigare program och program för Windows är meddelandebehandling.

Till exempel, när användaren trycker på en tangent på tangentbordet, genereras ett meddelande om att en tangent trycktes. Detta meddelande skickas sedan till applikationen som var aktiv när användaren tryckte på knappen.

Här har vi en händelse - en tangent trycktes.

En händelse kan vara: flytta muspekaren, ändra programfokus, trycka på en tangentbordstangent, stänga ett fönster. Det finns många evenemang. Mycket! Dussintals händelser kan inträffa i operativsystemet per sekund.

Så när en händelse inträffar skapar operativsystemet ett meddelande: en sådan och en sådan tangent trycktes, koordinaterna för muspekaren ändrades, ett nytt fönster öppnades.

Meddelanden kan skapas av både operativsystemet och olika applikationer.

Budskapet är en struktur och ser ut så här:

C++-kod typedef struct tagMSG ( HWND hwnd; // fönster som kommer att ta emot detta meddelande UINT-meddelande; // meddelandekod WPARAM wParam; // LPARAM-parameter lParam; // DWORD-tidsparameter; // tidpunkt då meddelandet inträffade POINT pt; // koordinater muspekare ) MSG;

Lägg märke till hur typedefs omdefinierar strukturer.

För att skapa denna struktur kan du använda följande kod:

C++-kod msg.messgae == 2; // dessa två rader är likvärdiga eftersom msg.message == WM_DESTROY; // konstant WM_DESTROY är lika med två

Här jämförs fältet som innehåller meddelandekoden (meddelandenamn) med konstanten WM_DESTROY - från Windows Message (Windows-meddelandet WM_DESTROY är meddelandet som genereras när fönstret stängs (destroy - destroy).

Meddelandekoder definieras med konstanter och har prefixet WM_: WM_CLOSE, WM_CREATE, etc.

MSG-strukturen innehåller HWND-typen - från Window Handle (fönsterhandtag eller fönsterdeskriptor). Det här är en sak som "beskriver" ett fönster. Det är ungefär som en identifierare (fönsternamn).

Kom ihåg detta ord - handtag (deskriptor, deskriptor). I Windows används detta koncept väldigt ofta. Nästan alla Windows-typer som börjar med H är handtag: ikonhandtag, teckensnittshandtag, applikationsinstanshandtag. Det är ett trettiotal av dem såvitt jag minns.

All interaktion mellan applikationer i Windows utförs med just dessa fönsterdeskriptorer (HWND).

Det finns en annan viktig deskriptor - applikationsbeskrivningen (HINSTANCE - den första parametern i WinMain) - detta är en unik applikationsidentifierare, tack vare vilken operativsystemet inte kan blanda ihop två olika program. Det är ungefär som en streckkod. Vi ska titta på det senare.

Varje gång användaren utför någon åtgärd skapas och fylls i ett meddelande: handtaget på fönstret som ska ta emot detta meddelande ställs in, meddelandeidentifieraren ställs in, parametrarna fylls i, tiden (nuvarande) fylls i och koordinaterna för muspekaren anges (se struktur).

Meddelandet placeras sedan i operativsystemets meddelandekö. När det är dags för vårt meddelande skickas det till önskat fönster (windows vet vilket fönster varje meddelande ska skickas till tack vare deskriptorer). När ett meddelande kommer till en applikation placeras det i applikationens meddelandekö. Så fort det blir sin tur bearbetas det.

Titta, mellan det ögonblick då användaren utförde en åtgärd (en händelse inträffade och ett meddelande genererades) och det ögonblick då programmet reagerade på denna åtgärd (meddelandet bearbetades av programmet), inträffar många händelser. När allt kommer omkring, både i Windows meddelandekö och i applikationsmeddelandekön kan det finnas många meddelanden. I det första fallet kan vi prata om hundratals, i det andra fallet åtminstone flera.

Fönsterprocedur (WndProc)

Vi fortsätter från det ögonblick då meddelandet kom in i applikationsmeddelandekön. Så snart dess tur har nått den, bearbetas den. För att bearbeta meddelanden måste varje program ha en speciell funktion - en fönsterprocedur. Det brukar kallas WndProc (för fönsterprocedur). Anropet till fönsterproceduren finns i huvudprogramslingan och exekveras vid varje iteration av slingan.

Meddelanden (i form av MSG-strukturvariabler) faller in i denna funktion i form av parametrar: ett fönsterhandtag, en meddelandeidentifierare och två parametrar. Observera att fälten för tid och pt inte skickas till fönsterproceduren. Det vill säga, meddelandet har redan "demonterats".

Inuti fönsterproceduren finns en växlingsgren, där meddelandeidentifieraren kontrolleras. Här är ett exempel på en enkel fönsterprocedur (den fungerar fullt ut):

C++-kod// ignorera HRESULT och __stdcall för tillfället. Vi ska titta på dem senare HRESULT __stdcall WndProc(HWND hWnd, UINT meddelande, WPARAM wParam, LPARAM lParam) ( switch (meddelande) ( fall WM_PAINT: // meddelandebehandlingskod WM_PAINT return 0; case WM_DESTROY: // meddelandebehandlingskod WM_DESTROY return 0 ) // hanterare för alla andra meddelanden )

Och det sista är huvudslingan. Det är väldigt enkelt. Varje iteration av loopen kontrolleras programmets meddelandekö. Om det finns ett meddelande i meddelandekön dras det från kön. Sedan, i slingans kropp, anropas en fönsterprocedur för att behandla meddelandet som tagits från kön.

Det är i allmänhet allt för idag. Det är redan klart att ett WinAPI-program är mycket mer komplext än ett DOS-program. Som jag skrev ovan kommer vi i nästa lektion att analysera koden för ett program som körs.

Skapa ett nytt projekt som en övning. I fönstret Nytt projekt väljer du mallen - Win32Project (tills nu valde vi Win32 Console Application). I ett av följande fönster, markera inte kryssrutan Empty Project och IDE kommer att generera ett mallprogram.

Om du tittar noga på koden i filen project_name.cpp hittar du allt vi diskuterade: MSG-strukturvariabeln, fylla WNDCLASS-strukturen, skapa ett fönster med CreateWindow-funktionen, huvudprogramslingan. Dessutom definierar filen WndProc-funktionen. Den bearbetar flera meddelanden i switchgrenarna: WM_COMMAND, WM_PAINT, WM_DESTROY. Hitta allt i filen.

Utöver det vi har tittat på innehåller programmet en hel del tilläggskod. I nästa nummer ska vi titta på programkoden, där alla onödiga saker kommer att klippas bort. Det blir mycket enklare och tydligare än vad IDE genererar.

API (Application Programming Interface) är ett applikationsprogrammeringsgränssnitt, en term som ofta nämns av mjukvaruutvecklare. Om applikationen du utvecklar har en funktion som låter dig komma åt den från andra applikationer, så är detta din applikations API. Parametrarna som din funktion accepterar utgör dess API eftersom de är sätten för andra applikationer att interagera med funktionen.

Operativsystemet Windows tillhandahåller en stor uppsättning funktioner som gör att olika applikationer, inklusive Visual FoxPro-applikationer, kan utbyta information med Windows på en ganska låg nivå. Dessa funktioner kallas vanligtvis Windows API. Genom att använda Windows API i Visual FoxPro-applikationer kan du implementera funktioner som inte går att uppnå med vanliga språkverktyg.

Deklarera Windows API-funktioner i Visual FoxPro

Windows API-funktioner paketeras i dynamiskt länkade bibliotek (Dynamic Link Library, DLL). Som regel har filerna i sådana bibliotek tillägget dll. Innan du kan använda en Windows API-funktion i din applikation måste du meddela. För att deklarera en funktion, använd kommandot DECLARE..DLL:

FÖRKLARA [ cFunctionType] Funktionsnamn I LibraryName ; [cParamType1 [@] ParamName1, cParamType2 [@] ParamName2, ...]

Kommandoparametrar:

cFunctionType
valfri parameter, anger typen av data som returneras av funktionen:

cFunctionType Storlek,
byte
Beskrivning
Kort 16-bitars heltal
Heltal, lång 4 32-bitars heltal
Enda 4 32-bitars reellt tal
Dubbel 8 64-bitars reellt tal
Sträng - Teckensträng

Funktionsnamn
namnet på funktionen i DLL. Funktionsnamnet är skiftlägeskänsligt, vilket betyder att GetDC och GETDC är helt olika funktionsnamn.

LibraryName
Namnet på den DLL där funktionen finns. För biblioteken Kernel32.dll, Gdi32.dll, User32.dll, Mpr.dll och Advapi32.dll kan du använda synonymen WIN32API.

AliasName
valfri parameter, låter dig använda ett valfritt alias istället för funktionsnamnet. Stavningen av ett alias, till skillnad från ett funktionsnamn, är inte skiftlägeskänslig. Vanligtvis används ett alias när API-namnet på en funktion är detsamma som namnet på en inbyggd (eller din) Visual FoxPro-funktion.

cParamType
indikerar datatypen för värdet som skickas till funktionen:

Parametern kan skickas antingen genom värde eller genom referens. För att indikera att parametern skickas med referens, används symbolen "@".

Ur ett Visual FoxPro-perspektiv är det ingen skillnad mellan datatyperna Long och Integer. Typiskt används heltalstypen för att representera heltal med tecken, och typen lång används för att representera heltal utan tecken.

ParamName
en valfri parameter som är rent beskrivande och som i allmänhet ignoreras.

Alla Windows API-funktioner, såväl som själva Windows, är skrivna i programmeringsspråket C. Därför, för att förstå hur man korrekt använder API-funktioner i Visual FoxPro (som förresten också är skrivet i C, åtminstone dess kärna), låt oss bekanta oss med vilka datatyper som används i C och Windows, och, inte mindre viktigt, låt oss förstå datatyper som uppräkningar, strukturer och pekare. Dessutom får du lära dig vilka funktionsprototyper som finns i C, och hur det, baserat på beskrivningen av en funktionsprototyp i MSDN, är korrekt att deklarera den i kommandot DECLARE..DLL.

Grundläggande C-datatyper

Om du är bekant med programmeringsspråket C vet du hur enkelt det är att skapa olika typer av data i det. Det räcker med att skriva följande kod:

Typedef int INT32;

och nu har du en ny typ INT32, som helt motsvarar int-typen. Men ur C-synpunkt är dessa helt olika typer, och att försöka tilldela en variabel av typen INT32 till värdet av en variabel av typen int kommer att leda till ett fel!

Överflödet av datatyper gör att många utvecklare tycker att programmering med API:er är svårt. Men det är inte sant! Följande datatyper används huvudsakligen i C:

    typ röding - tecken i ANSI-format. Den är 8 bitar lång (en byte).

    typ wchar - tecken i Unicode-format. Den är 16 bitar lång (två byte).

    typ int - heltal. De är indelade i tre typer i C: int, kort int Och lång int. De senare förkortas vanligtvis till kort Och lång. Typ kort- det här är 16-bitars, och typerna int Och lång- 32-bitars heltal.

    typ flyta- reella tal som har en bråkdel. De är 32 bitar långa (4 byte).

    typ dubbel- dubbel precision reella tal. De är 64 bitar långa (8 byte).

    typ uppräkning - uppräknad datatyp.

    typ ogiltig används för att beteckna kvantiteter som har noll längd och inte har någon betydelse.

    typ pekare - pekare; den innehåller inte information i konventionell mening - som andra C-typer; istället innehåller varje pekare adressen till minnesplatsen där den faktiska datan lagras. Den är 32 bitar lång (4 byte).

Konstigt nog finns det ingen strängtyp i C. Faktum är att alla strängar representeras i C som arrayer av tecken.

Vissa typer kan deklareras som osignerade. Modifierare osignerad (osignerad) används med följande datatyper: röding, kort, int Och lång.

Till exempel följande variabeldeklaration i C:

Signerad int variabelnamn;

betyder att denna variabel är ett 32-bitars heltal utan tecken.

Modifierare konst indikerar att en variabel av den angivna typen är en konstant, det vill säga att dess värde inte kan ändras.

Enum typ uppräkning associerar en uppsättning namngivna konstanter som kallas uppräknade konstanter med en variabel. En uppräknad typdeklaration ser ut så här:

Enum tag_fält { konst1, konst2, ... } variabel;

Om tag_fältär utelämnad, måste du ange efter det avslutande lockiga hängslet variabel. Om tag_fält anges eller inte anges variabel.

Historiskt sett är enum-typen ekvivalent med int-typen - det vill säga en variabel av en uppräknad typ tar upp 4 byte i minnet. Varje uppräknad konstant har ett värde som bestäms av dess serienummer i listan; numrering börjar från noll. Tänk på CombineMode-uppräkningen:

Enum CombineMode( CombineModeReplace, CombineModeIntersect, CombineModeUnion, CombineModeXor, CombineModeExclude, CombineModeComplement );

I denna uppräkning har CombineModeReplace-konstanten värdet 0, CombineModeIntersect-konstanten har värdet 1, och så vidare; CombineModeComplement-konstanten har värdet 5.

Värdena för uppräknade konstanter kan specificeras explicit, som i följande exempel:

Enum DashCap( DashCapFlat = 0, DashCapRound = 2, DashCapTriangle = 3 );

Datatyperna som anges täcker 99 % av alla datatyper som används i Windows API-programmering. Det låter för enkelt, eller hur? Varför innehåller API-funktionsbeskrivningar alla dessa typer - HWND, HINSTANCE, POINT och liknande?

Anledningen till detta är att C har en funktion som kallas strikt maskinskrivning. När den är närvarande kan en variabel av en typ bara ta värden som motsvarar dess typ. Du kan inte först lagra en sträng i en variabel och sedan tilldela den ett nummer. I Visual FoxPro försöker vi vanligtvis simulera detta genom en namnkonvention. Till exempel är cName en teckenvariabel, medan nCount är en numerisk variabel. Strikt maskinskrivning låter dig skapa en ny datatyp genom att ge en befintlig datatyp ett nytt namn. Varje ny typ verkar vara annorlunda än andra typer, även om de internt lagrar samma sak.

Windows gör detta koncept svårt att använda. Till exempel är typen LONG faktiskt en lång int, och typen UINT är faktiskt en osignerad int. Båda typerna är 32-bitars heltal. Härledda datatyper definieras i olika include-filer (filer med filtillägget .h). Om du har köpt Visual Studio.NET kan du hitta dessa filer i mappen ..\VC7\PlatformSDK\Include\.

Windows datatyper

Att bestämma vilken grundläggande C-typ som faktiskt representerar datatypen som används i en funktions API är en av de svåraste uppgifterna i API-programmering. Använd följande regel: om du inte hittar ett ord flyta, dubbel, röding eller str var som helst i ett funktions- eller parameternamn, då är det vanligtvis ett 32-bitars heltal. Det kommer att ta lite tid att förstå och utveckla färdigheter, men då kommer du enkelt att kunna konvertera datatyper. Följande tabell visar de grundläggande Windows-datatyperna och deras motsvarande typer som används när en funktion deklareras i Visual FoxPro:

Datatyp
Windows
Skriv in annonsen
funktioner
Beskrivning
BOOL Lång 32-bitars heltal. 0 betyder falskt, allt annat betyder sant.
BOOLEAN Lång samma som BOOL.
BYTE Sträng 8-bitars heltal
RÖDING Sträng 8-bitars heltal
CLSID Sträng
FÄRG Lång 32-bitars heltal
DWORD Lång 32-bitars heltal
DUBBEL Dubbel 64-bitars reellt tal
FLYTA Enda 32-bitars reellt tal
GUID Sträng 128-bitars nummer (16 byte)
HANTERA Lång
HBITMAP Lång 32-bitars heltal utan tecken
HDC Lång 32-bitars heltal utan tecken
HICON Lång 32-bitars heltal utan tecken
HGLOBAL Lång 32-bitars heltal utan tecken
HKL Lång 32-bitars heltal utan tecken
HLOKALT Lång 32-bitars heltal utan tecken
HINSTANS Lång 32-bitars heltal utan tecken
HRESULTAT Lång 32-bitars heltal utan tecken
HWND Lång 32-bitars heltal utan tecken
LÅNG Lång 32-bitars heltal
LPARAM Lång 32-bitars heltal utan tecken
KORT Heltal 16-bitars heltal
SIZE_T Lång 32-bitars heltal utan tecken
TCHAR Sträng Motsvarar CHAR för strängar i ANSI-format och WCHAR för strängar i Unicode-format
UCHAR Sträng ANSI-tecken
UINT Lång 32-bitars heltal utan tecken
ULONG Lång 32-bitars heltal utan tecken
USKORT Heltal
UUID Sträng 128-bitars nummer (16 byte)
OGILTIG Inga spelar ingen roll
WCHAR Sträng UNICODE-tecken
WNDPROC Lång 32-bitars heltal utan tecken
ORD Heltal 16-bitars heltal utan tecken
WPARAM Lång 32-bitars heltal utan tecken

Vägvisare

Ett annat begrepp som används ofta i C är pekare. En pekare är en variabel som innehåller adressen till en minnesplats där data lagras. Typen av en pekare bestäms alltid av vilken typ av data den pekar på; dess storlek är alltid fyra byte. Till exempel är en pekare till en SHORT-variabel ett 32-bitars heltal, precis som en pekare till vilken annan datatyp som helst. Beskrivningen av en pekare, som används i Windows API-programmering, börjar med tecknen "LP", vilket betyder lång pekare, eller "lång pekare" som arbetar med 32-bitars minnesmodellen. Detta kan följas av ett "C" (const) tecken som indikerar att data inte ska ändras. Följande är en beskrivning av datatypen för variabeln vars adress är lagrad i pekaren. Till exempel är LPDWORD en pekare till en variabel av typen DWORD.

När en Windows API-funktion deklareras skickas pekare till numeriska data genom referens. Som ett exempel, betrakta GetFileSize-funktionen. Här är dess prototyp (mer om funktionsprototyper kommer att diskuteras nedan):

DWORD GetFileSize(HANDLE hFile, // filhandtag LPDWORD lpFileSizeHigh // pekare);

Den andra parametern som skickas till funktionen är en pekare till en DWORD-variabel i vilken funktionen kommer att placera filstorleken i byte.

Deklarerar denna funktion i Visual FoxPro:

DEKLARERA GetFileSize I WIN32API Long hFile, Long @ FileSizeHight

Som du kan se skickas FileSizeHight-parametern till funktionen följ länken, eftersom att passera genom referens är just att skicka en pekare.

Situationen med strängar är mer komplicerad. Som redan nämnts är teckensträngar i C arrayer, så i programmering fungerar API-typen typen str, definierar en uppsättning tecken av typen CHAR (respektive typ wstr definierar en teckenuppsättning av typen WCHAR). Följande tabell visar typerna av pekare till teckensträngar:

Pekartyp
per rad
Beskrivning
LPSTR Pekare till en modifierbar nollterminerad sträng i ANSI-format.
Skickas via länk LPCSTR
En pekare till en icke-modifierbar nollterminerad sträng i ANSI-format. Godkänd av värde
LPTSTR Motsvarar LPSTR-typen för ANSI-formatsträngar och LPWSTR-typen för UNICODE-formatsträngar. Skickas som referens.
LPCTSTR Motsvarar LPSTR-typen för ANSI-formatsträngar och LPWSTR-typen för UNICODE-formatsträngar. Godkänd av värde.
LPWSTR Pekare till en modifierbar nollterminerad UNICODE-sträng.

Pekare till teckendata kan skickas antingen genom referens eller genom värde - String-typen i en funktionsdeklaration i Visual FoxPro skickar alltid en pekare till en variabel som innehåller teckendata. Använd teckendata som skickas med referens endast när API-funktionen behöver ändra värdet på en parameter.

Strukturer

En struktur kan ses som en samling av variabler av olika typer som bildar en enda helhet. I C skapas en struktur med hjälp av ett nyckelord struktur följt av en valfri taggfält(tagg) och lista element strukturer:

Struktur tag_fält { element_type element1; element_type element2; ..... element_type elementN; };

Det är också möjligt att deklarera en struktur så här:

Struktur( element_type element1; element_type element2; ..... element_type elementN; } variabel;

Denna annons inkluderar inte taggfält och en så kallad anonym strukturell typ skapas; Denna syntax tillåter att en eller flera variabler associeras med denna strukturtyp, som i följande exempel:

Struktur(WORD wÅr; ORD; wMånad; wDayOfWeek; wDay; wHour; wMinut; wSecond wMillisekunder

; ) SYSTEMTIME, *PSYSTEMTIME; Strukturer är mycket lika Visual FoxPro-tabellposter. Så, om tabellen posten personlig,innehåller fält,fio adress

tlfnummer och e-post

, då används följande syntax för att komma åt tlfnumber-fältet:

Personligt.tlfnummer

Så här ser också en vädjan till ett strukturfält ut: wÅr SYSTEMTIME.wMinute ORD Visual FoxPro använder variabler som innehåller teckensträngar för att bilda strukturer. Till exempel, för SYSTEMTIME-strukturen som diskuteras ovan, behöver du en variabel som är 16 byte lång. De första två byten av denna variabel innehåller fältets värde wMånad, i de följande två byten - fältvärdet

, i de följande två byten - fältvärdet

och så vidare tills strukturen är fullständigt bildad. Och när man deklarerar en API-funktion i Visual FoxPro måste typen av parameter där variabeln som innehåller strukturen skickas vara av typen String. Du kommer att lära dig hur man skriver numerisk data till en strängvariabel lite senare.

Vid programmering av Windows API i C börjar beskrivningen av en pekare till en struktur med tecknen LP (Long Pointer), följt av namnet på strukturen. Således kommer en pekare till en SYSTEMTIME-struktur att vara av typen LPSYSTEMTIME, en pekare till en POINT-struktur kommer att vara av typen LPPOINT, och så vidare. Som du kan se är inget komplicerat, men tack vare detta koncept finns det ett extremt stort antal typer av pekare till strukturer. Om data i den överförda strukturen inte skulle ändras, deklareras en pekare till en sådan struktur så här: *

Här betyder CONST-modifieraren att data i strukturen inte ska ändras, och symbolen (*) efter strukturnamnet betyder att hela denna rad är en beskrivning av en pekare till strukturen. Följande exempel visar en prototyp av CopyRect-funktionen, som kopierar en struktur till en annan:

BOOL CopyRect(LPRECT lprcDst, KONST REKT * lprcSrc);

Beskrivning av funktionsprototyper i MSDN

Nu när allt har blivit mer eller mindre klart med datatyper, låt oss ta en närmare titt på C-konceptet för funktionsprototyper.

Enligt ANSI-standarden ska alla funktioner i C ha prototyper. Funktionsprototypen är ganska enkel:

return_type funktionsnamn( parameter_type(s) parameter_name(s));

Om prototypen anger VOID-typen som return_type, betyder det att funktionen inte returnerar några värden. Om VOID-typen anges som parameter_type, betyder det att funktionen inte har några parametrar.

Du kan hitta information om Windows API-prototyper som ingår i biblioteken Kernel32.dll, Gdi32.dll, User32.dll, Mpr.dll och Advapi32.dll i MSDN för Visual Studio.NET genom att gå till följande hjälpämnen i avsnittet Innehåll : :

MSDN bibliotek

Windows Development Win32 API SDK Documentacion Reference

I avsnittet Referens kan du se funktionsbeskrivningar genom att öppna ett av följande underavsnitt:

Här är en annan adress på MSDN, som också innehåller information om API-funktioner:

MSDN bibliotek

Användargränssnittsdesign och utveckling SDK Documentacion Windows Shell Shell Referens Shell Funktioner

Följande bild visar ett fragment av MSDN-hjälpfönstret:

Så här beskrivs till exempel CopyRect-funktionen i MSDN:

CopyRect

De CopyRect funktion kopierar koordinaterna för en rektangel till en annan.

BOOL CopyRect(
LPRECT lprcDst, // destinationsrektangel
KONST REK* lprcSrc// källrektangel
);

Parametrar

lprcDst
Pekare till RECT struktur som tar emot de logiska koordinaterna för källrektangeln.
lprcSrc
Pekare till RECT-strukturen vars koordinater ska kopieras i logiska enheter.

Returvärden

Om funktionen lyckas är returvärdet icke noll.
Om funktionen misslyckas är returvärdet noll.
Windows NT/2000/XP: Ring GetLastError för att få utökad felinformation.

Anmärkningar

Eftersom applikationer kan använda rektanglar för olika ändamål, använder rektangelfunktionerna inte en explicit måttenhet. Istället anges alla rektangelkoordinater och dimensioner i logiska tecken med tecken. Mappningsläget och funktionen där rektangeln används bestämmer måttenheterna.

Exempelkod

För ett exempel, se Använda rektanglar.

Krav

Windows NT/2000/XP: Ingår i Windows NT 3.1 och senare.
Windows 95/98/Me: Ingår i Windows 95 och senare.
Header: Deklareras i Winuser.h; inkluderar Windows.h.
Bibliotek: Använd User32.lib.

Som du kan se är informationen ganska omfattande. Funktionen returnerar ett BOOL-typvärde, två parametrar skickas till det: LPRECT-typ och CONST RECT* - pekare till strukturer av RECT-typ. När du deklarerar den här funktionen i Visual FoxPro måste du ange att den första parametern skickas med referens och den andra med värdet:

DECLARE Long CopyRect IN User32.dll String @ Dst, Sträng Src

Hur kom jag fram till att den här funktionen finns i User32.dll-biblioteket? Väldigt enkelt. I avsnittet rekommendationer ( Krav) Bibliotek-objektet säger: Använd User32.lib. Ersättare för förlängning lib förlängning dll- och det är det! Förresten, där, i Header-stycket, rapporteras vilken include-fil som innehåller beskrivningen av funktionsprototypen.

Men det är inte allt! Eftersom funktionen fungerar med strukturer innehåller dess beskrivning en hyperlänk till RECT-strukturen. Klicka på denna hyperlänk så visas en detaljerad beskrivning av strukturen på skärmen.

Bildar strukturer i Visual FoxPro

Den nionde versionen av Visual FoxPro har avsevärt utökat funktionerna för de inbyggda funktionerna BINTOC och CTOBIN. Dessa funktioner kan nu användas för att konvertera numeriska data till ett format som lämpar sig för användning i strukturer. Låt mig påminna dig om att BINTOC-funktionen konverterar ett tal till en sträng och CTOBIN-funktionen konverterar en sträng till ett tal.

Syntax för BINTOC-funktion:

BINTOC( nUttryck, eFlagga)

Av alla möjliga värden som en parameter kan ta eFlagga, vi är intresserade av följande:

CTOBIN funktions syntax:

CTOBIN(c Uttryck, eFlagga)

Möjliga parametervärden eFlagga:

Exempel på användning av dessa funktioner visas nedan:

CTOBIN(BINTOC(1000,55,"4RS"), "4RS") && Resultat: 1000 ? CTOBIN(BINTOC(-1000,55,"4RS"), "4RS") && Resultat: -1000 ? CTOBIN(BINTOC(1000,55,"F"), "4N") && Resultat: 1000,549987929 ? CTOBIN(BINTOC(-1000,55,"F"), "4N") && Resultat: -1000,549987929 ? CTOBIN(BINTOC(1000,55,"B"), "8N") && Resultat: 1000,55 ? CTOBIN(BINTOC(-1000,55,"B"), "8N") && Resultat: -1000,55

Som ett exempel, låt oss skriva RECT-strukturen till en Visual FoxPro-variabel. Denna struktur används i CopyRect-funktionen som diskuterades tidigare för att beskriva koordinaterna för ett rektangulärt område. Så här beskrivs den här strukturen i MSDN:

Typedef struct _RECT ( LONG vänster; LÅNG överst; LÅNG höger; LÅNG botten; ) RECT, *PRECT;

Som du kan se innehåller RECT-strukturen fyra fält, som vart och ett lagrar ett LONG-värde. För att generera den i Visual FoxPro behöver du en sträng på 16 byte lång.

Nedan är koden som deklarerar CopyRect-funktionen, konstruerar Dst- och Src-strukturerna för att skicka dem som parametrar till funktionen och sedan kopierar en struktur till den andra. Exemplet använder BINTOC-funktionen för att konvertera ett tal till en sträng:

DECLARE Long CopyRect I WIN32API String @ Dst, String Src * Bildar Src-strukturen cSrc = BINTOC(nLeft,"4RS") + BINTOC(nTop,"4RS") + ;

BINTOC(nRight,"4RS") + BINTOC(nBottom,"4RS") * Förbered utrymme för Dst-strukturen cDst = REPLICATE(CHR(0),16) nResult = CopyRect(@cDst, cSrc) && Kopiering

Följande exempel visar hur du med hjälp av CTOBIN-funktionen kan "tolka" en struktur och få de numeriska värdena för dess fält:

NLvänster = CTOBIN(SUBSTR(cDst,1,4), "4RS") && RECT.vänster nTtop = CTOBIN(SUBSTR(cDst,5,4), "4RS") && RECT.top nHöger = CTOBIN(SUBSTR(cDst, 9,4), "4RS") && RECT.right nBottom = CTOBIN(SUBSTR(cDst,13,4), "4RS") && RECT.bottom

Strukturer som innehåller pekare

Ganska ofta finns det en situation när strukturen som skickas till en Windows API-funktion innehåller pekare. Som ett exempel, tänk på StartDoc-funktionen, som skapar ett dokument för utskrift på en skrivare. Här är dess prototyp: Int StartDoc(HDC hdc , // hantera till DC CONST DOCINFO* lpdi

// innehåller filnamn);

Som du kan se är den andra parametern som skickas till funktionen en pekare till DOCINFO-strukturen. Detta är strukturen: Typedef struct(int cbSize ; cbSize LPCTSTR cbSize lpszDocName lpszOutput lpszDatatype;

DWORD Typedef struct(int fwType ;; ) DOCINFO, *LPDOCINFO; Det första fältet i strukturen,

I Visual FoxPro är det ganska svårt att skapa en struktur som innehåller pekare. Först måste du allokera ett minnesblock och få en pekare till det. För det andra är det nödvändigt att skriva om värdet på Visual FoxPro-variabeln i detta minne - sålunda kommer vi att ha en fullt implementerad pekmekanism. Det sista som återstår att göra är att placera pekarvärdet i strukturen. I det här fallet måste vi uppfylla ett väsentligt krav: det tilldelade minnet får inte vara flyttbart - annars kan det visa sig att vår pekare vid något tillfälle kommer att peka på ett område som våra data inte har något att göra!

Det finns flera alternativ för att få ett minnesblock. Du kan ta en "slice" från både Windows delade minne och minne som allokerats till processen (det vill säga din applikation). Den andra metoden har högre prestanda, men här kommer vi att betrakta Windows-metoden för att arbeta med minne som en enklare.

Funktionen GlobalAlloc hämtar ett minnesblock av angiven storlek från Windows och returnerar en pekare till det. Här är prototypen för denna funktion:

HGLOBAL GlobalAlloc(UINT uFlaggor, // minnesallokeringsattribut SIZE_T dwBytes// storlek i byte);

Parameter uFlaggor bestämmer hur minnet kommer att tilldelas. MSDN säger att det kan ta ett av följande värden:

Av tabellen följer det för parametern uFlaggor GPTR-värdet ska användas. Men hur vet du det somär detta meningen? Sök i MSDN för en beskrivning av GlobalAlloc-funktionen och i avsnittet Krav titta i vilken inkluderingsfil dess prototyp finns. Detta är filen Winbase.h. Det är här man ska leta efter en beskrivning av konstanternas värden. Här är ett fragment av denna fil, som definierar konstanterna som listas i tabellen:

/* Globala minnesflaggor */ #define GMEM_FIXED 0x0000 #define GMEM_MOVEABLE 0x0002 #define GMEM_NOCOMPACT 0x0010 #define GMEM_NODISCARD 0x0020 #define GMEM_ZEROINIT 0x0040 #DEfine 0x0040_0x0040 CARDABLE 0x0 100 #define GMEM_NOT_BANKED 0x1000 #define GMEM_SHARE 0x2000 #define GMEM_DDESHARE 0x2000 #define GMEM_NOTIFY 0x4000 #define GMEM_LOWER GMEM_NOT_BANKED #define GMEM_VALID_FLAGS 0x7F72 #define GMEM_INVALID_HANDLE 0x8000 #define GHND (GMEM_MOVEABLE | #GMEM_FINE ZEROGMINGPINTRIT) |

Därför är GPTR = GMEM_FIXED + GMEM_ZEROINIT = 0x0000 + 0x0040 = 0x0040.

Vilken storlek ska det tilldelade minnesblocket ha? Naturligtvis lika med längden på raden där dokumentnamnet är lagrat. Följande exempel visar stegen från att deklarera en API-funktion till att allokera ett minnesblock:

uFlaggor,Lång dwBytes cDocumentName = "Namn på dokumentet som ska skrivas ut" && Dokumentnamn nLenDocumentName = LEN(cDocumentName) && Stränglängd hGlobal = GlobalAlloc(GPTR, nLenDocumentName)

Nästa uppgift är att skriva om innehållet i variabeln cDocumentName till det resulterande minnesblocket. Låt oss använda den inbyggda Visual FoxPro SYS(2600)-funktionen för detta. Här är dess syntax:

SYS(2600, dwAddress, nLängd [, cNewString])

Funktionen fungerar olika beroende på vilken parameter som anges cNewString eller inte.

Om parametern cNewString anges, sedan kopieras funktionen nLängd byte från variabel cNewString i minnet på adressen som anges i dwAddress.

Om parametern cNewString inte specificerat, sedan returnerar funktionen nLängd byte från minnet på adressen som anges i dwAddress.

Som du kan se, parametern dwAddress- Det här ) DOCINFO, *LPDOCINFO;.

Låt oss skriva innehållet i cDocumentName-strängen i minnet som tilldelats av GlobalAlloc-funktionen:

SYS(2600, hGlobal, nLenDocumentName, cDocumentName)

Här är den fullständiga koden för att generera DOCINFO-strukturen:

#DEFINE GPTR 0x0040 DECLARE Long GlobalAlloc I WIN32API Long uFlaggor,Lång dwBytes cDocumentName = "Namn på dokumentet som ska skrivas ut" nLenDocumentName = LEN(cDocumentName) hGlobal = GlobalAlloc(GPTR, nLenDocumentName) SYS(2600, dwAddress, nLängd [, cNewString]) * Vi börjar bilda DOCINFO-strukturen * cDocInfo - en variabel i vilken strukturen cDocInfo = BINTOC(20,"4RS") && DOCINFO bildas. Typedef struct(int cDocInfo = cDocInfo + BINTOC(hGlobal,"4RS") && DOCINFO. ; cDocInfo = cDocInfo + REPLICATE(CHR(0),12) && Andra fält i strukturen * Slut på strukturbildning

Strukturen bildas i en variabel cDocInfo. I de första fyra byten skriver vi talet 20 - detta är storleken på strukturen (fält Typedef struct(int). De nästa fyra byten som läggs till variabeln är en pekare till minnesområdet där innehållet i variabeln cDocumentName - dokumentnamnet - skrivs. Sedan läggs ytterligare tolv nollbyte till variabeln - det här är strukturens fält LPCTSTR, lpszDocName Och lpszDatatype, som enligt dokumentationen kan ignoreras; detta betyder att fälten måste ha nollvärden. Resultatet blev alltså en sträng på 20 byte lång - vilket är vad som krävdes.

Funktioner för minnesanvändning

När du använder Windows API-funktioner i dina applikationer måste du vara medveten om att Visual FoxPro inte kan hantera minnet som reserverats av dessa funktioner. Därför, om du allokerar minne, till exempel med hjälp av GlobalAlloc-funktionen, måste du returnera detta minne till Windows efter användning genom att anropa GlobalFree-funktionen. För varje API-funktion som reserverar minne finns det en antipodfunktion som frigör det reserverade minnet.

Här är en prototyp av GlobalFree-funktionen:

HGLOBAL GlobalFree(HGLOBAL hMem // pekare till ett minnesblock);

Funktionen tar bara emot en parameter - en pekare till ett minnesblock. Här är dess deklaration och användning i Visual FoxPro:

DEKLARERA Long GlobalFree I WIN32API Long hGlobal GlobalFree(hGlobal)

här är hGlobal en pekare till minnesblocket som returneras av GlobalAlloc-funktionen.

Om du glömmer att återta tilldelat minne, riskerar du att stöta på ett problem som kallas minnesläcka. Konsekvenserna av en sådan läcka kan vara mycket tråkiga - från en kraftig nedgång av din applikation orsakad av minnesfragmentering till kraschen av operativsystemet.

Skicka arrayer till en funktion

I C-termer är en array en variabel som innehåller flera element av samma typ. Varje enskilt element i arrayen nås med hjälp av ett index. Alla arrayelement har samma storlek arrayer med blandade datatyper kan inte beskrivas. Alla arrayelement lagras i minnet sekventiellt, efter varandra, med det minsta indexvärdet som motsvarar det första elementet och det maximala värdet till det sista.

En Visual FoxPro-array har en helt annan organisation som låter dig lagra helt olika typer av data i dess element. Därför är det inte möjligt att skicka en array från Visual FoxPro till en Windows API-funktion bara genom att ange dess namn som en parameter. Dessutom innehåller kommandot DECLARE..DLL inte en datatyp som arrayer.

Ändå finns det en väg ut ur denna situation. Precis som med strukturer används teckenvariabler för att skicka arrayer. Den numeriska data från arrayen måste konverteras till en sträng, som du skickar som en parameter till Windows API-funktionen. Följande exempel visar koden för ArrayToString-funktionen, som genererar en sträng från en array. Funktionen får array taArray(länk) och flagga tlTypeOfValue, som indikerar hur värdena för arrayelementen ska konverteras - som heltal ( tlTypeOfValue=.F.) eller verklig ( tlTypeOfValue=.T.) nummer:

FUNCTION ArrayToString PARAMETERS taArray, tlTypeOfValue EXTERN ARRAY taArray LOCAL lnLenArray, lnIndex, lcStruct, lcType lcType = IIF(tlTypeOfValue = .t.") = A, (LenArray) elementet i lcStruct = "" FÖR lnIndex = 1 TILL lnLenArray lcStruct = lcStruct + BINTOC(taArray, lcType) ENDFOR RETURN lcStruct ENDFUNC

Funktionen fungerar med både endimensionella och tvådimensionella arrayer.

Teckendatakodning: ANSI- och UNICODE-format

I ANSI-kodning (används i Visual FoxPro) definieras varje tecken av en byte, det vill säga det maximala antalet tecken är 256, vilket naturligtvis är mycket litet. Till exempel, under förryskningen, ersätts vissa ANSI-standardtecken med kyrilliska tecken. Och i vissa alfabet, till exempel japanska kana, finns det så många tecken att en byte helt enkelt inte räcker för att koda dem. För att stödja sådana språk, och, ännu viktigare, för att göra program lättare att "översätta" till andra språk, utvecklades Unicode. Varje tecken i Unicode består av två byte, vilket gjorde det möjligt att utöka uppsättningen av giltiga tecken till 65536.

Ett ganska stort antal Windows API-funktioner använder Unicode-formatet när de arbetar med teckensträngar. För att arbeta med sådana funktioner måste du konvertera teckendata från ett format till ett annat.

Den inbyggda Visual FoxPro STRCONV-funktionen konverterar strängar från ANSI till UNICODE och vice versa. Här är dess syntax:

STRCONV( cUttryck, nConversionSetting [, nRegionalIdentifier [, nRegionalIDType]])

Parameter cUttryckär strängen som behöver konverteras. Parameter nConversionSetting anger omvandlingens karaktär. Av alla dess möjliga värden är vi bara intresserade av två:

  • 5 - konvertera från ANSI till UNICODE
  • 6 - konvertera från UNICODE till ANSI

Valfria parametrar nRegionalIdentifier Och nRegionalIDType definiera ytterligare regionala inställningar och kan säkert ignoreras.

Exempel på användning av STRCONV-funktionen visas nedan:

CUnicodeString = STRCONV(cANSISString, 5) && Konvertera till Unicode cANSIString = STRCONV(cUnicodeString, 6) && Konvertera till ANSI

Du kanske har fått intrycket av att läsa det här avsnittet att det är ganska enkelt att arbeta med Windows API-funktioner i Visual FoxPro. Både ja och nej. Till exempel använder vissa API-funktioner datatyper som inte stöds av kommandot DECLARE..DLL, till exempel 64-bitars heltal. Det finns även ett antal funktioner som kallas återuppringningsfunktioner. I prototypen för en sådan funktion finns CALLBACK-modifieraren före beskrivningen av returtypen. Tyvärr kan man inte använda sådana funktioner, åtminstone inte direkt. Det händer också att strukturen innehåller en pekare till en funktion – sådana API:er kan inte heller användas i Visual FoxPro.

WindowsAPI (applicationprogramminginterface) är ett systemprogrammeringsgränssnitt i användarläge för Windows-familjen av operativsystem. Innan 64-bitarsversioner av Windows släpptes kallades programmeringsgränssnittet för 32-bitarsversioner av Windows operativsystem Win32 API för att skilja det från den ursprungliga 16-bitarsversionen av Windows API (som fungerade som programmeringsgränssnitt för initiala 16-bitarsversioner av Windows).

Windows API består av flera tusen anropsbara funktioner, som är indelade i följande huvudkategorier:

  • Bastjänster.
  • Komponenttjänster.
  • Användargränssnittstjänster.
  • Grafik- och multimediatjänster.
  • Meddelanden och samarbete.
  • Nätverk.
  • Webbtjänster.

En beskrivning av WindowsAPI finns i dokumentationen för Windows Software Development Kit (SDK). Denna dokumentation finns tillgänglig på www.msdn.microsoft.com. Det ingår också med alla prenumerationsnivåer i Microsoft DeveloperNetwork (MSDN), ett nätverk designat för utvecklare.

Microsoft .NET Framework består av ett klassbibliotek som kallas Framework Class Library (FCL) och en hanterad kodkörning, Common Language Runtime (CLR). CLR har funktioner som just-in-time kompilering, typkontroll, sophämtning och kodåtkomstsäkerhet. Genom att erbjuda dessa funktioner ger CLR en utvecklingsmiljö som förbättrar programmerarens produktivitet och minskar vanliga programmeringsfel.

CLR är implementerad som en klassisk COM-server, vars kod finns i ett standard Windows DLL-bibliotek designat för att fungera i användarläge. Praktiskt taget alla komponenter i .NET Framework är implementerade som standard Windows-användarläges-DLL:er skiktade ovanpå ohanterade Windows API-funktioner. (Ingen av .NET Framework-komponenterna körs i kärnläge.) Relationen mellan dessa komponenter visas i figuren.

Tjänster, funktioner och standardprogram.

Vissa termer i Windows användar- och mjukvarudokumentation har olika betydelser i olika sammanhang. Till exempel kan ordet tjänst hänvisa till en standardrutin som anropas av operativsystemet, en enhetsdrivrutin eller en serviceprocess. Exakt vad dessa eller andra termer betyder visas i följande lista:

  • Windows API-funktioner. Dokumenterade, anropsbara rutiner i WindowsAPI. Till exempel CreateProcess, CreateFile och GetMessage.
  • Inbyggda systemtjänster (eller systemanrop). Odokumenterade kärntjänster i operativsystemet som anropas när de körs i användarläge. Till exempel är NtCreateUserProcess en intern tjänst som Windows CreateProcess-funktionen anropar för att skapa en ny process.
  • Kernelstödfunktioner (eller rutiner). Rutiner inom Windows operativsystem som endast kan anropas från kärnläge. ExAllocatePoolWithTag är till exempel en rutin som anropas av enhetsdrivrutiner för att allokera minne från Windows-system dynamiskt allokerade områden (kallade pooler).
  • Windows-tjänster. Processer som startas av Service Control Manager (Windowsservicecontrolmanager). Till exempel körs Task Manager-tjänsten som en process i användarläge som stöder kommandot at (liknande UNIX-kommandona at eller cron).
  • DLL:er (dynamiska länkbibliotek). En uppsättning anropsbara rutiner länkade samman som en binär fil som kan laddas dynamiskt av applikationer som använder rutinerna. Exempel inkluderar Msvcrt.dll (ett körtidsbibliotek för applikationer skrivna i C) och Kernel32.dll (ett av Windows API-undersystembibliotek). DLL-filer används ofta av Windows-komponenter och applikationer som körs i användarläge. Fördelen med DLL-filer framför statiska bibliotek är att de kan användas av flera applikationer, och Windows säkerställer att det bara finns en kopia av DLL-koden i minnet för de applikationer som refererar till DLL:n. Observera att icke-körbara .NET-sammansättningar kompileras som DLL-filer, men utan några exporterade rutiner. CLR analyserar den kompilerade metadatan för att komma åt lämpliga typer och klassmedlemmar.

Historia för Win32 API.

Intressant nog var Win32 inte tänkt att vara det ursprungliga programmeringsgränssnittet för det som då kallades Windows NT. Eftersom Windows NT-projektet lanserades som en ersättning för OS/2 version 2, var det ursprungliga programmeringsgränssnittet 32-bitars OS/2 PresentationManagerAPI. Men ett år efter lanseringen av projektet tog Microsoft Windows 3.0, som började säljas, fart. Som ett resultat ändrade Microsoft riktning och gjorde Windows NT till en framtida ersättning för Windows-produktfamiljen snarare än en ersättning för OS/2. I detta avseende uppstod behovet av att utveckla en Windows API-specifikation - innan dess, i Windows 3.0, existerade API:et endast som ett 16-bitars gränssnitt.

Även om Windows API var avsett att introducera många nya funktioner som inte är tillgängliga i Windows 3.1, beslutade Microsoft att göra det nya API:et så kompatibelt med namngivning, semantik och datatyper som möjligt med 16-bitars Windows API, för att underlätta bördan av portering befintliga 16-bitars Windows-applikationer i Windows NT. Detta förklarar faktiskt det faktum att många av namnen på funktioner och gränssnitt kan verka inkonsekventa: detta var nödvändigt för att säkerställa kompatibilitet mellan det nya Windows API och det gamla 16-bitars Windows API.

En förkortning för API, Application Programming Interface (API) är helt enkelt någon färdig uppsättning funktioner som applikationsutvecklare kan använda. I allmänhet motsvarar detta koncept det som tidigare oftare kallades ett subrutinbibliotek. Men oftast refererar API till någon speciell kategori av sådana bibliotek.

Under utvecklingen av nästan vilken ganska komplex applikation (MyApplication) som helst för slutanvändaren, bildas en uppsättning specifika interna funktioner som används för att implementera just detta program, som kallas MyApplication API. Det visar sig ofta att dessa funktioner också effektivt kan användas för att skapa andra applikationer, inklusive av andra programmerare. I det här fallet måste författarna, baserat på strategin för att marknadsföra sin produkt, avgöra frågan - öppnar de åtkomst till denna uppsättning för externa användare eller inte? Om svaret är positivt, i beskrivningen av mjukvarupaketet, som dess fördel, visas frasen att "paketet innehåller en öppen uppsättning API-funktioner."

Således hänvisar ett API oftast till en uppsättning funktioner som ingår i en applikation, men som också är tillgängliga för användning i andra program. Till exempel har Excel, förutom sitt slutanvändargränssnitt, en uppsättning Excel API-funktioner som kan användas, särskilt när du skapar applikationer med VB.

Följaktligen är Windows API en uppsättning funktioner som är en del av själva operativsystemet och som samtidigt är tillgängliga för alla andra applikationer. Och i detta avseende är analogin med BIOS/DOS-systemavbrottsuppsättningen, som faktiskt är en DOS API, ganska berättigad.

Skillnaden är att sammansättningen av Windows API-funktionerna å ena sidan är mycket bredare jämfört med DOS, å andra sidan innehåller den inte många av de verktyg för direkt hantering av datorresurser som var tillgängliga för programmerare i tidigare OS. Dessutom utförs anrop till Windows API med hjälp av vanliga proceduranrop, och anrop till DOS-funktioner utförs genom en speciell processorinstruktion som kallas Interrupt.

Win16 API och Win32 API

Som du vet markerade förändringen från Windows 3.x till Windows 95 övergången från 16-bitars operativsystemsarkitektur till 32-bitars. Samtidigt ersattes 16-bitars Windows API (Win16 API) med en ny 32-bitars version (Win32 API). I det här fallet behöver du bara komma ihåg att, med några få undantag, är Win32 API-uppsättningen densamma för Windows 9x- och Windows NT-familjerna.

När du bekantar dig med Win API upptäcker du att många inbyggda funktioner inte är något annat än anrop till motsvarande systemprocedurer, utan endast implementerade i form av syntaxen för ett visst språk. Med hänsyn till detta bestäms behovet av att använda API:t av följande alternativ:

API-funktioner som är helt implementerade som inbyggda funktioner. Men ibland i det här fallet är det användbart att byta till att använda API, eftersom detta ibland kan förbättra prestandan avsevärt (särskilt på grund av frånvaron av onödiga transformationer av godkända parametrar).

Inbyggda funktioner implementerar endast ett specialfall av motsvarande API-funktion. Detta är ett ganska vanligt alternativ.

Ett stort antal API-funktioner har inga analoger alls i den nuvarande versionen av kompilatorer. Du kan till exempel inte ta bort en katalog med VB - för detta måste du använda funktionen DeleteDirectory.

Det bör också betonas att vissa API-funktioner (deras andel i Win API är mycket liten) inte kan anropas från program på grund av ett antal språkbegränsningar, till exempel oförmågan att arbeta med minnesadresser. Men i vissa fall kan icke-triviala programmeringstekniker hjälpa (särskilt när det gäller samma adresser).

Vinn APIOchDynamic Link Library (DLL)

Win API-uppsättningen är implementerad i form av dynamiska DLL:er.

I det här fallet menar vi med DLL den traditionella versionen av binära dynamiska bibliotek, som ger applikationer direkt tillgång till de nödvändiga procedurerna - subrutiner eller funktioner (ungefär samma sak som vad som händer när procedurer anropas inom ett projekt). Sådana bibliotek kan skapas med olika verktyg - VC++, Delphi, Fortran, Assembler.

Dynamiska biblioteksfiler har vanligtvis filtillägget .DLL, men detta är inte nödvändigt. För Win16 användes ofta tillägget .EXE för externa enhetsdrivrutiner med .DRV.

Det är svårt att bestämma det exakta antalet Windows API-funktioner och filerna som innehåller dem (men de finns alla i systemkatalogen). I detta avseende är det bättre att lyfta fram sammansättningen av biblioteken som utgör kärnan i operativsystemet och huvudbiblioteken med ytterligare viktiga funktioner.

Win32 API-bibliotek för Windows 95/98 operativsystemkärnan:

KERNEL32.DLL: lågnivåfunktioner för hantering av minne, uppgifter och andra systemresurser;

USER32.DLL: Det är huvudsakligen där användargränssnittets kontrollfunktioner finns;

GDI32.DLL: Graphics Device Interface library - olika funktioner för utmatning till externa enheter;

COMDLG32.DLL: Funktioner relaterade till användningen av dialogrutor för allmänna ändamål.

Huvudbibliotek med tilläggsfunktioner:

COMCTL32.DLL: En uppsättning ytterligare Windows-kontroller, inklusive Tree List och Rich Text;

MAPI32.DLL: funktioner för att arbeta med e-post;

NETAPI32.DLL: kontroller och nätverksfunktioner;

ODBC32.DLL: funktionerna i detta bibliotek behövs för att arbeta med olika databaser via ODBC-protokollet;

WINMM.DLL: Åtkomståtgärder för systemmedia.



Om du upptäcker ett fel markerar du ett textstycke och trycker på Ctrl+Enter
DELA: