Valid HTML 4.01 Transitional Valid CSS Valid SVG 1.0

Me, myself & IT

Implementations of a CreateJunctionW() Function

Purpose
Background Information
Win32 Implementation
Native Implementation
Demonstration

Purpose

Present a Win32 and a native implementation of a CreateJunctionW() function to create directory junctions in the NTFS file system of Microsoft® Windows 2000 and later versions of Windows NT.

Background Information

Since Windows NT 4 the Win32 function MoveFileEx() allows to create hard links in the NTFS file system through the back then undocumented MOVEFILE_CREATE_HARDLINK flag.

Windows 2000 finally introduced the Win32 function CreateHardLink():

A hard link is the file-system representation of a file by which more than one path references a single file in the same volume. To create a hard link, use the CreateHardLink function.
Windows 2000 also introduced so-called reparse points in the NTFS file system which implement volume mount points and directory junctions alias soft links:
A junction (also called a soft link) differs from a hard link in that the storage objects it references are separate directories. A junction can also link directories located on different local volumes on the same computer. Otherwise, junctions operate identically to hard links. Junctions are implemented through reparse points.
Microsoft but failed (and still fails) to provide a corresponding Win32 function CreateJunction() to create them!

Note: Windows Vista introduced symbolic links, another type of reparse points, this time but with a corresponding Win32 function CreateSymbolicLink() to create them.

Win32 Implementation

Perform the following 2 simple steps to build an object library of a CreateJunctionW() function implemented with the Win32 API.
  1. Create the text file junction.c with the following content in an arbitrary, preferable empty directory:

    // Copyright © 2004-2025, Stefan Kanthak <‍stefan‍.‍kanthak‍@‍nexgo‍.‍de‍>
    
    #pragma comment(compiler)
    #pragma comment(lib, "kernel32")
    
    #pragma intrinsic(__movsw)
    
    #define STRICT
    #define UNICODE
    #define WIN32_LEAN_AND_MEAN
    
    #include <windows.h>
    #include <winioctl.h>
    
    #define FILE_SHARE_NONE	0UL
    
    #define IO_REPARSE_TAG_JUNCTION	IO_REPARSE_TAG_MOUNT_POINT
    
    typedef	struct	_REPARSE_DATA_BUFFER
    {
    	DWORD	ReparseTag;
    	WORD	ReparseDataLength;
    	WORD	Reserved;
    	struct
    	{
    		WORD	SubstituteNameOffset;
    		WORD	SubstituteNameLength;
    		WORD	PrintNameOffset;
    		WORD	PrintNameLength;
    		WCHAR	PathBuffer[sizeof("\\??\\…\0…")];
    	} JunctionReparseData;
    } REPARSE_DATA_BUFFER, *LPREPARSE_DATA_BUFFER;
    
    const	FILE_DISPOSITION_INFO	fdi = {TRUE};
    
    BOOL	WINAPI	CreateJunctionW(LPCWSTR szJunction, LPCWSTR szTarget)
    {
    	LPREPARSE_DATA_BUFFER	lpJunction;
    
    	BOOL	bJunction = FALSE;
    	HANDLE	hJunction;
    	DWORD	dwJunction;
    	DWORD	dwTarget;
    
    	if (szJunction == NULL || szJunction[0] == L'\0'
    	 || szTarget == NULL || szTarget[0] == L'\0'
    	 || (szTarget[0] == L'\\' || szTarget[0] == L'/')
    	 && (szTarget[1] == L'\\' || szTarget[1] == L'/'))
    		SetLastError(ERROR_INVALID_PARAMETER);
    	else
    	{	// CAVEAT: GetFullPathName() returns buffer size greater than
    		//          string length + 1 for path name with "." or ".."!
    
    		dwTarget = GetFullPathName(szTarget, 0UL, (LPWSTR) NULL, (LPWSTR *) NULL);
    
    		if (dwTarget != 0UL)
    		{
    			dwJunction = sizeof(*lpJunction)
    			           - sizeof(L'\0') * 4
    			           + sizeof(L'\0') * 2 * dwTarget;
    
    			lpJunction = LocalAlloc(NONZEROLPTR, dwJunction);
    
    			if (lpJunction != NULL)
    			{
    				dwTarget = GetFullPathName(szTarget,
    				                           dwTarget,
    				                           lpJunction->JunctionReparseData.PathBuffer + 4,
    				                           (LPWSTR *) NULL);
    				if (dwTarget != 0UL)
    				{
    					dwJunction = sizeof(*lpJunction)
    					           - sizeof(L'\0') * 2
    					           + sizeof(L'\0') * 2 * dwTarget;
    
    					if (dwJunction > MAXIMUM_REPARSE_DATA_BUFFER_SIZE)
    						SetLastError(ERROR_FILE_SYSTEM_LIMITATION);
    					else
    					{
    						lpJunction->ReparseTag = IO_REPARSE_TAG_JUNCTION;
    						lpJunction->ReparseDataLength = sizeof(lpJunction->JunctionReparseData)
    						                              - sizeof(L'\0') * 2
    						                              + sizeof(L'\0') * 2 * dwTarget;
    						lpJunction->Reserved = 0;
    						lpJunction->JunctionReparseData.SubstituteNameOffset = 0;
    						lpJunction->JunctionReparseData.SubstituteNameLength = sizeof(L'\0') * dwTarget
    						                                                     + sizeof(L'\0') * 4;
    						lpJunction->JunctionReparseData.PrintNameOffset = sizeof(L'\0') * dwTarget
    						                                                + sizeof(L'\0') * 5;
    						lpJunction->JunctionReparseData.PrintNameLength = sizeof(L'\0') * dwTarget;
    						lpJunction->JunctionReparseData.PathBuffer[0] = L'\\';
    						lpJunction->JunctionReparseData.PathBuffer[1] = L'?';
    						lpJunction->JunctionReparseData.PathBuffer[2] = L'?';
    						lpJunction->JunctionReparseData.PathBuffer[3] = L'\\';
    
    						__movsw(lpJunction->JunctionReparseData.PathBuffer + 4 + dwTarget + 1,
    						        lpJunction->JunctionReparseData.PathBuffer + 4, dwTarget + 1);
    
    						hJunction = CreateFile(szJunction,
    						                       DELETE | FILE_WRITE_ATTRIBUTES | FILE_WRITE_EA,
    						                       FILE_SHARE_NONE,
    						                       (LPSECURITY_ATTRIBUTES) NULL,
    						                       CREATE_NEW,
    						                       FILE_ATTRIBUTE_DIRECTORY | FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_POSIX_SEMANTICS,
    						                       (HANDLE) NULL);
    
    						if (hJunction != INVALID_HANDLE_VALUE)
    						{
    							bJunction = DeviceIoControl(hJunction,
    							                            FSCTL_SET_REPARSE_POINT,
    							                            lpJunction,
    							                            dwJunction,
    							                            NULL,
    							                            0UL,
    							                            &dwJunction,
    							                            (LPOVERLAPPED) NULL);
    							if (bJunction == FALSE)
    								SetFileInformationByHandle(hJunction,
    								                           FileDispositionInfo,
    								                           &fdi,
    								                           sizeof(fdi));
    							CloseHandle(hJunction);
    						}
    					}
    				}
    
    				LocalFree(lpJunction);
    			}
    		}
    	}
    
    	return bJunction;
    }
    Note: \??\ refers to the \DosDevices\ subdirectory of the NT Object Manager for the logon session of the current user.
  2. Compile the source file junction.c created in step 1. and put the generated object file junction.obj into the new object library junction.lib:

    CL.EXE /c /Gy /Oxy /W4 /Zl junction.c
    LINK.EXE /LIB /NODEFAULTLIB junction.obj
    Note: the command lines can be copied and pasted as block into a Command Processor window.
    Microsoft (R) 32-bit C/C++ Optimizing Compiler Version 16.00.40219.01 for 80x86
    Copyright (C) Microsoft Corporation.  All rights reserved.
    
    junction.c
    junction.c(83) : warning C4244: '=' : conversion from 'unsigned long' to 'WORD', possible loss of data
    junction.c(87) : warning C4244: '=' : conversion from 'unsigned long' to 'WORD', possible loss of data
    junction.c(89) : warning C4244: '=' : conversion from 'unsigned long' to 'WORD', possible loss of data
    junction.c(90) : warning C4244: '=' : conversion from 'unsigned long' to 'WORD', possible loss of data
    junction.c(120) : warning C4090: 'function' : different 'const' qualifiers
    
    Microsoft (R) Library Manager Version 10.00.40219.386
    Copyright (C) Microsoft Corporation.  All rights reserved.

Native Implementation

Perform the following 3 simple steps to build a combined import and object library of the CreateJunctionW() function, implemented with Windows NT’s native API exported from NTDLL.dll.
  1. Create the text file junction.c with the following content in an arbitrary, preferable empty directory:

    // Copyright © 2004-2025, Stefan Kanthak <‍stefan‍.‍kanthak‍@‍nexgo‍.‍de‍>
    
    #ifndef _DLL
    #pragma comment(compiler)
    #pragma comment(lib, "junction")
    
    #pragma intrinsic(__movsw)
    
    #define STRICT
    #define UNICODE
    #define WIN32_LEAN_AND_MEAN
    
    #include <windows.h>
    #include <winioctl.h>
    
    #define FILE_SHARE_NONE			0UL
    #define FILE_CREATE			2UL
    #define FILE_DIRECTORY_FILE		1UL
    #define FILE_SYNCHRONOUS_IO_NONALERT	32UL
    
    #define IO_REPARSE_TAG_JUNCTION		IO_REPARSE_TAG_MOUNT_POINT
    
    #define OBJ_CASE_INSENSITIVE		64UL
    
    #define STATUS_SUCCESS			0L
    #define STATUS_FILE_SYSTEM_LIMITATION	0xC0000427L
    
    typedef	struct	_REPARSE_DATA_BUFFER
    {
    	DWORD	ReparseTag;
    	WORD	ReparseDataLength;
    	WORD	Reserved;
    	struct
    	{
    		WORD	SubstituteNameOffset;
    		WORD	SubstituteNameLength;
    		WORD	PrintNameOffset;
    		WORD	PrintNameLength;
    		WCHAR	PathBuffer[sizeof("\\??\\…\0…")];
    	} JunctionReparseData;
    } REPARSE_DATA_BUFFER;
    
    typedef	struct	_UNICODE_STRING
    {
    	WORD	Length;
    	WORD	MaximumLength;
    	LPWSTR	Buffer;
    } UNICODE_STRING;
    
    typedef	struct	_OBJECT_ATTRIBUTES
    {
    	DWORD		Length;
    	HANDLE		RootDirectory;
    	UNICODE_STRING	*ObjectName;
    	DWORD		Attributes;
    	LPVOID		SecurityDescriptor;
    	LPVOID		SecurityQualityOfService;
    } OBJECT_ATTRIBUTES;
    
    typedef	struct	_IO_STATUS_BLOCK
    {
    	union
    	{
    		LONG	Status;
    		LPVOID	Pointer;
    	};
    	DWORD_PTR	Information;
    } IO_STATUS_BLOCK;
    
    typedef	struct	_FILE_DISPOSITION_INFORMATION
    {
    	BOOLEAN DeleteFile;
    } FILE_DISPOSITION_INFORMATION;
    
    typedef	struct	_RTLP_CURDIR_REF
    {
    	LONG	RefCount;
    	HANDLE	Handle;
    } RTLP_CURDIR_REF;
    
    typedef	struct	_RTL_RELATIVE_NAME_U
    {
    	UNICODE_STRING	RelativeName;
    	HANDLE		ContainingDirectory;
    	RTLP_CURDIR_REF	*CurDirRef;
    } RTL_RELATIVE_NAME_U;
    
    typedef	struct	_RTL_USER_PROCESS_PARAMETERS
    {
    	BYTE		Reserved1[16];
    	LPVOID		Reserved2[10];
    	UNICODE_STRING	ImagePathName;
    	UNICODE_STRING	CommandLine;
    } RTL_USER_PROCESS_PARAMETERS;
    
    typedef	struct	_PEB_LDR_DATA
    {
    	BYTE		Reserved1[8];
    	LPVOID		Reserved2[3];
    	LIST_ENTRY	InMemoryOrderModuleList;
    } PEB_LDR_DATA;
    
    typedef	VOID	(NTAPI	PS_POST_PROCESS_INIT_ROUTINE) (VOID);
    
    typedef	struct	_PEB
    {
    	BYTE				Reserved1[2];
    	BOOLEAN				BeingDebugged;
    	BYTE				Reserved2[1];
    	LPVOID				Reserved3[2];
    	PEB_LDR_DATA			*Ldr;
    	RTL_USER_PROCESS_PARAMETERS	*ProcessParameters;
    #if 0
    	LPVOID				Reserved4[3];
    #else
    	LPVOID				SubSystemData;
    	HANDLE				ProcessHeap;
    	RTL_CRITICAL_SECTION		*FastPebLock;
    #endif
    	LPVOID				AtlThunkSListPtr;
    	LPVOID				Reserved5;
    	DWORD				Reserved6;
    	LPVOID				Reserved7;
    	DWORD				Reserved8;
    	DWORD				AtlThunkSListPtr32;
    	LPVOID				Reserved9[45];
    	BYTE				Reserved10[96];
    	PS_POST_PROCESS_INIT_ROUTINE	*PostProcessInitRoutine;
    	BYTE				Reserved11[128];
    	LPVOID				Reserved12[1];
    	DWORD				SessionId;
    } PEB;
    
    typedef	struct	_TEB
    {
    	LPVOID		Reserved1[12];
    	PEB		*ProcessEnvironmentBlock;
    	LPVOID		Reserved2[399];
    	BYTE		Reserved3[1952];
    	LPVOID		TlsSlots[64];
    	LIST_ENTRY	TlsLinks;
    	LPVOID		Reserved5[26];
    	LPVOID		ReservedForOle;
    	LPVOID		Reserved6[4];
    	LPVOID		*TlsExpansionSlots;
    } TEB;
    
    typedef	VOID	(NTAPI	IO_APC_ROUTINE) (VOID            *ApcContext,
    			                 IO_STATUS_BLOCK *IoStatusBlock,
    			                 DWORD           Reserved);
    typedef	LONG	NTSTATUS;
    
    typedef	enum	_FILE_INFORMATION_CLASS
    {
    	FileDispositionInformation = 13
    } FILE_INFORMATION_CLASS;
    
    __declspec(dllimport)
    LONG	NTAPI	NtClose(HANDLE Handle);
    
    __declspec(dllimport)
    LONG	NTAPI	NtCreateFile(HANDLE            *FileHandle,
    		             ACCESS_MASK       DesiredAccess,
    		             OBJECT_ATTRIBUTES *ObjectAttributes,
    		             IO_STATUS_BLOCK   *IoStatusBlock,
    		             LARGE_INTEGER     *AllocationSize,
    		             DWORD             FileAttributes,
    		             DWORD             ShareAccess,
    		             DWORD             CreateDisposition,
    		             DWORD             CreateOptions,
    		             VOID              *EaBuffer,
    		             DWORD             EaLength);
    __declspec(dllimport)
    LONG	NTAPI	NtFsControlFile(HANDLE          FileHandle,
    		                HANDLE          Event,
    		                IO_APC_ROUTINE  *ApcRoutine,
    		                VOID            *ApcContext,
    		                IO_STATUS_BLOCK *IoStatusBlock,
    		                DWORD           FsControlCode,
    		                VOID            *InputBuffer,
    		                DWORD           InputBufferLength,
    		                VOID            *OutputBuffer,
    		                DWORD           OutputBufferLength);
    __declspec(dllimport)
    LONG	NTAPI	NtSetInformationFile(HANDLE                 FileHandle,
    		                     IO_STATUS_BLOCK        *IoStatusBlock,
    		                     VOID                   *FileInformation,
    		                     DWORD                  FileInformationLength,
    		                     FILE_INFORMATION_CLASS FileInformationClass);
    __declspec(dllimport)
    LONG	NTAPI	NtWaitForSingleObject(HANDLE        Handle,
    		                      BOOLEAN       Alertable,
    		                      LARGE_INTEGER *Timeout);
    __declspec(dllimport)
    LPVOID	NTAPI	RtlAllocateHeap(LPCVOID HeapHandle,
    		                DWORD   Flags,
    		                SIZE_T  Size);
    __declspec(dllimport)
    LONG	NTAPI	RtlDosPathNameToNtPathName_U_WithStatus(LPCWSTR             DosName,
    		                                        UNICODE_STRING      *NtName,
    		                                        LPCWSTR             *PartName,
    		                                        RTL_RELATIVE_NAME_U *RelativeName);
    __declspec(dllimport)
    BOOL	NTAPI	RtlFreeHeap(LPCVOID HeapHandle,
    		            DWORD   Flags,
    		            LPCVOID HeapBase);
    __declspec(dllimport)
    VOID	NTAPI	RtlFreeUnicodeString(UNICODE_STRING *UnicodeString);
    
    __declspec(dllimport)
    VOID	NTAPI	RtlSetLastWin32ErrorAndNtStatusFromNtStatus(NTSTATUS Status);
    
    const	FILE_DISPOSITION_INFORMATION	fdi = {TRUE};
    
    BOOL	WINAPI	CreateJunctionW(LPCWSTR szJunction, LPCWSTR szTarget)
    {
    	LPCVOID	lpHeap = NtCurrentTeb()->ProcessEnvironmentBlock->ProcessHeap;
    	LONG	ntStatus = STATUS_INVALID_PARAMETER;
    	BOOL	bJunction = FALSE;
    	HANDLE	hJunction;
    	DWORD	dwJunction;
    
    	REPARSE_DATA_BUFFER	*lpJunction;
    	IO_STATUS_BLOCK		ioJunction;
    	UNICODE_STRING		usJunction, usTarget;
    	OBJECT_ATTRIBUTES	oaJunction = {sizeof(oaJunction),
    				              (HANDLE) NULL,
    				              (UNICODE_STRING *) NULL,
    				              OBJ_CASE_INSENSITIVE,
    				              NULL,
    				              NULL};
    
    	if (szJunction != NULL && *szJunction != L'\0'
    	 && szTarget != NULL && *szTarget != L'\0')
    	{
    		ntStatus = RtlDosPathNameToNtPathName_U_WithStatus(szTarget,
    		                                                   &usTarget,
    		                                                   (LPCWSTR *) NULL,
    		                                                   NULL);
    		if (ntStatus == STATUS_SUCCESS)
    		{
    			dwJunction = sizeof(*lpJunction)
    			           - sizeof(L"\\??\\") * 2
    			           + usTarget.Length * 2;
    
    			if (dwJunction > MAXIMUM_REPARSE_DATA_BUFFER_SIZE)
    				ntStatus = STATUS_FILE_SYSTEM_LIMITATION;
    			else
    			{
    				lpJunction = RtlAllocateHeap(lpHeap, 0UL, dwJunction);
    
    				if (lpJunction == NULL)
    					ntStatus = STATUS_NO_MEMORY;
    				else
    				{
    					lpJunction->ReparseTag = IO_REPARSE_TAG_JUNCTION;
    					lpJunction->ReparseDataLength = sizeof(lpJunction->JunctionReparseData)
    					                              - sizeof(L"\\??\\") * 2
    					                              + usTarget.Length * 2;
    					lpJunction->Reserved = 0;
    					lpJunction->JunctionReparseData.SubstituteNameOffset = 0;
    					lpJunction->JunctionReparseData.SubstituteNameLength = usTarget.Length;
    					lpJunction->JunctionReparseData.PrintNameOffset = usTarget.Length
    					                                                + sizeof(L"");
    					lpJunction->JunctionReparseData.PrintNameLength = usTarget.Length
    					                                                - sizeof(L"\\??\\") + sizeof(L"");
    
    					__movsw(lpJunction->JunctionReparseData.PathBuffer,
    					        usTarget.Buffer,
    					        usTarget.Length / sizeof(L'\0') + 1);
    					__movsw(lpJunction->JunctionReparseData.PathBuffer + usTarget.Length / sizeof(L'\0') + 1,
    					        usTarget.Buffer + 4,
    					        usTarget.Length / sizeof(L'\0') - 3);
    
    					ntStatus = RtlDosPathNameToNtPathName_U_WithStatus(szJunction,
    					                                                   &usJunction,
    					                                                   (LPCWSTR *) NULL,
    					                                                   NULL);
    					if (ntStatus == STATUS_SUCCESS)
    					{
    						oaJunction.ObjectName = &usJunction;
    
    						ntStatus = NtCreateFile(&hJunction,
    						                        DELETE | FILE_WRITE_ATTRIBUTES | FILE_WRITE_EA | SYNCHRONIZE,
    						                        &oaJunction,
    						                        &ioJunction,
    						                        (LARGE_INTEGER *) NULL,
    						                        FILE_ATTRIBUTE_DIRECTORY,
    						                        FILE_SHARE_NONE,
    						                        FILE_CREATE,
    						                        FILE_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT,
    						                        NULL,
    						                        0UL);
    
    						if (ntStatus == STATUS_SUCCESS)
    						{
    							ntStatus = NtFsControlFile(hJunction,
    							                           (HANDLE) NULL,
    							                           (IO_APC_ROUTINE *) NULL,
    							                           NULL,
    							                           &ioJunction,
    							                           FSCTL_SET_REPARSE_POINT,
    							                           lpJunction,
    							                           dwJunction,
    							                           NULL,
    							                           0UL);
    
    							if (ntStatus == STATUS_SUCCESS)
    							{
    								ntStatus = NtWaitForSingleObject(hJunction,
    							                                         FALSE,
    							                                         (LARGE_INTEGER *) NULL);
    								if (ntStatus == STATUS_SUCCESS)
    									ntStatus = ioJunction.Status;
    							}
    
    							if (ntStatus == STATUS_SUCCESS)
    								bJunction = TRUE;
    							else
    								NtSetInformationFile(hJunction,
    							                             &ioJunction,
    								                     &fdi,
    								                     sizeof(fdi),
    								                     FileDispositionInformation);
    							NtClose(hJunction);
    						}
    
    						RtlFreeUnicodeString(&usJunction);
    					}
    
    					RtlFreeHeap(lpHeap, 0UL, lpJunction);
    				}
    			}
    
    			RtlFreeUnicodeString(&usTarget);
    		}
    	}
    
    	if (!bJunction)
    		RtlSetLastWin32ErrorAndNtStatusFromNtStatus(ntStatus);
    
    	return bJunction;
    }
    #else // _DLL
    __declspec(dllexport)
    long	NtClose(void *_1)
    { return 0; }
    
    __declspec(dllexport)
    long	NtCreateFile(void *_1, long _2, void *_3, void *_4, void *_5, long _6, long _7, long _8, long _9, void *_10, long _11)
    { return 0; }
    
    __declspec(dllexport)
    long	NtFsControlFile(void *_1, void *_2, void *_3, void *_4, void *_5, long _6, void *_7, long _8, void *_9, long _10)
    { return 0; }
    
    __declspec(dllexport)
    long	NtSetInformationFile(void *_1, void *_2, void *_3, long _4, long _5)
    { return 0; }
    
    __declspec(dllexport)
    long	NtWaitForSingleObject(void *_1, long _2, void *_3)
    { return 0; }
    
    __declspec(dllexport)
    void	*RtlAllocateHeap(void *_1, long _2, void *_3)
    { return 0; }
    
    __declspec(dllexport)
    long	RtlFreeHeap(void *_1, long _2, void *_3)
    { return 0; }
    
    __declspec(dllexport)
    void	RtlFreeUnicodeString(void *_1)
    {}
    
    __declspec(dllexport)
    long	RtlDosPathNameToNtPathName_U_WithStatus(void *_1, void *_2, void *_3, void *_4)
    { return 0; }
    
    __declspec(dllexport)
    void	RtlSetLastWin32ErrorAndNtStatusFromNtStatus(long _1)
    {}
    #endif // _DLL
  2. Compile the source file junction.c created in step 1. a first time and build the import library junction.lib from the generated object file junction.obj:

    CL.EXE /c /Gz /MD /W4 /wd4100 /X /Zl junction.c
    LINK.EXE /LIB /DEF /EXPORT:NtClose /EXPORT:NtCreateFile /EXPORT:NtFsControlFile /EXPORT:NtSetInformationFile /EXPORT:NtWaitForSingleObject /EXPORT:RtlAllocateHeap /EXPORT:RtlFreeHeap /EXPORT:RtlFreeUnicodeString /EXPORT:RtlDosPathNameToNtPathName_U_WithStatus /EXPORT:RtlSetLastWin32ErrorAndNtStatusFromNtStatus /NAME:NTDLL /NODEFAULTLIB junction.obj

    Note: the command lines can be copied and pasted as block into a Command Processor window.

    Microsoft (R) 32-bit C/C++ Optimizing Compiler Version 16.00.40219.01 for 80x86
    Copyright (C) Microsoft Corporation.  All rights reserved.
    
    junction.c
    
    Microsoft (R) Library Manager Version 10.00.40219.386
    Copyright (C) Microsoft Corporation.  All rights reserved.
    
       Creating library junction.lib and object junction.exp
  3. Compile the source file junction.c created in step 1. a second time and put the generated object file junction.obj into the import (as well as object) library junction.lib built in step 2.:

    CL.EXE /c /Gy /Oxy /W4 /Zl junction.c
    LINK.EXE /LIB /NODEFAULTLIB junction.lib junction.obj
    Microsoft (R) 32-bit C/C++ Optimizing Compiler Version 16.00.40219.01 for 80x86
    Copyright (C) Microsoft Corporation.  All rights reserved.
    
    junction.c
    junction.c(66) : warning C4201: nonstandard extension used : nameless struct/union
    junction.c(322) : warning C4090: 'function' : different 'const' qualifiers
    
    Microsoft (R) Library Manager Version 10.00.40219.386
    Copyright (C) Microsoft Corporation.  All rights reserved.

Demonstration

Perform the following 4 simple steps to verify the proper function of the CreateJunctionW() routines.
  1. Overwrite the text file junction.c with the following content:

    // Copyright © 2004-2025, Stefan Kanthak <‍stefan‍.‍kanthak‍@‍nexgo‍.‍de‍>
    
    #define STRICT
    #define UNICODE
    #define WIN32_LEAN_AND_MEAN
    
    #include <windows.h>
    
    BOOL	WINAPI	CreateJunctionW(LPCWSTR szJunction, LPCWSTR szTarget);
    
    __declspec(noreturn)
    VOID	CDECL	wmainCRTStartup(VOID)
    {
    	ExitProcess(CreateJunctionW(L"Junction", L"..") ? ERROR_SUCCESS : GetLastError());
    }
  2. Compile the source file junction.c overwritten in step 1. and link the generated object file junction.obj with one of the (import and) object libraries junction.lib built before:

    SET CL=/GF /W4 /Zl
    SET LINK=/ENTRY:wmainCRTStartup /SUBSYSTEM:CONSOLE
    CL.EXE junction.c junction.lib kernel32.lib
    Microsoft (R) 32-bit C/C++ Optimizing Compiler Version 16.00.40219.01 for 80x86
    Copyright (C) Microsoft Corporation.  All rights reserved.
    
    junction.c
    
    Microsoft (R) Incremental Linker Version 10.00.40219.386
    Copyright (C) Microsoft Corporation.  All rights reserved.
    
    /ENTRY:wmainCRTStartup /SUBSYSTEM:CONSOLE
    /out:junction.exe
    junction.obj
    junction.lib
    kernel32.lib
  3. Execute the console application junction.exe built in step 2. and evaluate its exit code:

    .\junction.exe
    CERTUTIL.EXE /ERROR %ERRORLEVEL%
    0x0 (WIN32: 0 ERROR_SUCCESS) -- 0 (0)
    Error message text: The operation completed successfully.
    CertUtil: -error command completed successfully.
  4. List the junction Junction created in step 3. and remove it afterwards:

    DIR junction.*
    RMDIR Junction
     Volume in drive C has no label.
     Volume Serial Number is 1957-0427
    
     Directory of C:\Users\Stefan\Desktop
    
    04/27/2011  08:15 PM <JUNCTION>        Junction [C:\Users\Stefan]
    04/27/2011  08:15 PM               375 junction.c
    04/27/2011  08:15 PM             3,072 junction.exe
    04/27/2011  08:15 PM             1,937 junction.exp
    04/27/2011  08:15 PM             6,192 junction.lib
    04/27/2011  08:15 PM               983 junction.obj
                   5 File(s)         12,559 bytes
                   1 Dir(s)    9,876,543,210 bytes free

Contact and Feedback

If you miss anything here, have additions, comments, corrections, criticism or questions, want to give feedback, hints or tipps, report broken links, bugs, deficiencies, errors, inaccuracies, misrepresentations, omissions, shortcomings, vulnerabilities or weaknesses, …: don’t hesitate to contact me and feel free to ask, comment, criticise, flame, notify or report!

Use the X.509 certificate to send S/MIME encrypted mail.

Note: email in weird format and without a proper sender name is likely to be discarded!

I dislike HTML (and even weirder formats too) in email, I prefer to receive plain text.
I also expect to see your full (real) name as sender, not your nickname.
I abhor top posts and expect inline quotes in replies.

Terms and Conditions

By using this site, you signify your agreement to these terms and conditions. If you do not agree to these terms and conditions, do not use this site!

Data Protection Declaration

This web page records no (personal) data and stores no cookies in the web browser.

The web service is operated and provided by

Telekom Deutschland GmbH
Business Center
D-64306 Darmstadt
Germany
<‍hosting‍@‍telekom‍.‍de‍>
+49 800 5252033

The web service provider stores a session cookie in the web browser and records every visit of this web site with the following data in an access log on their server(s):


Copyright © 1995–2025 • Stefan Kanthak • <‍stefan‍.‍kanthak‍@‍nexgo‍.‍de‍>