Skip to content

DLL Skeleton

A minimal C DLL with a set of exported system and string functions, plus a console test driver that calls every export.

Published Apr 2, 1996

This is the classic shape of a Win32 C DLL project: one source file full of __declspec(dllexport) functions, built into an import library, and a small console app that links against it to prove each export works. It makes a good skeleton when you are starting your own DLL - note how each function that returns a string uses a static buffer ring (64 slots) so repeated calls from multiple callers do not clobber each other's results.

The export list below covers the usual suspects: time and date formatting, machine/user names, OS version detection, directory paths, case conversion, number-to-string and string-to-number, substring extraction, uptime, memory statistics, and CPU information via GetSystemInfo.

#include <windows.h>
#include <stdio.h>
#include <stdlib.h>

/////////////////////////////////////////////////////////////////////
__declspec(dllexport) char *GetTime(void)
{
	static  SYSTEMTIME  st;
	static char   t [257];
	GetLocalTime(&st);
	GetTimeFormat(LOCALE_USER_DEFAULT,TIME_NOSECONDS,&st,NULL,t,64);
	return (t);
}
/////////////////////////////////////////////////////////////////////
__declspec(dllexport) char *GetLongDate(void)
{
	static  SYSTEMTIME  st;
	static char   d [257];
	GetLocalTime(&st);
	GetDateFormat(LOCALE_USER_DEFAULT,DATE_LONGDATE,&st,NULL,d,64);
	return (d);
}
/////////////////////////////////////////////////////////////////////
__declspec(dllexport) char *GetShortDate(void)
{
	static  SYSTEMTIME  st;
	static char   s [257];
	GetLocalTime(&st);
	GetDateFormat(LOCALE_USER_DEFAULT,DATE_SHORTDATE,&st,NULL,s,64);
	return (s);
}
/////////////////////////////////////////////////////////////////////
__declspec(dllexport) char *GetMachineName(void)
{
	static  char StrFunction [64][257];
	static int StrCnt;
	static char A[257];
	static  DWORD  b;
	if (++StrCnt==64) StrCnt = 0;
	b=256;
	GetComputerName(A,&b);
	sprintf(StrFunction[StrCnt],"%s",A);
	return StrFunction[StrCnt];
}
/////////////////////////////////////////////////////////////////////
__declspec(dllexport) char *GetLogonName(void)
{
	static  char StrFunction [64][257];
	static int StrCnt;
	static char A[257];
	static  DWORD  b;
	if (++StrCnt==64) StrCnt = 0;
	b=256;
	GetUserName(A,&b);
	sprintf(StrFunction[StrCnt],"%s",A);
	return StrFunction[StrCnt];
}
/////////////////////////////////////////////////////////////////////
__declspec(dllexport) char *GetOsVersion(void)
{
	DWORD dwVersion;
	char szBuf[80];
	char *WinVer_Number;
	static  OSVERSIONINFO  os;
	os.dwOSVersionInfoSize=sizeof(os);
	dwVersion = GetVersion();
	WinVer_Number = calloc(100, sizeof(char));

	if(GetVersionEx(&os))
	{
		for(;;)
		{
			if(os.dwPlatformId==1)
			{
				if(os.dwMinorVersion==0)
				{
					sprintf(szBuf, "Windows 95 %d.%d",LOBYTE(LOWORD(dwVersion)),HIBYTE(LOWORD(dwVersion)));
					strcat(WinVer_Number, szBuf);
				}
				if(os.dwMinorVersion==10)
				{
					sprintf(szBuf, "Windows 98 %d.%d",LOBYTE(LOWORD(dwVersion)),HIBYTE(LOWORD(dwVersion)));
					strcat(WinVer_Number, szBuf);
				}
				break;
			}
			if(os.dwPlatformId==2)
			{
				if(os.dwMajorVersion==3)
				{
					sprintf(szBuf, "Windows NT %d.%d",LOBYTE(LOWORD(dwVersion)),HIBYTE(LOWORD(dwVersion)));
					strcat(WinVer_Number, szBuf);
				}
				if(os.dwMajorVersion==4)
				{
					sprintf(szBuf, "Windows NT %d.%d",LOBYTE(LOWORD(dwVersion)),HIBYTE(LOWORD(dwVersion)));
					strcat(WinVer_Number, szBuf);
				}
				if(os.dwMajorVersion==5)
				{
					sprintf(szBuf, "Windows 2000 %d.%d",LOBYTE(LOWORD(dwVersion)),HIBYTE(LOWORD(dwVersion)));
					strcat(WinVer_Number, szBuf);
				}
			}
			break;
		}
	}
	return WinVer_Number;
}
/////////////////////////////////////////////////////////////////////
__declspec(dllexport) char *GetWorkingDirectory(void)
{
	static char StrFunction [64][257];
	static int StrCnt;
	static char T [257];
	GetCurrentDirectory(256,T);
	if (++StrCnt==64) StrCnt = 0;
	sprintf(StrFunction[StrCnt],"%s",T);
	return StrFunction[StrCnt];
}
/////////////////////////////////////////////////////////////////////
__declspec(dllexport) char *GetTempDirectory(void)
{
	static char StrFunction [64][257];
	static int StrCnt;
	static char T [257];
	GetTempPath (256,T);
	if (++StrCnt==64) StrCnt = 0;
	sprintf(StrFunction[StrCnt],"%s",T);
	return StrFunction[StrCnt];
}
/////////////////////////////////////////////////////////////////////
__declspec(dllexport) char *GetSysDirectory(void)
{
	static char StrFunction [64][257];
	static int StrCnt;
	static char T [257];
	GetSystemDirectory (T,256);
	if (++StrCnt==64) StrCnt = 0;
	sprintf(StrFunction[StrCnt],"%s",T);
	return StrFunction[StrCnt];
}
/////////////////////////////////////////////////////////////////////
__declspec(dllexport) char *UCase (char *S)
{
	static char StrFunction [64][257];
	static int StrCnt;
	static char Tmp [257];
	if(++StrCnt==64) StrCnt = 0;
	sprintf(Tmp,"%s",S);
	{
		sprintf (StrFunction[StrCnt],"%s",strupr(Tmp));
	}
	return StrFunction[StrCnt];
}
/////////////////////////////////////////////////////////////////////
__declspec(dllexport) char *LCase(char *S)
{
	static char StrFunction [64][257];
	static int StrCnt;
	static char Tmp [257];
	if(++StrCnt==64) StrCnt = 0;
	sprintf(Tmp,"%s",S);
	{
		sprintf (StrFunction[StrCnt],"%s",strlwr(Tmp));
	}
	return StrFunction[StrCnt];
}
/////////////////////////////////////////////////////////////////////
__declspec(dllexport) char *IntChar(double d)
{
	static int   StrCnt;
	LPSTR StrFunc [16];
	if (++StrCnt==16) StrCnt = 0;
	if (StrFunc[StrCnt]) free (StrFunc[StrCnt]);
	StrFunc[StrCnt] = (char*) malloc (2048);
	memset (StrFunc[StrCnt],0,2048);
	sprintf(StrFunc[StrCnt],"% .16g",d);
	return StrFunc[StrCnt];
}
/////////////////////////////////////////////////////////////////////
__declspec(dllexport) int CharInt(char *string2convert)
{
	int i, lenght_string;
	int power;
	int tmp_number;
	char tmp_char;
	if (!string2convert)
	{
		return 0;
	}
	lenght_string = strlen(string2convert);
	for(i = 0; i < (lenght_string / 2); i++)
	{
		tmp_char = string2convert[i];
		string2convert[i] = string2convert[lenght_string - 1 - i];
		string2convert[lenght_string - 1 - i] = tmp_char;
	}
	power = 1;
	i = 0;
	tmp_number = 0;
	while (string2convert[i] != '\0')
	{
		tmp_number += (string2convert[i] - '0') * power;
		power *= 10;
		i++;
	}
	return tmp_number;
}
/////////////////////////////////////////////////////////////////////
__declspec(dllexport) char *StringScan(char *S, int length1, int length2)
{
	static  char StrFunction [64][257];
	static int StrCnt;
	if(++StrCnt==64) StrCnt = 0;
	strncpy (StrFunction[StrCnt], &S[length1], length2);
	return StrFunction[StrCnt];
}
/////////////////////////////////////////////////////////////////////
__declspec(dllexport) char *GetUpTime(void)
{
    long int Mins = 0;
    long int Secs = 0;
    long int Hous = 0;
    long int Days = 0;
    static char UpTimeReturn[256];
    int Temp_Time = GetTickCount()/1000;
    while(Temp_Time >= 60)
    {
        if(Temp_Time >= 60)
        {
            Mins++;
            Temp_Time = Temp_Time-60;
        }
    }
    while(Mins >= 60)
    {
        if(Mins >= 60)
        {
            Hous++;
            Mins = Mins-60;
        }
    }
    while(Hous >= 24)
    {
        if(Hous >= 24)
        {
            Days++;
            Hous = Hous-24;
        }
    }
     Secs = Temp_Time;
     sprintf(UpTimeReturn,"%d Days, %d Hours, %d Minutes, %d Seconds",Days,Hous,Mins,Secs);
     return (UpTimeReturn);
}
//////////////////////////////////////////////////////////////////////
__declspec(dllexport) long int TotalMemory(void)
{
    static  SYSTEM_INFO  si;
    static  MEMORYSTATUS  ms;
    ms.dwLength=sizeof(&ms);
    GlobalMemoryStatus(&ms);
    GetSystemInfo(&si);
    return ms.dwTotalPhys;
}
//////////////////////////////////////////////////////////////////////
__declspec(dllexport) long int UsedMemory(void)
{
    static  SYSTEM_INFO  si;
    static  MEMORYSTATUS  ms;
    ms.dwLength=sizeof(&ms);
    GlobalMemoryStatus(&ms);
    GetSystemInfo(&si);
    return ms.dwTotalPhys - ms.dmAvailPhys;
}

...and so on for FreeMemory, NumberOfProcessors, ProcessorType, ProcessorLevel, ProcessorRevision, ProcessorModel and ProcessorStepping - all thin wrappers over GlobalMemoryStatus and GetSystemInfo in the same style.

And the console test driver that links against the import library:

#include <windows.h>
#include <stdio.h>
#include <stdlib.h>

extern char *GetTime(void);
extern char *GetLongDate(void);
extern char *GetShortDate(void);
extern char *GetMachineName(void);
extern char *GetLogonName(void);
extern char *GetOsVersion(void);
extern char *GetWorkingDirectory(void);
extern char *GetTempDirectory(void);
extern char *GetSysDirectory(void);
extern char *UCase (char *);
extern char *LCase(char *);
extern char *IntChar(double);
extern char *GetUpTime(void);
extern char *StringScan(char *, int , int);
extern int CharInt(char *);
extern long int TotalMemory(void);
extern long int UsedMemory(void);
extern long int FreeMemory(void);
extern int NumberOfProcessors(void);
extern int ProcessorType(void);
extern int ProcessorLevel(void);
extern int ProcessorRevision(void);
extern int ProcessorModel(void);
extern int ProcessorStepping(void);


int main()
{
    printf("GetTime %s\n",GetTime());
    printf("GetLongDate %s\n",GetLongDate());
    printf("GetShortDate %s\n",GetShortDate());
    printf("GetMachineName %s\n",GetMachineName());
    printf("GetLogonName %s\n",GetLogonName());
    printf("GetOsVersion %s\n",GetOsVersion());
    printf("GetWorkingDirectory %s\n",GetWorkingDirectory());
    printf("GetTempDirectory %s\n",GetTempDirectory());
    printf("GetSysDirectory %s\n",GetSysDirectory());
    printf("UCase %s\n",UCase("my string"));
    printf("LCase %s\n",LCase("MY OTHER STRING"));
    printf("IntChar %s\n",IntChar(123456));
    printf("CharInt %d\n",CharInt("123456"));
    printf("StringScan %s\n",StringScan("Hello Cruel World",6,5));
    printf("TotalMemory %d\n",TotalMemory());
    printf("UsedMemory %d\n",UsedMemory());
    printf("FreeMemory %d\n",FreeMemory());

   printf("NumberOfProcessors %d\n",NumberOfProcessors());
   printf("ProcessorType %d\n",ProcessorType());
   printf("ProcessorLevel %d\n",ProcessorLevel());
   printf("ProcessorRevision %d\n",ProcessorRevision());
   printf("ProcessorModel %d\n",ProcessorModel());
   printf("ProcessorStepping %d\n",ProcessorStepping());


    return 0;
}
An unhandled error has occurred. Reload 🗙