aboutsummaryrefslogtreecommitdiffstats
path: root/example
diff options
context:
space:
mode:
authorJason A. Donenfeld <Jason@zx2c4.com>2020-11-02 22:09:52 +0100
committerJason A. Donenfeld <Jason@zx2c4.com>2020-11-02 23:42:43 +0100
commit9a937c7a49ced541f805e8443c993b6de89324ac (patch)
treef5543e08c2dcb36bf53604398207a31a10f260e4 /example
parentapi: free beginning of heap object (diff)
downloadwintun-9a937c7a49ced541f805e8443c993b6de89324ac.tar.xz
wintun-9a937c7a49ced541f805e8443c993b6de89324ac.zip
example: rewrite and replace api's debug rundll32 functionality
Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
Diffstat (limited to 'example')
-rw-r--r--example/example.c318
-rw-r--r--example/example.vcxproj19
-rw-r--r--example/example.vcxproj.filters8
3 files changed, 231 insertions, 114 deletions
diff --git a/example/example.c b/example/example.c
index 02e1443..0914f3c 100644
--- a/example/example.c
+++ b/example/example.c
@@ -3,16 +3,31 @@
* Copyright (C) 2018-2020 WireGuard LLC. All Rights Reserved.
*/
-#include "../api/wintun.h"
+#include <winsock2.h>
+#include <Windows.h>
+#include <ws2ipdef.h>
+#include <iphlpapi.h>
+#include <ip2string.h>
#include <stdarg.h>
#include <stdio.h>
+#include "wintun.h"
-static WINTUN_GET_VERSION_FUNC WintunGetVersion;
-static WINTUN_SET_LOGGER_FUNC WintunSetLogger;
static WINTUN_CREATE_ADAPTER_FUNC WintunCreateAdapter;
static WINTUN_DELETE_ADAPTER_FUNC WintunDeleteAdapter;
+static WINTUN_DELETE_DRIVER_FUNC WintunDeleteDriver;
+static WINTUN_ENUM_ADAPTERS_FUNC WintunEnumAdapters;
+static WINTUN_FREE_ADAPTER_FUNC WintunFreeAdapter;
+static WINTUN_GET_ADAPTER_FUNC WintunGetAdapter;
+static WINTUN_GET_ADAPTER_DEVICE_OBJECT_FUNC WintunGetAdapterDeviceObject;
+static WINTUN_GET_ADAPTER_GUID_FUNC WintunGetAdapterGUID;
+static WINTUN_GET_ADAPTER_LUID_FUNC WintunGetAdapterLUID;
+static WINTUN_GET_ADAPTER_NAME_FUNC WintunGetAdapterName;
+static WINTUN_SET_ADAPTER_NAME_FUNC WintunSetAdapterName;
+static WINTUN_GET_VERSION_FUNC WintunGetVersion;
+static WINTUN_SET_LOGGER_FUNC WintunSetLogger;
static WINTUN_START_SESSION_FUNC WintunStartSession;
static WINTUN_END_SESSION_FUNC WintunEndSession;
+static WINTUN_GET_READ_WAIT_EVENT_FUNC WintunGetReadWaitEvent;
static WINTUN_RECEIVE_PACKET_FUNC WintunReceivePacket;
static WINTUN_RECEIVE_RELEASE_FUNC WintunReceiveRelease;
static WINTUN_ALLOCATE_SEND_PACKET_FUNC WintunAllocateSendPacket;
@@ -59,9 +74,8 @@ ConsoleLogger(_In_ WINTUN_LOGGER_LEVEL Level, _In_z_ const WCHAR *LogLine)
}
static DWORD
-LogLastError(_In_z_ const WCHAR *Prefix)
+LogError(_In_z_ const WCHAR *Prefix, _In_ DWORD Error)
{
- DWORD Error = GetLastError();
WCHAR *SystemMessage = NULL, *FormattedMessage = NULL;
FormatMessageW(
FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_MAX_WIDTH_MASK,
@@ -84,7 +98,6 @@ LogLastError(_In_z_ const WCHAR *Prefix)
ConsoleLogger(WINTUN_LOG_ERR, FormattedMessage);
LocalFree(FormattedMessage);
LocalFree(SystemMessage);
- SetLastError(Error);
return Error;
}
@@ -100,7 +113,7 @@ Log(_In_ WINTUN_LOGGER_LEVEL Level, _In_z_ const WCHAR *Format, ...)
}
static BOOL WINAPI
-CtrlHandler(DWORD CtrlType)
+CtrlHandler(_In_ DWORD CtrlType)
{
switch (CtrlType)
{
@@ -109,6 +122,7 @@ CtrlHandler(DWORD CtrlType)
case CTRL_CLOSE_EVENT:
case CTRL_LOGOFF_EVENT:
case CTRL_SHUTDOWN_EVENT:
+ Log(WINTUN_LOG_INFO, L"Cleaning up and shutting down...");
HaveQuit = TRUE;
SetEvent(QuitEvent);
return TRUE;
@@ -116,143 +130,249 @@ CtrlHandler(DWORD CtrlType)
return FALSE;
}
+static void
+PrintPacket(_In_ const BYTE *Packet, _In_ DWORD PacketSize)
+{
+ if (PacketSize < 20)
+ {
+ Log(WINTUN_LOG_INFO, L"Received packet without room for an IP header");
+ return;
+ }
+ BYTE IpVersion = Packet[0] >> 4, Proto;
+ WCHAR Src[46], Dst[46];
+ if (IpVersion == 4)
+ {
+ RtlIpv4AddressToStringW((struct in_addr *)&Packet[12], Src);
+ RtlIpv4AddressToStringW((struct in_addr *)&Packet[16], Dst);
+ Proto = Packet[9];
+ Packet += 20, PacketSize -= 20;
+ }
+ else if (IpVersion == 6 && PacketSize < 40)
+ {
+ Log(WINTUN_LOG_INFO, L"Received packet without room for an IP header");
+ return;
+ }
+ else if (IpVersion == 6)
+ {
+ RtlIpv6AddressToStringW((struct in6_addr *)&Packet[8], Src);
+ RtlIpv6AddressToStringW((struct in6_addr *)&Packet[24], Dst);
+ Proto = Packet[6];
+ Packet += 40, PacketSize -= 40;
+ }
+ else
+ {
+ Log(WINTUN_LOG_INFO, L"Received packet that was not IP");
+ return;
+ }
+ if (Proto == 1 && PacketSize >= 8 && Packet[0] == 0)
+ Log(WINTUN_LOG_INFO, L"Received IPv%d ICMP echo reply from %s to %s", IpVersion, Src, Dst);
+ else
+ Log(WINTUN_LOG_INFO, L"Received IPv%d proto 0x%x packet from %s to %s", IpVersion, Proto, Src, Dst);
+}
+
+static USHORT
+IPChecksum(BYTE *Buffer, DWORD Len)
+{
+ ULONG Sum = 0;
+ for (; Len > 1; Len -= 2, Buffer += 2)
+ Sum += *(USHORT *)Buffer;
+ if (Len)
+ Sum += *Buffer;
+ Sum = (Sum >> 16) + (Sum & 0xffff);
+ Sum += (Sum >> 16);
+ return (USHORT)(~Sum);
+}
+
+static void
+MakeICMP(_Inout_ BYTE Packet[28])
+{
+ memset(Packet, 0, 28);
+ Packet[0] = 0x45;
+ *(USHORT *)&Packet[2] = htons(28);
+ Packet[8] = 255;
+ Packet[9] = 1;
+ *(ULONG *)&Packet[12] = htonl((10 << 24) | (6 << 16) | (7 << 8) | (8 << 0)); /* 10.6.7.8 */
+ *(ULONG *)&Packet[16] = htonl((10 << 24) | (6 << 16) | (7 << 8) | (7 << 0)); /* 10.6.7.7 */
+ *(USHORT *)&Packet[10] = IPChecksum(Packet, 20);
+ Packet[20] = 8;
+ *(USHORT *)&Packet[22] = IPChecksum(&Packet[20], 8);
+ Log(WINTUN_LOG_INFO, L"Sending IPv4 ICMP echo request to 10.6.7.8 from 10.6.7.7");
+}
+
static DWORD WINAPI
-TestAdapter(_Inout_ DWORD_PTR Index)
+ReceivePackets(_Inout_ DWORD_PTR SessionPtr)
{
- /* Create adapter. */
- WCHAR AdapterName[MAX_ADAPTER_NAME];
- _snwprintf_s(
- AdapterName,
- _countof(AdapterName),
- _TRUNCATE,
- L"test-%d.%d-%zu",
- WINTUN_VERSION_MAJ,
- WINTUN_VERSION_MIN,
- Index);
- const GUID AdapterGuid = { 0xeef7ebf,
- WINTUN_VERSION_MAJ,
- WINTUN_VERSION_MIN,
- { (BYTE)Index & 0xff, 0xa, 0x33, 0xbf, 0x5c, 0x8, 0x4a, 0xc6 } };
+ WINTUN_SESSION_HANDLE Session = (WINTUN_SESSION_HANDLE)SessionPtr;
+ HANDLE WaitHandles[] = { WintunGetReadWaitEvent(Session), QuitEvent };
+
while (!HaveQuit)
{
- WINTUN_ADAPTER_HANDLE Adapter;
- BOOL RebootRequired = FALSE;
- DWORD Result = WintunCreateAdapter(L"Example", AdapterName, &AdapterGuid, &Adapter, &RebootRequired);
- if (Result != ERROR_SUCCESS)
+ BYTE *Packet;
+ DWORD PacketSize;
+ DWORD Result = WintunReceivePacket(Session, &Packet, &PacketSize);
+ switch (Result)
{
- Log(WINTUN_LOG_ERR, L"%s adapter creation failed.\n", AdapterName);
+ case ERROR_SUCCESS:
+ PrintPacket(Packet, PacketSize);
+ WintunReceiveRelease(Session, Packet);
+ continue;
+ case ERROR_NO_MORE_ITEMS:
+ if (WaitForMultipleObjects(_countof(WaitHandles), WaitHandles, FALSE, INFINITE) == WAIT_OBJECT_0)
+ continue;
+ return ERROR_SUCCESS;
+ default:
+ LogError(L"Packet read failed", Result);
return Result;
}
+ }
+ return ERROR_SUCCESS;
+}
- DWORDLONG WintunVersion = WintunGetVersion();
- Log(WINTUN_LOG_INFO,
- L"%s adapter created (Wintun %d.%d.%d.%d, reboot: %d).\n",
- AdapterName,
- (WintunVersion >> 48) & 0xffff,
- (WintunVersion >> 32) & 0xffff,
- (WintunVersion >> 16) & 0xffff,
- (WintunVersion >> 0) & 0xffff,
- RebootRequired ? 1 : 0);
+static DWORD WINAPI
+SendPackets(_Inout_ DWORD_PTR SessionPtr)
+{
+ WINTUN_SESSION_HANDLE Session = (WINTUN_SESSION_HANDLE)SessionPtr;
+ while (!HaveQuit)
+ {
+ BYTE *Packet;
+ WintunAllocateSendPacket(Session, 28, &Packet);
+ MakeICMP(Packet);
+ WintunSendPacket(Session, Packet);
- WINTUN_SESSION_HANDLE Session;
- HANDLE WaitHandles[2] = { NULL, QuitEvent };
- Result = WintunStartSession(Adapter, 0x100000, &Session, &WaitHandles[0]);
- if (Result != ERROR_SUCCESS)
- {
- Log(WINTUN_LOG_ERR, L"%s session creation failed.\n", AdapterName);
- goto cleanupAdapter;
- }
- while (!HaveQuit)
+ switch (WaitForSingleObject(QuitEvent, 1000 /* 1 second */))
{
- BYTE *Packet;
- DWORD PacketSize;
- Result = WintunReceivePacket(Session, &Packet, &PacketSize);
- switch (Result)
- {
- case ERROR_SUCCESS:
- // TODO: Process packet.
- WintunReceiveRelease(Session, Packet);
- continue;
- case ERROR_NO_MORE_ITEMS:
- if (WaitForMultipleObjects(_countof(WaitHandles), WaitHandles, FALSE, INFINITE) == WAIT_OBJECT_0)
- continue;
- goto cleanupSession;
- }
- Log(WINTUN_LOG_ERR, L"%s packet read failed (Code 0x%08X).\n", AdapterName, Result);
- goto cleanupSession;
+ case WAIT_ABANDONED:
+ case WAIT_OBJECT_0:
+ return ERROR_SUCCESS;
}
- cleanupSession:
- WintunEndSession(Session);
- cleanupAdapter:
- WintunDeleteAdapter(Adapter, TRUE, &RebootRequired);
}
return ERROR_SUCCESS;
}
-int
-main(void)
+static HMODULE
+InitializeWintun(void)
{
- Log(WINTUN_LOG_INFO, L"Wintun Test v%d.%d\n", WINTUN_VERSION_MAJ, WINTUN_VERSION_MIN);
-
HMODULE Wintun =
LoadLibraryExW(L"wintun.dll", NULL, LOAD_LIBRARY_SEARCH_APPLICATION_DIR | LOAD_LIBRARY_SEARCH_SYSTEM32);
if (!Wintun)
- return LogLastError(L"Failed to load wintun.dll");
- DWORD Result;
- if ((WintunGetVersion = (WINTUN_GET_VERSION_FUNC)GetProcAddress(Wintun, "WintunGetVersion")) == NULL ||
- (WintunSetLogger = (WINTUN_SET_LOGGER_FUNC)GetProcAddress(Wintun, "WintunSetLogger")) == NULL ||
- (WintunCreateAdapter = (WINTUN_CREATE_ADAPTER_FUNC)GetProcAddress(Wintun, "WintunCreateAdapter")) == NULL ||
- (WintunDeleteAdapter = (WINTUN_DELETE_ADAPTER_FUNC)GetProcAddress(Wintun, "WintunDeleteAdapter")) == NULL ||
- (WintunStartSession = (WINTUN_START_SESSION_FUNC)GetProcAddress(Wintun, "WintunStartSession")) == NULL ||
- (WintunEndSession = (WINTUN_END_SESSION_FUNC)GetProcAddress(Wintun, "WintunEndSession")) == NULL ||
- (WintunReceivePacket = (WINTUN_RECEIVE_PACKET_FUNC)GetProcAddress(Wintun, "WintunReceivePacket")) == NULL ||
- (WintunReceiveRelease = (WINTUN_RECEIVE_RELEASE_FUNC)GetProcAddress(Wintun, "WintunReceiveRelease")) == NULL ||
- (WintunAllocateSendPacket =
- (WINTUN_ALLOCATE_SEND_PACKET_FUNC)GetProcAddress(Wintun, "WintunAllocateSendPacket")) == NULL ||
- (WintunSendPacket = (WINTUN_SEND_PACKET_FUNC)GetProcAddress(Wintun, "WintunSendPacket")) == NULL)
+ return NULL;
+#define X(Name, Type) ((Name = (Type)GetProcAddress(Wintun, #Name)) == NULL)
+ if (X(WintunCreateAdapter, WINTUN_CREATE_ADAPTER_FUNC) || X(WintunDeleteAdapter, WINTUN_DELETE_ADAPTER_FUNC) ||
+ X(WintunDeleteDriver, WINTUN_DELETE_DRIVER_FUNC) || X(WintunEnumAdapters, WINTUN_ENUM_ADAPTERS_FUNC) ||
+ X(WintunFreeAdapter, WINTUN_FREE_ADAPTER_FUNC) || X(WintunGetAdapter, WINTUN_GET_ADAPTER_FUNC) ||
+ X(WintunGetAdapterDeviceObject, WINTUN_GET_ADAPTER_DEVICE_OBJECT_FUNC) ||
+ X(WintunGetAdapterGUID, WINTUN_GET_ADAPTER_GUID_FUNC) ||
+ X(WintunGetAdapterLUID, WINTUN_GET_ADAPTER_LUID_FUNC) ||
+ X(WintunGetAdapterName, WINTUN_GET_ADAPTER_NAME_FUNC) ||
+ X(WintunSetAdapterName, WINTUN_SET_ADAPTER_NAME_FUNC) || X(WintunGetVersion, WINTUN_GET_VERSION_FUNC) ||
+ X(WintunSetLogger, WINTUN_SET_LOGGER_FUNC) || X(WintunStartSession, WINTUN_START_SESSION_FUNC) ||
+ X(WintunEndSession, WINTUN_END_SESSION_FUNC) || X(WintunGetReadWaitEvent, WINTUN_GET_READ_WAIT_EVENT_FUNC) ||
+ X(WintunReceivePacket, WINTUN_RECEIVE_PACKET_FUNC) || X(WintunReceiveRelease, WINTUN_RECEIVE_RELEASE_FUNC) ||
+ X(WintunAllocateSendPacket, WINTUN_ALLOCATE_SEND_PACKET_FUNC) || X(WintunSendPacket, WINTUN_SEND_PACKET_FUNC))
+#undef X
{
- Result = LogLastError(L"Failed to get wintun.dll entries");
- goto cleanupWintun;
+ DWORD Result = GetLastError();
+ FreeLibrary(Wintun);
+ SetLastError(Result);
+ return NULL;
}
+ SetLastError(ERROR_SUCCESS);
+ return Wintun;
+}
+
+int
+main(void)
+{
+ HMODULE Wintun = InitializeWintun();
+ if (!Wintun)
+ return LogError(L"Failed to initialize Wintun", GetLastError());
+ WintunSetLogger(ConsoleLogger);
+ Log(WINTUN_LOG_INFO, L"Wintun library loaded");
+ DWORD Result;
HaveQuit = FALSE;
QuitEvent = CreateEventW(NULL, TRUE, FALSE, NULL);
if (!QuitEvent)
{
- Result = LogLastError(L"Failed to create event");
+ Result = LogError(L"Failed to create event", GetLastError());
goto cleanupWintun;
}
- WintunSetLogger(ConsoleLogger);
if (!SetConsoleCtrlHandler(CtrlHandler, TRUE))
{
- Result = LogLastError(L"Failed to set console handler");
+ Result = LogError(L"Failed to set console handler", GetLastError());
goto cleanupQuit;
}
- HANDLE Workers[MAXIMUM_WAIT_OBJECTS] = { 0 };
- for (size_t i = 0; i < _countof(Workers); ++i)
- if (!Workers[i])
- {
- Workers[i] = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)TestAdapter, (LPVOID)i, 0, NULL);
- if (!Workers[i])
- {
- Result = LogLastError(L"Failed to create thread");
- goto cleanupWorkers;
- }
- }
+ GUID ExampleGuid = { 0xdeadbabe, 0xcafe, 0xbeef, { 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef } };
+ WINTUN_ADAPTER_HANDLE Adapter;
+ Result = WintunGetAdapter(L"Example", L"Demo", &Adapter);
+ if (Result != ERROR_SUCCESS)
+ Result = WintunCreateAdapter(L"Example", L"Demo", &ExampleGuid, &Adapter, NULL);
+ if (Result != ERROR_SUCCESS)
+ {
+ LogError(L"Failed to create adapter", Result);
+ goto cleanupQuit;
+ }
+
+ DWORDLONG Version = WintunGetVersion();
+ Log(WINTUN_LOG_INFO,
+ L"Wintun v%d.%d.%d.%d loaded",
+ (Version >> 48) & 0xff,
+ (Version >> 32) & 0xff,
+ (Version >> 16) & 0xff,
+ (Version >> 0) & 0xff,
+ WINTUN_VERSION_MIN);
+
+ MIB_UNICASTIPADDRESS_ROW AddressRow;
+ InitializeUnicastIpAddressEntry(&AddressRow);
+ WintunGetAdapterLUID(Adapter, &AddressRow.InterfaceLuid);
+ AddressRow.Address.Ipv4.sin_family = AF_INET;
+ AddressRow.Address.Ipv4.sin_addr.S_un.S_addr = htonl((10 << 24) | (6 << 16) | (7 << 8) | (7 << 0)); /* 10.6.7.7 */
+ AddressRow.OnLinkPrefixLength = 24; /* This is a /24 network */
+ Result = CreateUnicastIpAddressEntry(&AddressRow);
+ if (Result != ERROR_SUCCESS)
+ {
+ LogError(L"Failed to set IP address", Result);
+ goto cleanupAdapter;
+ }
+
+ WINTUN_SESSION_HANDLE Session;
+ Result = WintunStartSession(Adapter, 0x40000, &Session);
+ if (Result != ERROR_SUCCESS)
+ {
+ LogError(L"Failed to create adapter", Result);
+ goto cleanupAdapter;
+ }
+
+ Log(WINTUN_LOG_INFO, L"Launching threads and mangling packets...");
+
+ HANDLE Workers[] = { CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)ReceivePackets, (LPVOID)Session, 0, NULL),
+ CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)SendPackets, (LPVOID)Session, 0, NULL) };
+ if (!Workers[0] || !Workers[1])
+ {
+ Result = LogError(L"Failed to create threads", GetLastError());
+ goto cleanupWorkers;
+ }
WaitForMultipleObjectsEx(_countof(Workers), Workers, TRUE, INFINITE, TRUE);
Result = ERROR_SUCCESS;
+
cleanupWorkers:
HaveQuit = TRUE;
SetEvent(QuitEvent);
for (size_t i = 0; i < _countof(Workers); ++i)
+ {
if (Workers[i])
{
WaitForSingleObject(Workers[i], INFINITE);
CloseHandle(Workers[i]);
}
- SetConsoleCtrlHandler(CtrlHandler, FALSE);
+ }
+ WintunEndSession(Session);
+cleanupAdapter:
+ WintunDeleteAdapter(Adapter, FALSE, NULL);
+ WintunFreeAdapter(Adapter);
cleanupQuit:
+ SetConsoleCtrlHandler(CtrlHandler, FALSE);
CloseHandle(QuitEvent);
cleanupWintun:
FreeLibrary(Wintun);
diff --git a/example/example.vcxproj b/example/example.vcxproj
index 4deb367..3c8d8d1 100644
--- a/example/example.vcxproj
+++ b/example/example.vcxproj
@@ -52,17 +52,14 @@
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)'=='Debug'" Label="Configuration">
- <ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
- <PlatformToolset>v142</PlatformToolset>
- <CharacterSet>Unicode</CharacterSet>
- <SpectreMitigation>false</SpectreMitigation>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)'=='Release'" Label="Configuration">
+ <WholeProgramOptimization>true</WholeProgramOptimization>
+ </PropertyGroup>
+ <PropertyGroup Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
- <UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v142</PlatformToolset>
- <WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet>
<SpectreMitigation>false</SpectreMitigation>
</PropertyGroup>
@@ -107,7 +104,15 @@
<LinkTimeCodeGeneration>UseLinkTimeCodeGeneration</LinkTimeCodeGeneration>
</Link>
</ItemDefinitionGroup>
+ <ItemDefinitionGroup>
+ <Link>
+ <AdditionalDependencies>iphlpapi.lib;kernel32.lib;ntdll.lib;ws2_32.lib;%(AdditionalDependencies)</AdditionalDependencies>
+ </Link>
+ <ClCompile>
+ <AdditionalIncludeDirectories>..\api</AdditionalIncludeDirectories>
+ </ClCompile>
+ </ItemDefinitionGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
-</Project>
+</Project> \ No newline at end of file
diff --git a/example/example.vcxproj.filters b/example/example.vcxproj.filters
index d292814..eb29fb9 100644
--- a/example/example.vcxproj.filters
+++ b/example/example.vcxproj.filters
@@ -5,14 +5,6 @@
<UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
<Extensions>cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
</Filter>
- <Filter Include="Header Files">
- <UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
- <Extensions>h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd</Extensions>
- </Filter>
- <Filter Include="Resource Files">
- <UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
- <Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>
- </Filter>
</ItemGroup>
<ItemGroup>
<ClCompile Include="example.c">