Jump to content
Sign in to follow this  
Ascend4nt

File + Process Imports and Exports - DLL, EXE etc

Recommended Posts

File + Process Imports/Exports Information UDFs

Posted ImagePosted Image

Forwarder String Support, C++ Name Undecorating Added!!

(Extreme case of string forwarding from wsock32.dll example in this post)

This UDF gets Function Imports and Exports for any Windows PE file (.DLL, .EXE), both 32-bit and 64-bit (unlike most programs out there), and from either a 32-bit or 64-bit Process.

I created this due to my frustration with other programs either working only *some* of the time, or having a common inability to read PE32+ (x64) file format tables properly.

There's just two functions in the main UDF - _FileGetWinPEImports or _FileGetWinPEExports. The bundled TestImportExportsList program lets you explore files on your system.

*Newly included are: _ProcessGetWinPEImports, _ProcessGetWinPEExports and TestProcessImportExportsList program (requires my Process Functions UDF).

NOTE: *Compressed* executable files will only give the Import information for the 'decompressor'. The only way to get the compressed executable's Import information is to decompress the executable.

Anyway, enjoy my hard work. Either read on for more information about some of the features, or see below for the License agreement and Download link.

Information on 'Virtual Offset of Thunk':

These address offsets you see are offsets from the base of the .DLL or .EXE file (uncompressed only!), where the actual function location of an 'Import' gets placed. All calls to these functions load addresses from these Thunk locations in order to correctly place a call to the right DLL function. (This is totally different than the old Import fixup location lists of earlier pre-NT systems). Technically, you could overwrite these Thunks with addresses to your own functions, but this is a dangerous thing to do. Its a neat tool to have though.

Forwarder functions? An explanation:

The whole 'DLLNAME.Functionname' string might be confusing to you, but here's an explanation of why an address can not and should not be returned. To better understand all this, grab a copy of DLL Export Viewer, (which doesn't report Relative/Function addresses correctly for Forwarded functions) and then follow along: *update: as of v1.50, DLL Export Viewer now reports forwarder string info (I was the one that reported the bug heh)

Okay, open up DLL Export Viewer and look at (for this example) KERNEL32.DLL - lets pick 'HeapFree', a known Forwarded function. DLL Export Viewer reports the following (on XP SP3):Relative Address: 0x0000910c, 'Loaded' address: 0x7c80910c. *Neither* is the case, though - 0x0000910c is in fact just the virtual address of the forwarder string!

Now, with my Exports function, you'll find that 'HeapFree' is reported (correctly) as a Forwarder string. What you'll see then is 'NTDLL.RtlFreeHeap'. What does that mean? It means that:

  • HeapFree is not a part of KERNEL32.DLL (and hasn't been for a while),
  • When that function is called or the address retrieved via 'GetProcAddress', the function 'RtlFreeHeap' in NTDLL.DLL is the function that's actually called (or returned as an address). Hopefully the 'DLLNAME.FunctionName' structure of a Forwarder string is starting to make sense now?
  • The address you get when you do 'GetProcAddress' does *not* correspond to what you see in DLL Export Viewer - in fact, 'HeapFree's reported address lies entirely OUTSIDE of kernel32.dll's memory space - pointing instead inside of NTDLL.DLL, at (guess what?): RtlFreeHeap.
So, on XP SP3, looking up 'HeapFree' with GetProcAddress, you get: 0x7C90FF2D. Doesn't match what was reported with DLL Export Viewer AT ALL. However - go back, and now look at NTDLL.DLL with DLL Export Viewer, and at function 'RtlFreeHeap' (following the logic of the Forwarder Function string). What is reported for RtlFreeHeap? Relative Address: 0x0000ff2d, 'Loaded' address: 0x7c90ff2d. See now how it lines up with what was reported via GetProcAddress for 'HeapFree' in KERNEL32.DLL?

So, there you have it in a nutshell - Forwarder functions are functions 'rerouted' to another DLL. The DLL's that are being rerouted to are either:

  • A.) Pre-loaded by the system (Important DLL's like NTDLL.DLL, KERNEL32.DLL, USER32.DLL, GDI32.DLL, etc - are all permanently loaded)
  • B.) Loaded upon a program's execution if the function is in its 'Imports' list, or
  • C.) Loaded upon a call to GetProcAddress. To see how this works clearly, list the modules that are loaded (my Process Functions UDF GUI can do this for you), then call GetProcAddress for 'GetServiceW' from WSOCK32.DLL, and then re-list the modules again. You'll see a new module loaded up - MSWSOCK.DLL (the location of the forwarder function). Wa-la, forwarder is set up.
Ascend4nt's AutoIT Code License agreement:

While I provide this source code freely, if you do use the code in your projects, all I ask is that:

  • If you provide source, keep the header as I have put it, OR, if you expand it, then at least acknowledge me as the original author, and any other authors I credit
  • If the program is released, acknowledge me in your credits (it doesn't have to state which functions came from me, though again if the source is provided - see #1)
  • The source on it's own (as opposed to part of a project) can not be posted unless a link to the page(s) where the code were retrieved from is provided and a message stating that the latest updates will be available on the page(s) linked to.
  • Pieces of the code can however be discussed on the threads where Ascend4nt has posted the code without worrying about further linking.

Download the ZIPs from my Site

UPDATES:

7-21-2010:

Added:

  • C++ Function Name Undecorating/Unmangling option. For an example of what this causes function name results to be, check out something like 'msvcrt.dll'. It will report alot more than just a function name! If you choose to do the Undecorating yourself, just call the included function _WinAPI_UndecorateName().

    Example: "??3@YAXPAX@Z" becomes "void __cdecl operator delete(void *)" unmanged/undecorated

  • New _ProcessGetWinPEImportExports module (with Test program) as a separate download - requires use of my Process Functions UDF. The biggest benefits, besides looking into loaded DLL's that might not be on the disk? Addresses reported are real, and Imported function addresses are reported (as pulled from Thunk locations).
7-12-2010:

Fixed:

  • Oops, Big-time logic errors in mapping Export function names to addresses and using ordinals to look them up from pointer tables. Now everything points to where it should!
  • Ordinal #'s are now correctly calculated with the 'Base' # part of the EXPORT DIRECTORY TABLE.
Added:
  • 'Forwarder' string lookup & reporting! Not even DLL Export Viewer does this! Basically, certain function 'pointers' aren't really code offsets, but offsets to Forwarder strings. My function looks those strings up and puts them in the list instead of a phoney address.
7-11-2010:

Fixed:

  • Executables linked with Borland's TLINK32.exe do not set the 'ImportLookupTableRVA' element correctly. This was easy to work around, as the 'Thunks' list also contains pointers to the same information (until an executable/DLL is loaded by the O/S, at least)
Added:
  • Imports: Extra column: Virtual Offset of Thunk ( [3] ). When an .EXE or .DLL is loaded, this is the Offset from the base of the .EXE or .DLL which will hold the actual function address. This could be used for redirection of calls (dangerous though!).

    ...

    An important note on this: Compressed executables are a completely different beast, and in fact the whole Import section is for the Decompressor itself, which disappears once the executable is loaded! The only way to get the actual Imports for Compressed Executables is to Decompress them first.

Edited by Ascend4nt

Share this post


Link to post
Share on other sites

Thanks. I've been using DLL Export Viewer actually - But it doesn't report on Imports, and I'd rather not have to rely on using another program just for Exports.


Share this post


Link to post
Share on other sites

This is a very useful UDF.


Determined -- Devoted -- Delivered Make your mind up -- to seriously apply yourself -- accomplishing the desired results. **** A soft answer turneth away wrath: but grievous words stir up anger. Proverbs 15:1 KJB ****

Share this post


Link to post
Share on other sites

Thanks everyone for the compliments.

I've updated the UDF after reading about Borland's TLINK32 issue. All files should report the right Import information now, though I still have yet to figure out the 'forwarding' thing with certain Exports (that return an Offset of 0).

UPDATES:

7-11-2010:

Fixed:

  • Executables linked with Borland's TLINK32.exe do not set the 'ImportLookupTableRVA' element correctly. This was easy to work around, as the 'Thunks' list also contains pointers to the same information (until an executable/DLL is loaded by the O/S, at least)
Added:

  • Imports: Extra column: Virtual Offset of Thunk ( [3] ). When an .EXE or .DLL is loaded, this is the Offset from the base of the .EXE or .DLL which will hold the actual function address. This could be used for redirection of calls (dangerous though!).

    ...

    An important note on this: Compressed executables are a completely different beast, and in fact the whole Import section is for the Decompressor itself, which disappears once the executable is loaded! The only way to get the actual Imports for Compressed Executables is to Decompress them first.

Edited by Ascend4nt

Share this post


Link to post
Share on other sites

Sorry for the short time between updates, but I found a major issue with my code, and at the same time added something new - not even DLL Export Viewer has Forwarder-String information :blink:

Check out these examples of Forwarder strings inside DLL's (2nd example is an extreme case!)

Posted Image..Posted Image

Onto the updates:

UPDATES:

7-12-2010:

Fixed:

  • Oops, Big-time logic errors in mapping Export function names to addresses and using ordinals to look them up from pointer tables. Now everything points to where it should!
  • Ordinal #'s are now correctly calculated with the 'Base' # part of the EXPORT DIRECTORY TABLE.
Added:

  • 'Forwarder' string lookup & reporting! Not even DLL Export Viewer does this! Basically, certain function 'pointers' aren't really code offsets, but offsets to Forwarder strings. My function looks those strings up and puts them in the list instead of a phoney address.
Edited by Ascend4nt

Share this post


Link to post
Share on other sites

Updated!

7-21-2010:

Added:

  • C++ Function Name Undecorating/Unmangling option. For an example of what this causes function name results to be, check out something like 'msvcrt.dll'. It will report alot more than just a function name! If you choose to do the Undecorating yourself, just call the included function _WinAPI_UndecorateName().

    Example: "??3@YAXPAX@Z" becomes "void __cdecl operator delete(void *)" unmanged/undecorated

  • New _ProcessGetWinPEImportExports module (with Test program) as a separate download - requires use of my Process Functions UDF. The biggest benefits, besides looking into loaded DLL's that might not be on the disk? Addresses reported are real, and Imported function addresses are reported (as pulled from Thunk locations).

Share this post


Link to post
Share on other sites

Would it be possible to use parts of this library to validate that exports of a system DLL have not been dynamically remapped within the process where my script is running?

D.

Share this post


Link to post
Share on other sites

I'm not sure I understand. Do you mean that imports in your process (which are mapped to exports from DLL's) are being redirected to a different address than they should be? Theoretically it would be possible to check them, if the LoadLibrary/GetProcAddress API functions needed by DLLCall() were not themselves remapped to something that prevents them from working correctly.

Probably the best thing for you to do is to use UPX or some other compression utility which makes it more difficult for someone to get and remap the imports for your app.

I would also say that its possible to do using compiled machine code that goes through the PEB and module lists, but machine code still requires a DLLCall() to use from AutoIt..


Share this post


Link to post
Share on other sites

Not sure what aclayers is, but sounds easy enough. Use DLLCall to call 'GetProcAddress' for the different registry API calls, and compare those returned values to the process's loaded addresses for those API calls. If there's a difference, then they are being redirected. You can even go further to see where the module address is located by comparing it against the loaded modules' start and 'end' (start+size) addresses.


Share this post


Link to post
Share on other sites

First off, you mean 33.4KB uncompressed (for the File Import/Exports info).

Secondly, NirSoft's DLL Export Viewer incorrectly reports the code address, because that function doesn't actually exist in kernel32.dll. In the PE, it gives an offset that points to a 'forwarder' string. That means that "NTDLL.RtlAddVectoredExceptionHandler" tells you where the function really exists - in NTDLL.DLL, as the function name RtlAddVectoredExceptionHandler. Read my first post, hopefully that will help you understand what forwarding is, and why NirSoft's program reports bad information.


Share this post


Link to post
Share on other sites

How about that - Nirsoft actually listened to feedback :huh2:

DLL Export Viewer finally has forwarder string information reported correctly as of v1.50.

On another note.. I've noticed some .EXE files are putting Imports all over - inside different sections of the PE. wth? Anyway.. causes the program to crash currently, so if anyone sees a crash, this is most likely whats happening. I'd call it non-standard, but Windows handles it fine, as do some other PE viewers (some crash though). That was a very annoying bugger to track down.

What this means is that I need to search for the right section and recalculate RVA Offsets for each and every Import. What a pain.. Anyhoo.. that's on my to-do list for the next version. Just thought I'd at least log the problem here in the meantime and tell y'all to update your copy of DLL Export Viewer as well ;)


Share this post


Link to post
Share on other sites

Any sample code how you use export functions of a dll to my own script would appreciated?

Thanks

Edited by mailro

Share this post


Link to post
Share on other sites

You'd need to figure that out for yourself. If you are planning on calling a function in a DLL, you need to know what parameters it takes, as well as the return value. If its a standard Microsoft DLL, you can find the documentation for the function on MSDN. Any other DLL's, you need to know who made it and then check their website for info on calling the functions. I think WinAPIOverride32 lets you explore how certain DLL functions are called, though the program seems to crash more than anything for me.


Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
Sign in to follow this  

  • Similar Content

    • By RAMzor
      Hello all!
      I got the Acroname Programmable USB Hub based on BrainStem platform. I will use it to manage ports and read current.
      They have development kit (BRAINSTEM DEVELOPMENT KIT) with examples for any languages like C#, C++, LabVIEW and python but no AutoIt.
      The kit include BrainStem2.dll (x32 and x64), BrainStem2_LabVIEW.dll, BrainStem2CLI.dll and many examples.
      Anyone used this dll and implemented it in AutoIt?
      Please share some example for Device Discovering, User LED Flashing or power enable/disable on port to start play with this HUB
      BrainStem Reference 
       
      BrainStem2 lib+example.7z USB HUB User Manual s79-usbhub-3p_v1.10_0.pdf
    • By Scriptmaster
      <NEWBIE ALERT>
      Is it possible to unzip a zip file in Autoit without using a dll!
      My script downloads a zip file to a temporary directory (successfully) and it must be unzipped to (Or moved to after unzip) another a folder which just happens to be
      @scriptdir & "file.exe" Thanks in advance
    • By Inpho
      Hi All,
      I intend on keeping custom functions/UDFs (works in progress) here; if anyone wants to use any code, feel free.
      String functions:
      #AutoIt3Wrapper_AU3Check_Parameters=-d -w- 1 -w 2 -w 3 -w 4 -w 5 -w 6 #include-once ; #FUNCTION# ==================================================================================================================== ; Name ..........: _DateTimeGet ; Description ...: Returns the date and time formatted for use in sortable filenames, logs, listviews, etc. ; Syntax ........: _DateTimeGet(iType = 1[, $bHumanFormat = False]) ; Parameters ....: $iType - [optional] an integer value. Default is 1. ; 1 - Date and time in file-friendly format; 20190115_113756 ; 2 - Date in file-friendly format; 20190115 ; 3 - Time in file friendly format; 113756 ; $bHumanFormat - [optional] a boolean value. Default is False. ; True - Includes slashes in the date and colons in the time with a space inbetween ; False - No slashes or colons included with an underscore inbetween ; Return values .: Success - String ; Failure - Sets @error to non-zero and returns an empty string ; Author ........: Sam Coates ; =============================================================================================================================== Func _DateTimeGet($iType = 1, $bHumanFormat = False) If $iType < 1 Or $iType > 3 Then Return (SetError(-1, 0, "")) ;; Param1: ;; 1 = Date and time in file friendly format: 20190115_113756 ;; 2 = Date in file friendly format: 20190115 ;; 3 = Time in file friendly format: 113756 ;; Param2: ;; True = Use human-readable format: 15/01/2019 11:37:56 Local $sTime = @HOUR & ":" & @MIN & ":" & @SEC Local $sDate = @MDAY & "/" & @MON & "/" & @YEAR If $iType = 1 Then If $bHumanFormat = False Then $sTime = StringReplace($sTime, ":", "") $sDate = StringReplace($sDate, "/", "") $sDate = StringTrimLeft($sDate, 4) & StringMid($sDate, 3, 2) & StringLeft($sDate, 2) Return ($sDate & "_" & $sTime) Else Return ($sDate & " " & $sTime) EndIf ElseIf $iType = 2 Then If $bHumanFormat = False Then $sDate = StringReplace($sDate, "/", "") $sDate = StringTrimLeft($sDate, 4) & StringMid($sDate, 3, 2) & StringLeft($sDate, 2) EndIf Return ($sDate) ElseIf $iType = 3 Then If $bHumanFormat = False Then $sTime = StringReplace($sTime, "/", "") EndIf Return ($sTime) EndIf EndFunc ;==>_DateTimeGet ; #FUNCTION# ==================================================================================================================== ; Name ..........: _FileToFileExtension ; Description ...: Returns a file extension from a filename/FQPN (Fully Qualified Path Name) ; Syntax ........: _FileToFileExtension($sPath) ; Parameters ....: $sPath - a string value. ; Return values .: Success - String ; Failure - Empty string as returned from StringTrimLeft() ; Author ........: Sam Coates ; =============================================================================================================================== Func _FileToFileExtension($sPath) Return (StringTrimLeft($sPath, StringInStr($sPath, ".", 0, -1))) EndFunc ;==>_FileToFileExtension ; #FUNCTION# ==================================================================================================================== ; Name ..........: _FileToFileName ; Description ...: Returns a filename from a FQPN (Fully Qualified Path Name) ; Syntax ........: _FileToFileName($sPath[, $bIncludeExtension = True]) ; Parameters ....: $sPath - a string value. ; $bIncludeExtension - [optional] a boolean value. Default is True. ; Return values .: Success - String ; Failure - Empty string as returned from StringLeft() ; Author ........: Sam Coates ; =============================================================================================================================== Func _FileToFileName($sPath, $bIncludeExtension = True) Local $sReturn = StringTrimLeft($sPath, StringInStr($sPath, "\", 0, -1)) If $bIncludeExtension = False Then $sReturn = StringLeft($sReturn, StringInStr($sReturn, ".", 0, -1) - 1) Return ($sReturn) EndFunc ;==>_FileToFileName ; #FUNCTION# ==================================================================================================================== ; Name ..........: _FileToFilePath ; Description ...: Returns a folder path from a FQPN (Fully Qualified Path Name) ; Syntax ........: _FileToFilePath($sPath) ; Parameters ....: $sPath - a string value. ; Return values .: Success - String ; Failure - Empty string as returned from StringLeft() ; Author ........: Sam Coates ; =============================================================================================================================== Func _FileToFilePath($sPath) Return (StringLeft($sPath, StringInStr($sPath, "\", 0, -1) - 1)) EndFunc ;==>_FileToFilePath ; #FUNCTION# ==================================================================================================================== ; Name ..........: _StringLeft ; Description ...: Searches for a string inside a string, then removes everything on the right of that string ; Syntax ........: _StringLeft($sString, $sRemove[, $iCaseSense = 0, $iOccurrence = 1]) ; Parameters ....: $sString - a string value. The string to search inside. ; $sRemove - a string value. The string to search for. ; $iCaseSense - an integer value. Flag to indicate if the operations should be case sensitive. ; $iOccurrence - an integer value. Which occurrence of the substring to find in the string. Use a ; negative occurrence to search from the right side. ; Return values .: Success - String ; Failure - Empty string as returned from StringLeft() ; Author ........: Sam Coates ; =============================================================================================================================== Func _StringLeft($sString, $sRemove, $iCaseSense = 0, $iOccurrence = 1) Return (StringLeft($sString, StringInStr($sString, $sRemove, $iCaseSense, $iOccurrence) - 1)) EndFunc ;==>_StringLeft ; #FUNCTION# ==================================================================================================================== ; Name ..........: _StringRandom ; Description ...: Returns a string of random characters ; Syntax ........: _StringRandom($iAmount[, $iType = 1]) ; Parameters ....: $iAmount - an integer value. Length of returned string ; $iType - [optional] an integer value. Default is 1. ; 1 - Return digits (0-9) ; 2 - Return hexadecimal (0-9, A - F) ; 3 - Return Alphanumeric upper (0-9, A - Z) ; 4 - Return Alphanumeric (0-9, A - Z, a - z) ; 5 - Return Alpha upper (A - Z) ; 6 - Return Alpha (A - Z, a - z) ; Return values .: Success - String ; Failure - Empty string and @error flag as follows: ; @error : 1 - $iAmount is not a positive integer ; 2 - $iType is out of bounds ; Author ........: Sam Coates ; =============================================================================================================================== Func _StringRandom($iAmount, $iType = 1) If $iAmount < 1 Or IsInt($iAmount) = 0 Then Return (SetError(-1, 0, "")) Local $sString = "" Local $iRandomLow = 1, $iRandomHigh = 62 #Tidy_Off Local Static $aCharId[63] = [0, Chr(48), Chr(49), Chr(50), Chr(51), Chr(52), Chr(53), Chr(54), Chr(55), Chr(56), Chr(57), Chr(65), Chr(66), Chr(67), _ Chr(68), Chr(69), Chr(70), Chr(71), Chr(72), Chr(73), Chr(74), Chr(75), Chr(76), Chr(77), Chr(78), Chr(79), Chr(80), _ Chr(81), Chr(82), Chr(83), Chr(84), Chr(85), Chr(86), Chr(87), Chr(88), Chr(89), Chr(90), Chr(97), Chr(98), Chr(99), _ Chr(100), Chr(101), Chr(102), Chr(103), Chr(104), Chr(105), Chr(106), Chr(107), Chr(108), Chr(109), Chr(110), Chr(111), _ Chr(112), Chr(113), Chr(114), Chr(115), Chr(116), Chr(117), Chr(118), Chr(119), Chr(120), Chr(121), Chr(122)] #Tidy_On If $iType = 1 Then ;; digits: 1 - 10 $iRandomHigh = 10 ElseIf $iType = 2 Then ;; hexadecimal: 1 - 16 $iRandomHigh = 16 ElseIf $iType = 3 Then ;; alnumupper: 1 - 36 $iRandomHigh = 36 ElseIf $iType = 4 Then ;; alnum: 1 - 62 $iRandomHigh = 62 ElseIf $iType = 5 Then ;; alphaupper: 11 - 36 $iRandomLow = 11 $iRandomHigh = 36 ElseIf $iType = 6 Then ;; alpha: 11 = 62 $iRandomLow = 11 $iRandomHigh = 62 Else Return (SetError(-2, 0, "")) EndIf For $i = 1 To $iAmount $sString &= $aCharId[Random($iRandomLow, $iRandomHigh, 1)] ;; append string with corresponding random character from ascii array Next Return ($sString) EndFunc ;==>_StringRandom ; #FUNCTION# ==================================================================================================================== ; Name ..........: _StringTrimLeft ; Description ...: Searches for a string inside a string, then removes everything on the left of that string ; Syntax ........: _StringTrimLeft($sString, $sRemove[, $iCaseSense = 0, $iOccurrence = 1]) ; Parameters ....: $sString - a string value. The string to search inside. ; $sRemove - a string value. The string to search for. ; $iCaseSense - an integer value. Flag to indicate if the operations should be case sensitive. ; $iOccurrence - an integer value. Which occurrence of the substring to find in the string. Use a ; negative occurrence to search from the right side. ; Return values .: Success - String ; Failure - Empty string as returned from StringTrimLeft() ; Author ........: Sam Coates ; =============================================================================================================================== Func _StringTrimLeft($sString, $sRemove, $iCaseSense = 0, $iOccurrence = 1) Return (StringTrimLeft($sString, StringInStr($sString, $sRemove, $iCaseSense, $iOccurrence) + StringLen($sRemove) - 1)) EndFunc ;==>_StringTrimLeft Examples:
      ConsoleWrite(_StringRandom(100, 6) & @CRLF) ConsoleWrite(_StringTrimLeft("C:\Windows\System32\cmd.exe", "C:\Windows\System32\") & @CRLF) ConsoleWrite(_StringLeft("C:\Windows\System32\cmd.exe", "cmd.exe") & @CRLF) ConsoleWrite(_FileToFileName("C:\Windows\System32\cmd.exe") & @CRLF) ConsoleWrite(_FileToFilePath("C:\Windows\System32\cmd.exe") & @CRLF) ConsoleWrite(_FileToFileExtension("C:\Windows\System32\cmd.exe") & @CRLF) ConsoleWrite(_StringRandom(6, 4) & "-" & _StringRandom(4, 4) & "-" & _StringRandom(4, 4) & "-" & _StringRandom(4, 4) & "-" & _StringRandom(6, 4)& @CRLF)  
    • By dinotom
      Can files be read from the web or the cloud?
      I am trying to read this file but get the file open error.
      #include <FileConstants.au3> #include <MsgBoxConstants.au3> ;Assign the file path to a variable Local $sFilePath = "C:\Automation\test.txt" Local $sFilePathAzure ="https://batlgroupimages.blob.core.windows.net/files/test.txt" Local $nLineNumberToLookFor = 0 ;Open the file test.txt in append mode. ;If the folder C:\Automation does not exist, it will be created. Local $hFileOpen = FileOpen($sFilePathAzure, $FO_APPEND + $FO_CREATEPATH) ;Display a message box in case of any errors. If $hFileOpen = -1 Then MsgBox($MB_SYSTEMMODAL, "", "An error occurred while opening the file.") EndIf ;Set the file position to beginning for reading the data from the beginning of the file. FileSetPos($hFileOpen, 0, $FILE_BEGIN) ;Read the data from the file using the handle returned by FileOpen ;Local $sFileRead = FileRead($hFileOpen) ;Read the 2nd line of data from the file using the handle returned by FileOpen Local $sFileReadLine = FileReadLine ($hFileOpen,2) ;Close the handle returned by FileOpen. FileClose($hFileOpen)  
    • By matwachich
      Hi guys!
      A pretty simple UDF to convert HTML to PDF using wkHTMLtoPDF.
      It uses the C API of the tool (DLL), so no external process, no ActiveX or COM sh*t.
      See the example, and the documentation of wkHTMLtoPDF.
      Cheers
      https://github.com/matwachich/wkhtmltopdf-au3
×
×
  • Create New...