Page 1 of 1

Creating a hard link

Posted: Sun Sep 09, 2018 4:02 pm
by Bitblazer
The hard link requirements by microsoft for windows are : NTFS file system V5 or above, administrator rights to create them, with win32 API : CreateHardLinkW or via commandline "{systemfolder}\cmd.exe /q /s mklink /h" (its a standard cmd.exe internal command with recent windows versions). I tried both methods and try to get a clean simple win32 api method running, but no matter which kind of string passing or pototype for import i use, i always get the result of "failed" with a lasterror() of 2 (see error codes). I tried pointers and direct argument passing as p-utf8, p-unicode and string on PB 5.62 x86. The NTFS versions are the latest official, so it should be above Ver. 5. My OS is Windows7 x64, i wonder if i have to use the 64bit PB 5.62 version :(

Any hint why it does'nt work?

The snippet was comiled in a project with admin rights and i get the UAC confirmation request so that should be fine.

Code: Select all

Import "Kernel32.lib"
  CreateHardLinkW(lpLinkFileName.p-unicode, lpExistingFileName.p-unicode, lpSecurityAttributes.i = 0)
  GetLastError.i()
EndImport

EnableExplicit

Define LinkResult.i, ErrorCode.i = 0

Debug "link test"

LinkResult = CreateHardLinkW("e:\linktest.exe", "e:\streamwriter.exe")
If (LinkResult = 0)
  Debug "Ein fehler ist aufgetreten"
  ErrorCode = GetLastError()
EndIf
Debug "Ergebnis war " + Str(LinkResult) + " ErrorCode = " + Str(ErrorCode)
ignore the german text, it should be irrelevant to the problem :)

Re: Creating a hard link

Posted: Sun Sep 09, 2018 5:25 pm
by RSBasic
My code works:

Code: Select all

EnableExplicit

Define lpFileName$
Define lpExistingFileName$

If OpenLibrary(0, "Kernel32.dll")
  Prototype CreateHardLink(lpFileName, lpExistingFileName, lpSecurityAttributes)
  Define CreateHardLink.CreateHardLink = GetFunction(0, "CreateHardLinkW")
  CloseLibrary(0)
EndIf

lpFileName$ = "D:\Hardlink.png"
lpExistingFileName$ = "D:\Originalfile.png"

If CreateHardLink(@lpFileName$, @lpExistingFileName$, 0)
  MessageRequester("", "Hard link was created.", 0)
Else
  MessageRequester("", "Hard link could not be created.", 0)
EndIf
Tested with x86 (Unicode) and x64 (Unicode).

Re: Creating a hard link

Posted: Sun Sep 09, 2018 6:04 pm
by fryquez
Works fine here, even without admin rights. What error code do you get?

Re: Creating a hard link

Posted: Sun Sep 09, 2018 6:15 pm
by skywalk
Both codes work. v562 x64 on Windows 10 Pro.

Re: Creating a hard link

Posted: Mon Sep 10, 2018 9:05 am
by Bitblazer
Thanks for the help. I am still not sure why my attempt with the .lib didnt work, but the method with .dll works even without admin mode in win7 x64. That's a definitive plus and to make this reply useful for others, here is a cleaned up and re-useable snippet for general use. Thanks again :)

Code snippet to create a hard link to a file

Code: Select all

EnableExplicit

Define LibraryID.i
Prototype CreateHardLink_Type(lpFileName, lpExistingFileName, lpSecurityAttributes)
Global CreateHardLink.CreateHardLink_Type = GetFunction(0, "CreateHardLinkW")

Procedure.i CreateLink(lpFileName$, lpExistingFileName$)
  Define Result.i
  
  Result = CreateHardLink(@lpFileName$, @lpExistingFileName$, 0)
  
  ProcedureReturn Result
EndProcedure

LibraryID = OpenLibrary(#PB_Any, "Kernel32.dll")

If (LibraryID = 0)
  MessageRequester("Fatal error!", "Could not open kernel32.dll" + Chr(10) + "this should not be possible.", #PB_MessageRequester_Error | #PB_MessageRequester_Ok)
  End 999
EndIf

CreateHardLink = GetFunction(LibraryID, "CreateHardLinkW")
CloseLibrary(LibraryID)
LibraryID = 0

CreateLink("e:\zz_linktest.jpg", "e:\testpicture.jpg")
MessageRequester("Success!", "Link 'zz_linktest.jpg' created", #PB_MessageRequester_Ok | #PB_MessageRequester_Info)