I tried contacting Borje Hagsten to get permission to update PBCodec and wound up exchanging emails with Donnie Ewald.
Mr Ewald said, and the comments in the code found on the PB Codec Link on
http://http://www.reonis.com/POFFS/index.htm both indicate this is Public Domain code.
It is a very powerful tool that has helped me save 20-30K bytes on my DLLs and in one case 170K on a coworker's DLL.
Particularly helpful is the section of the report that details "included-but-not-used-functions() and subs()".
Deleting them (and the types associated) can really shrink a DLL/EXE.
There were several items that I have taken the liberty to update.
Items I believe are still unaddressed:
Still, it is an improvement.
PBCodec.BAS
PBCodec.Inc
Mr Ewald said, and the comments in the code found on the PB Codec Link on
http://http://www.reonis.com/POFFS/index.htm both indicate this is Public Domain code.
It is a very powerful tool that has helped me save 20-30K bytes on my DLLs and in one case 170K on a coworker's DLL.
Particularly helpful is the section of the report that details "included-but-not-used-functions() and subs()".
Deleting them (and the types associated) can really shrink a DLL/EXE.
There were several items that I have taken the liberty to update.
- Whenever a $TAB preceeded #COMPILE, the tool produced a msgbox and gave up.
- There was no support for conditional compilation
- #IF %ABC
- #IF NOT %ABC
- #IF %Def(%ABC)
- #IF NOT %DEF(%ABC)
- #ELSE...
- PB 9.0 seems to have eliminated the need to DECLARE every function or Sub yet there is an "Non-Declared Function/Sub" section of the report. In this case I added a checkbox on the main dialog that can be used to omit that section.
- several #Include ONCE's produced multiple sets of report items.
Items I believe are still unaddressed:
- #ELSEIF %ABC
- #ELSEIF %Def(%ABC)
- Built-in Numeric Equates (some would be compiler specific some code specific)
- Spiffy new GUI
- Use OPENFILE statement instead of OPENFILEDIALOG()
Still, it is an improvement.
PBCodec.BAS
Code:
'¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤ ' PBcodec, Source Code Checker, v1.25 '----------------------------------------------------------------------------- ' Scans a main source file and all its include files for Un-used Subs, ' Functions, and variables. Version 1.1 also has ability to extract string ' literals, that is, strings withing double-quotes. ' ' PBcodec will save the result in a file ending with --LOG.TXT and also show ' this file in associated texteditor. ' ' This version does not process any Conditional Compiling statements, so far, ' but all files are properly scanned and it even handles "DIM x AS GLOBAL in ' a correct way. Tested on my own projects, all reports so far has been correct. ' ' The output will show the SUB,FUNCT and VAR name followed by [FileName: 565 ' where the last number is the line number where the item is declared. It will ' also present a list of all Includes, Global vars, Subs and Functions, this ' part originally written by Wayne Diamond. ' ' Public Domain, this version by Borje Hagsten, July 2001, but main credits ' goes to Scott Slater for showing us it could be done (and how to do it). ' Parts of this program has been copied from his version, but parsing and ' some other things has been totally rewritten, my way.. ' Many have been involved, giving many valuable tips and providing code, ' so one could say this is the result of a joined PB community effort.. :) ' ' Tip: Prog launches txt-associated texteditor to show report. Standard is ' NotePad. I have set mine to use Courier New, 9p, which gives nice output.. ' ' A few notes: Exported subs/functions, or ones inside "public" include files, ' may have a reference count of zero and still not be un-used, since some other ' program may be using them. ' ' Also, since one of the advantages with the PB language is almost unlimited ' flexibility to do things, there's no guaranties everything will be found, ' or even be 100% correct. It has proved to be successful on my projects, ' but please, use this (and similar) programs with extreme care.. ' ' LOG: ' Aug 11, 2003 - added some extrs checks for line wraps, _ to DoProcess ' Jan 23, 2002 - added support for relative include paths, plus optimized ' some for better speed, etc. ' Jan 23, 2002 - added support for relative include paths, plus optimized ' some for better speed, etc. ' Jan 17, 2002 - changed to use IsCharAlphaNumeric in ANSItrim, to include ' leading/trailing digits in string literals. Also had to change ' UCASER function a bit, so all now can be compiled in PBDLL 6.1 too.. ' Oct 17, Corrected error in DoSaveResults, where global/local name mix warning ' could end up pointing at wrong file for first local declare. ' Oct 10, added exclude() array to avoid some of the most common include file ' names when extracting string literals. Possible to expand - see WinMain. ' Also set string literal extraction checkbox as checked from start. ' Oct 09, added possibility to extract string literals, that is, text within ' double-quotes. Added AnsiTRIM function for this purpose. ' Aug 01, in DoSaveResults, moved REDIM PRESERVE lVars out from loop in first ' IF/THEN block and reversed loop, because it sometimes GPF'd there. ' Of course it could GPF. Must run such loops backwards, silly me. ' Aug 01, removed AllLocals array and use lVars to store all locals instead. ' Changed report accordingly and now, Global/Local name mix lists ' Line number for local representations too. ' Jul 31, excluded declarations of Subs/Function from usage check ' Jul 31, re-fixed previous stupid fix of GLOBAL DIM, so it works this time.. ' Jul 29, fixed code in DoProcess - ExtractLocals, to check DIM more carefully, ' since DIM/REDIM may have been preceeded with a GLOBAL declare of same variable. ' Jul 29, added support for multiple include file paths in WinMain and DoGetIncFiles ' Added check for trailing backslash to fExist, so paths are handled correctly ' Jul 29, added code to DoProcess - ExtractSub, to exclude declares for external ' procedures (in DLL's etc.) from being counted as "declared but un-used". ' Also added code to DoProcess - ExtractLine, to replace colons within ' paranthesis, which could cause weird results when parsing a line for colons. ' Jul 29, added "Scan" button to enable easy rescanning of a file, since I ' have found this useful to do after changes have been made. Also did ' some minor tweaking of the code to enhance performance. ' Jul 28, major trimming of parser, to ensure results and improve performance. ' Sep 22 2009 IsMainFile() will no longer balk at $TAB before #compile - Nathan Maddox ' Sep 26 2009 Added ReadFile() to simplify development going forward ' Sep 26 2009 Added support for #IF %ABC conditional compile ' Sep 26 2009 Added support for #IF NOT %ABC conditional compiles ' Sep 26 2009 Added Support for #IF %Def(%ABC) conditional compiles ' Sep 26 2009 Added Support for #IF NOT %Def(%ABC) conditional compiles ' Sep 26 2009 Added support for #ELSE ' Sep 26 2009 Added checkbox to control whether or not the ' "Existing Function()'s and Subs()'s that are not Declared Report" ' PB 9.0 eliminated the need for Declaring all Sub()'s and Function()'s '¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤ #COMPILE EXE #INCLUDE "PBCODEC.INC" 'Basic Win API definitions TYPE InfoStruct uName AS ASCIIZ * 100 'is 100 enough? For me it is, but if not for you, increase.. zName AS ASCIIZ * 100 inFunct AS ASCIIZ * 100 IsUsed AS LONG iType AS LONG FileNum AS LONG LineNum AS LONG SubEnd AS LONG Exported AS LONG END TYPE TYPE EquateCnsts EquateName AS STRING * 50 EquateVal AS LONG END TYPE TYPE CondCompType EquateName AS STRING * 50 IncludeIt AS LONG END TYPE GLOBAL Vars() AS InfoStruct ' All Locals in Current Proc (TEMP) GLOBAL gVars() AS InfoStruct ' All Globals GLOBAL gDbl() AS InfoStruct ' Duplicate Global names GLOBAL gDecl() AS InfoStruct ' Declared Subs/Functions GLOBAL lVars() AS InfoStruct ' Un-Used Locals GLOBAL Functs() AS InfoStruct ' All Functions GLOBAL EqCnst() AS EquateCnsts GLOBAL CComp() AS CondCompType GLOBAL Files() AS STRING GLOBAL inFile() AS STRING GLOBAL sIncDir() AS STRING GLOBAL sString() AS STRING 'for string literals GLOBAL exclude() AS STRING 'for exclude strings GLOBAL getStrings AS LONG, sStrCount AS LONG GLOBAL NotDecl AS LONG GLOBAL FilePathStr AS STRING, FileNameStr AS STRING, DestFile AS STRING GLOBAL sWork AS STRING, LineStr AS STRING GLOBAL Done AS LONG GLOBAL igDbl AS LONG ' # of Duplicate Globals GLOBAL iVars AS LONG ' # of Vars GLOBAL ilVars AS LONG ' # of lVars GLOBAL igVars AS LONG ' # of gVars GLOBAL iFuncts AS LONG ' # of Functs GLOBAL DeclCount AS LONG GLOBAL gTotLines AS LONG, t AS SINGLE GLOBAL True, False AS LONG DECLARE CALLBACK FUNCTION WinMainProc() AS LONG DECLARE FUNCTION AnsiTRIM(BYVAL txt AS STRING) AS STRING DECLARE FUNCTION DoGetIncFiles(BYVAL TheFile AS STRING) AS LONG DECLARE FUNCTION DoProcess(BYVAL TheFile AS STRING, BYVAL fNum AS LONG, WhatRun AS LONG) AS LONG DECLARE FUNCTION GetCommandFile(BYVAL CmdStr AS STRING, Fi() AS STRING) AS LONG DECLARE FUNCTION GetDroppedFile(BYVAL hDrop AS LONG, Fi() AS STRING) AS LONG DECLARE FUNCTION GetIncludeDir AS STRING DECLARE FUNCTION IniGetString(BYVAL sSection AS STRING, BYVAL sKey AS STRING, _ BYVAL sDefault AS STRING, BYVAL sFile AS STRING) AS STRING DECLARE FUNCTION IsFileMain(BYVAL fName AS STRING) AS LONG DECLARE FUNCTION UCASER(BYVAL st AS STRING) AS STRING DECLARE SUB DoInitProcess(BYVAL hDlg AS LONG, BYVAL fName AS STRING) DECLARE SUB DoSaveResults FUNCTION ReadFile(BYVAL FileName AS STRING, BYREF Arr() AS STRING) AS LONG LOCAL FileNum AS LONG LOCAL FileSiz AS LONG LOCAL COUNT AS LONG LOCAL Buf AS STRING Filenum=FREEFILE OPEN FileName FOR BINARY ACCESS READ SHARED AS #FileNum FileSiz=LOF(FileNum) GET$ #FileNum, FileSiz, Buf CLOSE #FileNum buf=REMOVE$(buf, ANY $TAB) buf=UCASE$(buf) '---- Parse the Records REPLACE $CRLF WITH $CR IN Buf COUNT=PARSECOUNT(Buf, $CR) REDIM Arr(1:COUNT) AS STRING PARSE Buf, Arr(), $CR FOR COUNT=1 TO UBOUND(Arr) Arr(COUNT)=TRIM$(Arr(COUNT)) NEXT '---- Set Function Result FUNCTION=COUNT END FUNCTION '¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤ ' Main entrance - create dialog, etc. '¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤ FUNCTION WINMAIN (BYVAL hCurInstance AS LONG, _ BYVAL hPrevInstance AS LONG, _ BYVAL lpszCmdLine AS ASCIIZ PTR, _ BYVAL nCmdShow AS LONG) AS LONG LOCAL hDlg AS LONG, iCnt AS LONG, rc AS RECT, tmpIncDir AS STRING, tmpStr AS STRING LOCAL I AS LONG REDIM sIncDir(0) REDIM EqCnst(0) AS EquateCnsts REDIM CComp(0) AS CondCompType False=0 : True= NOT False DIALOG NEW 0, "PBcodec v1.25", , , 200, 70, %WS_CAPTION OR %WS_MINIMIZEBOX OR %WS_SYSMENU TO hDlg IF hDlg = 0 THEN EXIT FUNCTION CONTROL ADD LABEL, hDlg, 114, "", 2, 2, 192, 20, %SS_CENTER, %WS_EX_CLIENTEDGE CONTROL ADD LABEL, hDlg, 115, " Main file: ", 2, 27, 161, 10 CONTROL ADD BUTTON, hDlg, 120, " &Browse..", 4, 53, 50, 14 CONTROL ADD BUTTON, hDlg, %IDOK, "&Scan", 58, 53, 50, 14 CONTROL ADD BUTTON, hDlg, %IDCANCEL, "&Quit", 112, 53, 50, 14 CONTROL ADD CHECKBOX, hDlg, %IDC_CheckBox1, "E&xtract string literals ", 4, 39, 80, 10 CONTROL SET CHECK hDlg, %IDC_CheckBox1, 1 CONTROL ADD CHECKBOX, hDlg, %IDC_CheckBox2, "Non-Declared Sub()/Fx()",100, 39, 90, 10 CONTROL SET CHECK hDlg, %IDC_CheckBox2, 1 CONTROL DISABLE hDlg, %IDOK tmpIncDir = GetIncludeDir 'grab include path from registry IF LEN(tmpIncDir) THEN 'if we got anything IF INSTR(tmpIncDir, ";") THEN 'if it contains multiple paths FOR I = 1 TO PARSECOUNT(tmpIncDir, ";") 'loop through string tmpStr = TRIM$(PARSE$(tmpIncDir, ";", I)) 'parse out each path IF LEN(tmpStr) AND TRIM$(DIR$(tmpStr))<>"" THEN 'if we got a path and it exists REDIM PRESERVE sIncDir(iCnt) 'prepare array IF ASC(tmpStr, -1) = 92 THEN 'if a path with trailing backslash sIncDir(iCnt) = tmpStr 'store path in array element ELSE 'else sIncDir(iCnt) = tmpStr + "\" 'make sure it has a trailing backslash END IF INCR iCnt 'increase temporary array counter END IF NEXT ELSE 'else, single path was given IF TRIM$(DIR$(tmpIncDir))<>"" THEN 'if it exists IF ASC(tmpIncDir, -1) = 92 THEN 'if a path with trailing backslash sIncDir(0) = tmpIncDir 'store path in first array element ELSE 'else sIncDir(0) = tmpIncDir + "\" 'make sure it has a trailing backslash END IF END IF END IF END IF SystemParametersInfo %SPI_GETWORKAREA, BYVAL 0, BYVAL VARPTR(rc), 0 'grab desktop cordinates DIALOG PIXELS hDlg, rc.nRight, rc.nBottom TO UNITS rc.nRight, rc.nBottom 'convert to dialog units DIALOG SET LOC hDlg, rc.nRight - 220, rc.nBottom - 100 'place dialog bottom, right SetWindowPos hDlg, %HWND_TOPMOST, 0, 0, 0, 0, %SWP_NOMOVE OR %SWP_NOSIZE 'set dialog topmost DragAcceptFiles hDlg, %True 'enable drag&drop REDIM exclude(24) 'exclude these string literals exclude(0) = "WIN32API.INC" : exclude(1) = "COMDLG32.INC" exclude(2) = "COMMCTRL.INC" : exclude(3) = "DDT.INC" exclude(4) = "MDI32.INC" : exclude(5) = "COMBO32.INC" exclude(6) = "LISTVIEW.INC" : exclude(7) = "TRVIEW32.INC" exclude(8) = "RICHEDIT.INC" : exclude(9) = "EDIT32.INC" exclude(10) = "BUTTON32.INC" : exclude(11) = "MMSYSTEM.INC" exclude(12) = "WSOCK32.INC" : exclude(13) = "STATIC32.INC" exclude(14) = "DPMI.INC" : exclude(15) = "LZEXPAND.INC" exclude(16) = "TOOLHLP.INC" : exclude(17) = "VBAPI.INC" exclude(18) = "CTL3D.INC" : exclude(19) = "VER.INC" exclude(20) = "WINAPI.INC" : exclude(21) = "WINSOCK.INC" exclude(22) = "COMMDLG.INC" : exclude(23) = "PROGRAM" exclude(24) = "WIN32API.INC" DIALOG SHOW MODAL hDlg CALL WinMainProc END FUNCTION '¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤ ' Main callback procedure '¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤ CALLBACK FUNCTION WinMainProc() AS LONG SELECT CASE CBMSG CASE %WM_INITDIALOG REDIM Files(1) ' Reset Array REDIM infile(1) IF LEN(COMMAND$) THEN IF GetCommandFile(COMMAND$, Files()) THEN ' Retrieve the contents of the Command String LOCAL sTimer AS LONG sTimer = SETTIMER(CBHNDL, 1, 400, %NULL) ' wait for window to draw END IF ELSE CONTROL SET TEXT CBHNDL, 114, "Drag && Drop a main source file on dialog, " + $CRLF + _ "or use Browse to select a file to Scan.." END IF CASE %WM_CTLCOLORSTATIC IF CBLPARAM = GetDlgItem(CBHNDL, 114) THEN SetBkColor CBWPARAM, GetSysColor(%COLOR_INFOBK) FUNCTION = GetSysColorBrush(%COLOR_INFOBK) END IF CASE %WM_TIMER KILLTIMER CBHNDL, 1 CALL DoInitProcess(CBHNDL, Files(0)) CASE %WM_DROPFILES REDIM Files(1) ' Reset Array REDIM infile(1) IF GetDroppedFile(CBWPARAM, Files()) THEN ' Retrieve the Dropped filenames CALL DoInitProcess(CBHNDL, Files(0)) END IF CASE %WM_DESTROY CALL DragAcceptFiles(CBHNDL, 0) CASE %WM_COMMAND SELECT CASE CBCTL CASE 120 'Browse LOCAL STYLE AS DWORD, fName AS STRING, Buffer AS STRING, PATH AS STRING STYLE = %OFN_EXPLORER OR %OFN_FILEMUSTEXIST OR %OFN_HIDEREADONLY fName = "*.BAS" Buffer = "PB Code files (*.BAS)|*.BAS|" PATH = CURDIR$ IF OpenFileDialog(CBHNDL, "", fName, PATH, Buffer, "BAS" , STYLE) THEN REDIM Files(1) ' Reset Array REDIM infile(1) Files(0) = fName fName = MID$(fName, INSTR(-1, fName, "\") + 1) CONTROL SET TEXT CBHNDL, 115, " Main file: " & UCASER(fName) CONTROL ENABLE CBHNDL, %IDOK CALL DoInitProcess(CBHNDL, Files(0)) '<- deactivate, if not to scan directly.. END IF CASE %IDOK REDIM PRESERVE Files(1) CALL DoInitProcess(CBHNDL, Files(0)) 'scan file CASE %IDCANCEL ' Quit Done = 1 ' jump out of any loops DIALOG END CBHNDL ' and QUIT END SELECT END SELECT END FUNCTION '************************************************************************ ' Initiate and run entire process '************************************************************************ SUB DoInitProcess(BYVAL hDlg AS LONG, BYVAL fName AS STRING) LOCAL ci AS LONG, mc AS LONG FOR ci = 1 TO 10 : DIALOG DOEVENTS : NEXT IF TRIM$(DIR$(fName))<>"" THEN 'make sure it exists ci = IsFileMain(fName) 'if a #COMPILE statement exists (main source file) IF ci = -3 THEN 'if return is -3, file was empty MSGBOX "Selected file is empty.",,"Error!" EXIT SUB ELSEIF ci = -2 THEN 'if return is -2, file could not be opened MSGBOX "Selected file could not be opened!",,"Error!" EXIT SUB ELSEIF ci >= 0 THEN 'if return is >= 0, file was not a main source file MSGBOX "Selected file does not contain a #COMPILE statement.",,"Error!" EXIT SUB END IF ELSE 'else, it didn't even exist.. MSGBOX "Could not open this file:" + $CRLF + fName + $CRLF + $CRLF + _ "Please make sure it exists and try again.",,"Error!" EXIT SUB END IF CONTROL GET CHECK hDlg, %IDC_CheckBox1 TO getStrings 'Extract Strings CONTROL GET CHECK hDlg, %IDC_CheckBox2 TO NotDecl 'Extract Strings CONTROL DISABLE hDlg, 120 CONTROL DISABLE hDlg, %IDOK CONTROL DISABLE hDlg, %IDC_CheckBox1 CONTROL DISABLE hDlg, %IDC_CheckBox2 FilePathStr = LEFT$(fName, INSTR(-1, fName, "\")) FileNameStr = MID$(fName, INSTR(-1, fName, "\") + 1) CONTROL SET TEXT hDlg, 115, " Main file: " & UCASER(FileNameStr) IF Files(0) = "" THEN Files(0) = fName CHDRIVE LEFT$(FilePathStr, 2) CHDIR FilePathStr CONTROL SET TEXT hDlg, 114, "Collecting include files" DoGetIncFiles fName iFuncts = 0 : REDIM Functs(0) igVars = 0 : REDIM gVars(0) ilVars = 0 : REDIM lVars(0) iVars = 0 : REDIM Vars(0) igDbl = 0 : REDIM gDbl(0) DeclCount = 0 : REDIM gDecl(0) sStrCount = 0 : REDIM sString(0) gTotLines = 0 t = TIMER FOR mc = 0 TO 1 FOR ci = 0 TO UBOUND(Files) SELECT CASE UCASE$(MID$(Files(ci), INSTR(-1, Files(ci), "\") + 1)) 'ignore these CASE "WIN32API.INC", "COMDLG32.INC", "COMMCTRL.INC", "COMBO32.INC", _ "DDT.INC", "MDI32.INC", "LISTVIEW.INC", "TRVIEW32.INC", "RICHEDIT.INC", _ "EDIT32.INC", "BUTTON32.INC", "MMSYSTEM.INC", "WSOCK32.INC", _ "STATIC32.INC", "DPMI.INC", "LZEXPAND.INC", "TOOLHLP.INC", "VBAPI.INC", _ "CTL3D.INC", "VER.INC", "WINAPI.INC", "WINSOCK.INC", "COMMDLG.INC" CASE ELSE IF mc = 0 THEN CONTROL SET TEXT hDlg, 114, "Scanning for Local vars, Subs and Functions in: " + _ MID$(Files(ci), INSTR(-1, Files(ci), "\") + 1) ELSE CONTROL SET TEXT hDlg, 114, "Scanning for Global vars in: " + _ MID$(Files(ci), INSTR(-1, Files(ci), "\") + 1) END IF DoProcess Files(ci), ci, mc END SELECT NEXT IF mc = 0 THEN IF iFuncts THEN REDIM PRESERVE Functs(iFuncts) IF igVars THEN REDIM PRESERVE gVars(igVars) IF ilVars THEN REDIM PRESERVE lVars(ilVars) IF igDbl THEN REDIM PRESERVE gDbl(igDbl) IF DeclCount THEN REDIM PRESERVE gDecl(DeclCount) IF sStrCount THEN REDIM PRESERVE sString(sStrCount) END IF NEXT t = TIMER - t CONTROL ENABLE hDlg, 120 CONTROL ENABLE hDlg, %IDOK CONTROL ENABLE hDlg, %IDC_CheckBox1 CONTROL ENABLE hDlg, %IDC_CheckBox2 CONTROL SET TEXT hDlg, 114, "Done! Drag && Drop a main source file on dialog, " + $CRLF + _ "or use Browse to select a file to Scan.." CALL DoSaveResults END SUB '¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤ ' Get all included files into array '¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤ FUNCTION DoGetIncFiles(BYVAL TheFile AS STRING) AS LONG LOCAL ci AS LONG, ii AS LONG, sTemp2 AS STRING LOCAL A$, B$ LOCAL I, J, K, L, M, N, O, QQ, Found AS LONG REDIM tmpFiles(0) AS STRING REDIM Arr$(0) I=ReadFile(TheFile,Arr$()) '----Bas file goes into Arr$() FOR I=1 TO UBOUND(Arr$) LineStr=Arr$(I) 'Starting point '----- handle comments started with ' J=INSTR(1,LineStr,"'") 'Any Comments? IF J>0 THEN IF J=1 THEN ITERATE FOR '1st char is comment marker LineStr=LEFT$(LineStr,J-1) 'eliminate comments END IF '------ handle comments started with REM J=INSTR(1,LineStr,"REM ") SELECT CASE J CASE 0 : 'No comment CASE 1 : ITERATE FOR '1st char is comment CASE ELSE : A$=MID$(LineStr,J-1,1) IF A$=" " OR A$=":" THEN LineStr=LEFT$(LineStr,MAX(1,J-2)) 'eliminate comments END SELECT '--- Didn't work... below 'Replace Any " " With " " in LineStr '#IF %ABC DO J=INSTR(1,LineStr," ") IF J=0 THEN EXIT DO LineStr=STRDELETE$(LineStr,j,1) LOOP '------ Conditionally compiled code ?? QQ=UBOUND(CComp) 'UDT Array of conditional compiles IF QQ>=1 THEN SELECT CASE True CASE INSTR(1,LineStr,"#ELSE") >0 : CComp(QQ).IncludeIt=IIF(CComp(QQ).IncludeIt=True,False,True) ITERATE FOR CASE INSTR(1,LineStr,"#ENDIF")>0 : REDIM PRESERVE CComp(QQ-1) ITERATE FOR CASE ELSE : IF CComp(QQ).IncludeIt=False THEN ' ? "False"+$CRLF+_ ' "CComp(QQ).EquateName="+CComp(QQ).EquateName+$CRLF+_ ' "CComp(QQ).Includeit="+Str$(CComp(QQ).IncludeIt) ITERATE FOR ELSE ' ? "True"+$CRLF+_ ' "CComp(QQ).EquateName="+CComp(QQ).EquateName+$CRLF+_ ' "CComp(QQ).Includeit="+Str$(CComp(QQ).IncludeIt) END IF END SELECT END IF '------- start looking for triggers in source code SELECT CASE True CASE INSTR(1,LineStr,"#INCLUDE ") >0 : GOSUB GetInclude CASE INSTR(1,LineStr,"$INCLUDE ") >0 : GOSUB GetInclude CASE INSTR(1,LineStr,"#IF %DEF(") >0 : GOSUB CheckEquateIfDef CASE INSTR(1,LineStr,"#IF NOT %DEF(")>0 : GOSUB CheckEquateIfNotDef CASE INSTR(1,LineStr,"#IF NOT %") >0 : GOSUB CheckEquateNotIF CASE INSTR(1,LineStr,"#IF %") >0 : GOSUB CheckEquateIF CASE INSTR(1,LineStr,"%") >0 : GOSUB GetEquate END SELECT NEXT EXIT FUNCTION CheckEquateIfNotDef: J=INSTR(1,LineStr,"%") K=INSTR(J,LineStr," ") L=LEN(LineStr) M=IIF(K>0,MIN(K,L),L) A$=MID$(LineStr,J,L-J+1) 'Name of Equate (everything btwn % and ($SPC or end of String) QQ=UBOUND(CComp)+1 : REDIM PRESERVE CComp(QQ) CComp(QQ).EquateName=A$ GOSUB FindEquate 'Returns Found IF Found>0 THEN 'If Found then Defined CComp(QQ).IncludeIt =False ELSE CComp(QQ).IncludeIt =True END IF RETURN CheckEquateIfDef: J=INSTR(1,LineStr,"%DEF(") : J+=5 K=INSTR(J,LineStr," ") L=LEN(LineStr) M=IIF(K>0,MIN(K,L),L) A$=MID$(LineStr,J,L-J+1) 'Name of Equate (everything btwn % and ($SPC or end of String) QQ=UBOUND(CComp)+1 : REDIM PRESERVE CComp(QQ) CComp(QQ).EquateName=A$ GOSUB FindEquate 'Returns Found IF Found>0 THEN 'If Found then Defined CComp(QQ).IncludeIt =True ELSE CComp(QQ).IncludeIt =False END IF RETURN CheckEquateNotIf: J=INSTR(1,LineStr,"%DEF(") : J+=5 K=INSTR(J,LineStr," ") L=LEN(LineStr) M=IIF(K>0,MIN(K,L),L) A$=MID$(LineStr,J,L-J+1) 'Name of Equate (everything btwn % and ($SPC or end of String) GOSUB FindEquate 'Returns Found IF Found>0 THEN QQ=UBOUND(CComp)+1 : REDIM PRESERVE CComp(QQ) CComp(QQ).EquateName=A$ CComp(QQ).IncludeIt =IIF(EqCnst(Found).EquateVal<>0,False,True) END IF RETURN CheckEquateIf: J=INSTR(1,LineStr,"%") K=INSTR(J,LineStr," ") L=LEN(LineStr) M=IIF(K>0,MIN(K,L),L) A$=MID$(LineStr,J,L-J+1) 'Name of Equate (everything btwn % and ($SPC or end of String) GOSUB FindEquate 'Returns Found IF Found>0 THEN QQ=UBOUND(CComp)+1 : REDIM PRESERVE CComp(QQ) CComp(QQ).EquateName=A$ CComp(QQ).IncludeIt =IIF(EqCnst(Found).EquateVal<>0,True,False) END IF RETURN FindEquate: Found=0 FOR QQ=1 TO UBOUND(EqCnst) B$=TRIM$(EqCnst(QQ).EquateName) IF A$=B$ THEN Found=QQ : EXIT FOR NEXT RETURN 'TYPE EquateCnsts ' EquateName AS STRING * 50 ' EquateVal AS Long 'END TYPE GetEquate: J=INSTR(1, LineStr,"%") 'Position of % (important) K=INSTR(J+1,LineStr,"=") 'Position of = (equal sign) IF J>=1 AND K>=J THEN A$=TRIM$(MID$(LineStr,J,K-J-1)) 'Get Equate Name 'everything btwn % and = SELECT CASE True CASE INSTR(1,A$,"(")>0 : 'ie.. IF JulianDate%("01-01-2010)>=5000 THEN CASE INSTR(1,A$," THEN ")>0 : 'ie.. IF %ABC THEN Function=0 CASE INSTR(1,A$,",")>0 : ' following line continuation %KEY_QUERY_VALUE, hKey) = %ERROR_SUCCESS THEN CASE ELSE : M=LEN(LineStr) 'Length of line N=INSTR(1,LineStr,":") ': continuation ? O=IIF(N>0,MIN(N,M),M) L=UBOUND(EqCnst)+1 : REDIM PRESERVE EqCnst(L) AS EquateCnsts EqCnst(L).EquateName=A$ QQ =VAL(TRIM$(MID$(LineStr,K+1,M-O-1))) EqCnst(L).EquateVal =QQ IF M<LEN(LineStr) THEN 'More to come ? ie.. %ABC=1 : %DEF=2 etc LineStr=RIGHT$(LineStr,LEN(LineStr)-M-1) GOSUB GetEquate 'Psuedo-Recursion :) END IF END SELECT END IF RETURN GetInclude: sWork = PARSE$(LineStr, CHR$(34), 2) 'get filename IF LEFT$(sWork, 2) = ".\" THEN 'resolve eventual relative paths sWork = FilePathStr + MID$(sWork, 2) ELSEIF LEFT$(sWork, 3) = "..\" THEN sWork = LEFT$(FilePathStr, INSTR(-2, FilePathStr, "\")) + MID$(sWork, 4) ELSEIF LEFT$(sWork, 4) = "...\" THEN sTemp2 = LEFT$(FilePathStr, INSTR(-2, FilePathStr, "\")) sWork = LEFT$(sTemp2, INSTR(-2, sTemp2, "\")) + MID$(sWork, 5) ELSEIF LEFT$(sWork, 5) = "....\" THEN sTemp2 = LEFT$(FilePathStr, INSTR(-2, FilePathStr, "\")) sTemp2 = LEFT$(sTemp2, INSTR(-2, sTemp2, "\")) sWork = LEFT$(sTemp2, INSTR(-2, sTemp2, "\")) + MID$(sWork, 6) ELSEIF LEFT$(sWork, 6) = ".....\" THEN sTemp2 = LEFT$(FilePathStr, INSTR(-2, FilePathStr, "\")) sTemp2 = LEFT$(sTemp2, INSTR(-2, sTemp2, "\")) sTemp2 = LEFT$(sTemp2, INSTR(-2, sTemp2, "\")) sWork = LEFT$(sTemp2, INSTR(-2, sTemp2, "\")) + MID$(sWork, 7) ELSEIF LEFT$(sWork, 7) = "......\" THEN sTemp2 = LEFT$(FilePathStr, INSTR(-2, FilePathStr, "\")) sTemp2 = LEFT$(sTemp2, INSTR(-2, sTemp2, "\")) sTemp2 = LEFT$(sTemp2, INSTR(-2, sTemp2, "\")) sTemp2 = LEFT$(sTemp2, INSTR(-2, sTemp2, "\")) sWork = LEFT$(sTemp2, INSTR(-2, sTemp2, "\")) + MID$(sWork, 8) END IF IF INSTR(-1, sWork, ".") = 0 THEN 'if no file extension is given, sWork = sWork + ".BAS" 'compiler assumes .BAS file END IF 'if no path is given, compiler will first look in include dir, so we better start there IF INSTR(sWork, "\") = 0 THEN 'if no path given FOR ii = 0 TO UBOUND(sIncDir) 'loop through the ones we have IF TRIM$(DIR$(sIncDir(ii) + sWork))<>"" THEN 'if file exists sWork = sIncDir(ii) + sWork 'use it END IF NEXT END IF IF LEN(FilePathStr) AND TRIM$(DIR$(FilePathStr + sWork))<>"" THEN 'try with current file's path sWork = FilePathStr + sWork 'if ok, use it END IF IF TRIM$(DIR$(sWork))<>"" THEN 'safety check - if we can find what we got.. sWork=UCASE$(sWork) 'store path + name in temporary array SELECT CASE MID$(Files(ci), INSTR(-1, swork, "\") + 1) CASE "WIN32API.INC", "COMDLG32.INC","COMMCTRL.INC","COMBO32.INC" , _ "DDT.INC" , "MDI32.INC" ,"LISTVIEW.INC","TRVIEW32.INC", _ "RICHEDIT.INC", "EDIT32.INC" ,"BUTTON32.INC","MMSYSTEM.INC", _ "WSOCK32.INC", "STATIC32.INC","DPMI.INC" ,"LZEXPAND.INC", _ "TOOLHLP.INC", "VBAPI.INC" ,"CTL3D.INC" ,"VER.INC" , _ "WINAPI.INC", "WIN32API.Inc","WINSOCK.INC" ,"COMMDLG.INC" : 'Do nothing CASE ELSE : Found=0 ARRAY SCAN Files(),=swork, TO Found '#include once ... laziness IF Found=0 THEN QQ=UBOUND(files) A$=files(QQ) : A$=REMOVE$(A$,ANY CHR$(0)) IF TRIM$(A$)="" THEN Files(QQ) =swork InFile(QQ)=MID$(TheFile, INSTR(-1, TheFile, "\") + 1) ELSE INCR QQ REDIM PRESERVE files(QQ) : Files(QQ) =swork REDIM PRESERVE infile(QQ) : InFile(QQ)=MID$(TheFile, INSTR(-1, TheFile, "\") + 1) END IF CALL DoGetIncFiles(swork) 'recursive call to get eventual includes in includes END IF END SELECT END IF RETURN END FUNCTION '¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤ ' Trim away all leading/ending non-letters and digits from a string '¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤ FUNCTION AnsiTRIM(BYVAL txt AS STRING) AS STRING LOCAL pos1 AS LONG, pos2 AS LONG FOR pos1 = 1 TO LEN(txt) IF IsCharAlphaNumeric(ASC(txt, pos1)) THEN EXIT FOR NEXT FOR pos2 = LEN(txt) TO 1 STEP -1 IF IsCharAlphaNumeric(ASC(txt, pos2)) THEN EXIT FOR NEXT IF Pos2 > Pos1 THEN FUNCTION = MID$(txt, Pos1, Pos2 - Pos1 + 1) END FUNCTION '¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤ ' Load text from file, extract lines and get all subs, functions and globals ' into arrays. '¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤ FUNCTION DoProcess(BYVAL TheFile AS STRING, BYVAL fNum AS LONG, WhatRun AS LONG) AS LONG IF TRIM$(DIR$(TheFile))="" THEN EXIT FUNCTION 'if file doesn't exist, exit LOCAL ci AS LONG, I AS LONG, p AS LONG, Letter AS BYTE PTR, Letter2 AS BYTE PTR LOCAL Ac AS LONG, K AS LONG, sFlag AS LONG, QuotePos AS LONG, QuotePos2 AS LONG, dbl AS LONG, dUscored AS LONG LOCAL exported AS LONG, x AS LONG, y AS LONG, uscoredGlobal AS LONG, endRout AS LONG, fUscored AS LONG LOCAL di AS LONG, POS AS LONG, wordFlag AS LONG, StrFlag AS LONG, dFlag AS LONG, inPar AS LONG LOCAL locX AS LONG, locY AS LONG, locPos AS LONG, uscoredLocal AS LONG, iv AS LONG, isGLOBAL AS LONG LOCAL MainStr AS STRING, sBuf AS STRING, txt AS STRING, Buf AS STRING, fsName AS STRING, strDump AS STRING '-------------------------------------------------------------------- ' load file into MainStr '-------------------------------------------------------------------- OPEN TheFile FOR BINARY AS #1 LEN = 16384 'open file IF ERR THEN 'if it failed RESET : ERRCLEAR : EXIT FUNCTION 'reset, clear error and exit END IF GET$ #1, LOF(1), MainStr 'else load contents into MainStr CLOSE #1 'close file IF LEN(MainStr) < 2 THEN EXIT FUNCTION 'if MainStr is too short, exit '-------------------------------------------------------------------- ' scan MainStr and extract lines '-------------------------------------------------------------------- p = 1: ci = 0 : I = 0 Letter = STRPTR(MainStr) 'point to beginning of MainStr FOR ci = 1 TO LEN(MainStr) SELECT CASE @Letter CASE 9 : @Letter = 32 'replace ev. tab with space CASE 13 INCR I : INCR gTotLines 'increase line- and total line counter IF ci - p > 3 THEN GOSUB ExtractLine 'if line is enough long, extract it INCR Letter : INCR ci : p = ci + 1 'jump past LF and store position END SELECT INCR Letter NEXT ci IF ci > p + 2 THEN INCR I 'increase line counter GOSUB ExtractLine 'if line didn't end with line feed.. END IF EXIT FUNCTION '--------------------------------------------------------- ' Extract line from main text '--------------------------------------------------------- ExtractLine: txt = MID$(MainStr, p, ci - p) 'extract line IF ASC(LTRIM$(txt)) = 39 THEN RETURN 'if whole line is uncommented, get next '-------------------------------------------------------------------- ' blank out text within double quotes '-------------------------------------------------------------------- QuotePos = INSTR(txt, $DQ) 'see if there is any IF QuotePos THEN DO 'loop while there is any left QuotePos2 = INSTR(QuotePos + 1, txt, $DQ) 'look for matching pair IF QuotePos2 THEN IF WhatRun = 0 AND getStrings = 1 THEN 'if to extract string literals strDump = AnsiTRIM(MID$(txt, QuotePos, QuotePos2 - QuotePos + 1)) IF LEN(strDump) THEN ARRAY SCAN exclude(), FROM 1 TO LEN(strDump), COLLATE UCASE, = strDump, TO Ac IF Ac = 0 THEN IF sStrCount MOD 20 = 0 THEN REDIM PRESERVE sString(sStrCount + 20) sString(sStrCount) = FORMAT$(fNum) + $TAB + USING$("####", I) + $TAB + strDump INCR sStrCount END IF END IF END IF MID$(txt, QuotePos, QuotePos2 - QuotePos + 1) = SPACE$(QuotePos2 - QuotePos + 1) QuotePos = INSTR(QuotePos2 + 1, txt, $DQ) IF QuotePos = 0 THEN EXIT DO ELSE EXIT DO END IF LOOP END IF txt = LTRIM$(EXTRACT$(txt, "'")) 'cut off ev. uncommented part and trim away leading spaces IF ASC(txt) = 82 AND LEFT$(txt, 4) = "REM " THEN RETURN 'if whole line in uncommented IF INSTR(UCASE$(txt), " REM ") THEN txt = LEFT$(txt, INSTR(UCASE$(txt), "REM ")) 'same here, if REM was used END IF IF INSTR(txt, " _") THEN txt = LEFT$(txt, INSTR(txt, " _") + 2) 'if line wraps to next, ignore the rest of it ELSEIF INSTR(txt, ",_ ") THEN txt = LEFT$(txt, INSTR(txt, ",_ ")) + " _" 'adjust to parser ELSEIF RIGHT$(txt, 2) = ",_" THEN txt = LEFT$(txt, LEN(txt) - 2) + " _" 'adjust to parser END IF IF ASC(txt, -1) = 32 THEN txt = RTRIM$(txt) 'trim off trailing spaces IF INSTR(txt, ":") THEN 'colon inside paranthesis must be converted inPar = 0 FOR Letter2 = STRPTR(txt) TO STRPTR(txt) + LEN(txt) SELECT CASE @Letter2 CASE 40 : INCR inPar 'left paranthesis ( CASE 41 : DECR inPar 'right paranthesis ) CASE 58 : IF inPar > 0 THEN @Letter2 = 59 'if within paranthesis, convert colon to semicolon (whatever) END SELECT NEXT END IF IF LEN(txt) > 2 THEN 'now, if line is enough long IF WhatRun = 0 THEN 'and first run GOSUB ExtractSub 'send it to sub/function check GOSUB ExtractGlobal 'send it to global variable check ELSE IF LTRIM$(UCASE$(LEFT$(txt, 8))) = "DECLARE " OR dUscored THEN dUscored = (ASC(TRIM$(txt), -1) = 95) RETURN END IF GOSUB ChkVariables 'second run, calculate globals END IF END IF RETURN '--------------------------------------------------------- ' Get subs and functions, plus get/check local variables (DIM, LOCAL, STATIC) '--------------------------------------------------------- ExtractSub: IF sFlag = 0 THEN Buf = UCASER(txt) IF LEFT$(Buf, 8) = "DECLARE " THEN 'Declaration IF INSTR(Buf, " LIB ") THEN RETURN 'external routine - DLL, etc. txt = LTRIM$(MID$(txt, 9)) Buf = UCASE$(txt) : dFlag = 1 IF LEN(RTRIM$(txt)) = 1 AND ASC(txt) = 95 THEN RETURN END IF IF LEFT$(Buf, 9) = "FUNCTION " THEN 'Function start sFlag = 2 : fsName = LTRIM$(MID$(txt, 10)) : K = I ELSEIF LEFT$(Buf, 4) = "SUB " THEN 'Sub start sFlag = 1 : fsName = LTRIM$(MID$(txt, 5)) : K = I ELSEIF LEFT$(Buf, 18) = "CALLBACK FUNCTION " THEN 'Callback Function start sFlag = 3 : fsName = LTRIM$(MID$(txt, 19)) : K = I END IF IF sFlag THEN IF INSTR(UCASE$(fsName), " EXPORT") THEN exported = 1 Ac = INSTR(fsName, ANY " ('") IF Ac THEN fsName = TRIM$(LEFT$(fsName, Ac - 1), ANY " &%@!#$?") END IF IF LEN(fsName) = 1 AND ASC(fsName) = 95 THEN fUscored = 1 IF dFlag AND fUscored = 0 THEN GOSUB AddDeclare : RETURN END IF ELSE IF fUscored THEN IF dFlag AND INSTR(Buf, " LIB ") THEN RETURN 'external routine, DLL IF fUscored = 1 THEN 'look for name ac = INSTR(LTRIM$(txt), ANY " (") IF Ac THEN fsName = TRIM$(LEFT$(txt, Ac - 1), ANY " &%@!#$?") ELSE fsName = TRIM$(txt, ANY " &%@!#$?") END IF ELSE IF INSTR(UCASE$(txt), "EXPORT") THEN exported = 1 END IF IF ASC(TRIM$(txt), -1) = 95 THEN fUscored = 2 ELSE fUscored = 0 END IF END IF IF dFlag AND fUscored = 0 THEN 'declaration GOSUB AddDeclare : RETURN END IF SELECT CASE sFlag CASE 1 IF UCASE$(LEFT$(txt, 7)) = "END SUB" THEN endRout = sFlag ELSE GOSUB ExtractLocals GOSUB ChkVariables RETURN END IF CASE 2, 3 IF UCASE$(LEFT$(txt, 12)) = "END FUNCTION" THEN endRout = sFlag ELSE GOSUB ExtractLocals GOSUB ChkVariables RETURN END IF END SELECT IF endRout THEN IF iFuncts MOD 40 = 0 THEN REDIM PRESERVE Functs(iFuncts + 40) fsName = RTRIM$(fsName) Functs(iFuncts).zName = fsName fsName=UCASE$(fsName) Functs(iFuncts).uName = fsName & CHR$(0) Functs(iFuncts).iType = endRout Functs(iFuncts).LineNum = K Functs(iFuncts).SubEnd = I Functs(iFuncts).FileNum = fNum Functs(iFuncts).Exported = exported INCR iFuncts sFlag = 0 : endRout = 0 : exported = 0 IF iVars THEN REDIM PRESERVE lVars(ilVars + iVars) FOR iv = 0 TO iVars - 1 lVars(ilVars).zName = Vars(iv).zName lVars(ilVars).uName = Vars(iv).uName lVars(ilVars).InFunct = Vars(iv).InFunct lVars(ilVars).iType = Vars(iv).iType lVars(ilVars).LineNum = Vars(iv).LineNum lVars(ilVars).FileNum = Vars(iv).FileNum lVars(ilVars).IsUsed = Vars(iv).IsUsed INCR ilVars NEXT iVars = 0 : REDIM Vars(0) END IF END IF END IF RETURN AddDeclare: IF DeclCount MOD 40 = 0 THEN REDIM PRESERVE gDecl(DeclCount + 40) fsName = RTRIM$(fsName) gDecl(DeclCount).zName = fsName fsName=UCASE$(fsName) gDecl(DeclCount).uName = fsName & CHR$(0) gDecl(DeclCount).iType = sFlag gDecl(DeclCount).LineNum = K gDecl(DeclCount).SubEnd = I gDecl(DeclCount).FileNum = fNum gDecl(DeclCount).Exported = exported INCR DeclCount sFlag = 0 : endRout = 0 : exported = 0 : dFlag = 0 RETURN '--------------------------------------------------------- ' Get Locals '--------------------------------------------------------- ExtractLocals: IF INSTR(UCASE$(txt), "LOCAL ") OR INSTR(UCASE$(txt), "DIM ") OR _ INSTR(UCASE$(txt), "STATIC ") OR uscoredLocal THEN FOR locX = 1 TO PARSECOUNT(txt, ":") sWork = TRIM$(PARSE$(txt, ":", locX)) IF UCASE$(LEFT$(sWork, 6)) = "LOCAL " OR _ UCASE$(LEFT$(sWork, 4)) = "DIM " OR _ UCASE$(LEFT$(sWork, 7)) = "STATIC " OR _ uscoredLocal THEN IF uscoredLocal = 0 THEN IF UCASE$(LEFT$(sWork, 6)) = "LOCAL " THEN isGLOBAL = 0 : sWork = MID$(sWork, 7) ELSEIF UCASE$(LEFT$(sWork, 4)) = "DIM " THEN isGLOBAL = 1 : sWork = MID$(sWork, 5) 'start out by assuming global status ELSEIF UCASE$(LEFT$(sWork, 7)) = "STATIC " THEN isGLOBAL = 0 : sWork = MID$(sWork, 8) END IF END IF FOR locY = 1 TO PARSECOUNT(sWork, ",") sBuf = TRIM$(PARSE$(sWork, ",", locY)) IF isGLOBAL = 1 THEN 'check if DIM statement really was global IF INSTR(UCASE$(sBuf), " GLOBAL") THEN 'this can only happen isGLOBAL = 2 'with "DIM xx AS GLOBAL.." ELSEIF INSTR(UCASE$(sBuf), " LOCAL") OR _ 'local DIM.. INSTR(UCASE$(sBuf), " STATIC") THEN isGLOBAL = 0 END IF END IF sBuf = EXTRACT$(sBuf, ANY " ()") 'Chop off AS LONG, etc, or if array - ( sBuf = RTRIM$(sBuf, ANY " &%@!#$?") IF LEN(sBuf) = 1 AND ASC(sBuf) = 95 THEN ITERATE sBuf = sBuf + CHR$(0) IF isGLOBAL < 2 THEN ARRAY SCAN Vars(), FROM 1 TO LEN(sBuf), COLLATE UCASE, = sBuf, TO locPos IF locPos = 0 THEN IF iVars MOD 40 = 0 THEN REDIM PRESERVE Vars(iVars + 40) Vars(iVars).zName = sBuf Vars(iVars).uName = UCASER(sBuf) Vars(iVars).InFunct = fsName Vars(iVars).FileNum = fNum Vars(iVars).iType = isGlobal Vars(iVars).LineNum = I INCR iVars END IF ELSE ARRAY SCAN gVars(), FROM 1 TO LEN(sBuf), COLLATE UCASE, = sBuf, TO POS IF POS = 0 THEN 'if not already there, add it (GLOBAL+DIM/REDIM, DIM AS GLOBAL, etc.) IF igVars MOD 40 = 0 THEN REDIM PRESERVE gVars(igVars + 40) gVars(igVars).zName = sBuf gVars(igVars).uName = UCASER(sBuf) gVars(igVars).FileNum = fNum gVars(igVars).LineNum = I INCR igVars END IF END IF NEXT END IF NEXT uscoredLocal = (RIGHT$(RTRIM$(txt), 2) = " _") END IF RETURN '--------------------------------------------------------- ' Get Globals '--------------------------------------------------------- ExtractGlobal: IF INSTR(UCASE$(txt), "GLOBAL ") OR uscoredGlobal THEN FOR x = 1 TO PARSECOUNT(txt, ":") sWork = TRIM$(PARSE$(txt, ":", x)) isGLOBAL = (UCASE$(LEFT$(sWork, 7)) = "GLOBAL ") IF isGLOBAL = 0 THEN isGLOBAL = uscoredGlobal IF UCASE$(LEFT$(sWork, 7)) = "GLOBAL " OR uscoredGlobal THEN IF uscoredGlobal = 0 THEN sWork = MID$(sWork, 8) FOR y = 1 TO PARSECOUNT(sWork, ",") sBuf = TRIM$(PARSE$(sWork, ",", y)) sBuf = EXTRACT$(sBuf, ANY " ()") 'Chop off AS LONG etc. sBuf = RTRIM$(sBuf, ANY " &%@!#$?") IF LEN(sBuf) = 1 AND ASC(sBuf) = 95 THEN ITERATE sBuf = sBuf + CHR$(0) IF igVars THEN 'must check for ev. duplicate declarations ARRAY SCAN gVars(), FROM 1 TO LEN(sBuf), COLLATE UCASE, = sBuf, TO dbl IF dbl THEN IF igDbl THEN ARRAY SCAN gDbl(), FROM 1 TO LEN(sBuf), COLLATE UCASE, = sBuf, TO dbl IF dbl THEN INCR gDbl(dbl - 1).IsUsed ITERATE FOR END IF END IF REDIM PRESERVE gDbl(igDbl) gDbl(igDbl).zName = sBuf gDbl(igDbl).uName = UCASER(sBuf) gDbl(igDbl).FileNum = fNum gDbl(igDbl).LineNum = I INCR igDbl ITERATE FOR END IF END IF IF igVars MOD 40 = 0 THEN REDIM PRESERVE gVars(igVars + 40) gVars(igVars).zName = sBuf gVars(igVars).uName = UCASER(sBuf) gVars(igVars).FileNum = fNum gVars(igVars).LineNum = I INCR igVars NEXT END IF NEXT IF isGlobal THEN uscoredGlobal = ( RIGHT$(RTRIM$(txt), 2) = " _" ) END IF RETURN '--------------------------------------------------------- ' Check variables '--------------------------------------------------------- ChkVariables: wordFlag = 0 : StrFlag = 0 Letter2 = STRPTR(txt) FOR di = 1 TO LEN(txt) SELECT CASE @Letter2 CASE 97 TO 122, 65 TO 90, 48 TO 57, 95, 192 TO 214, 216 TO 246, 248 TO 255 IF wordFlag = 0 AND @Letter2 <> 95 THEN 'if valid char and no flag, word starts here (not with underscore) wordFlag = 1 : POS = di 'set wordflag and store position END IF CASE ELSE 'we hit something else, like space, dot, etc.. IF wordFlag = 1 THEN 'if flag, then a word is ready GOSUB ChkWord 'check what we got wordFlag = 0 'and reset wordflag END IF END SELECT INCR Letter2 'next char NEXT IF wordFlag = 1 THEN GOSUB ChkWord 'in case there were letters all the way to the end.. RETURN ChkWord: POS = di - POS 'calculate length sBuf = PEEK$(Letter2 - POS, POS) + CHR$(0) 'grab word sBuf=UCASE$(sBuf) 'make it upper case for compare IF WhatRun = 0 THEN 'check local variables ARRAY SCAN Vars(), FROM 1 TO LEN(sBuf), = sBuf, TO POS IF POS THEN INCR Vars(POS - 1).IsUsed ELSE 'check Subs(Functions and Global vars ARRAY SCAN Functs(), FROM 1 TO LEN(sBuf), = sBuf, TO POS IF POS THEN INCR Functs(POS - 1).IsUsed ARRAY SCAN gVars(), FROM 1 TO LEN(sBuf), = sBuf, TO POS IF POS THEN INCR gVars(POS - 1).IsUsed END IF RETURN END FUNCTION '¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤ ' Prepare and save a report of what we've found out! '¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤ SUB DoSaveResults LOCAL hFile AS LONG, lRes AS LONG, fDbl AS LONG, cTmp AS LONG, I AS LONG, _ uline AS STRING, fName AS STRING, aStr AS STRING, aStr2 AS STRING '------------------------------------------------------------------------------ ' first look through locals array. if iType = 1, it may be a GLOBAL DIM '------------------------------------------------------------------------------ IF igVars AND ilVars THEN FOR I = ilVars - 1 TO 0 STEP -1 '<- must run this backwards through array! IF lVars(I).iType = 1 THEN aStr = lVars(I).uName + CHR$(0) ARRAY SCAN gVars(), FROM 1 TO LEN(aStr), = aStr, TO cTmp IF cTmp THEN 'if also GLOBAL, remove from local arrays ARRAY DELETE lVars(I) DECR ilVars END IF END IF NEXT END IF REDIM PRESERVE lVars(ilVars) '------------------------------------------------------------------------------ ' now prepare report.. '------------------------------------------------------------------------------ DestFile = PARSE$(FileNameStr, ANY ".", 1)+"LOG.txt" OPEN FilePathStr + DestFile FOR OUTPUT AS hFile sWork = STRING$(80,"¤") uline = STRING$(80,"-") GOSUB ReportHeader GOSUB ReportFiles GOSUB UnusedFunctions GOSUB UnusedSubs GOSUB DecButNonExistant IF NotDecl THEN GOSUB ExistingButNotDecl 'PB 9.00 allows functions without declaring Nathan Maddox END IF GOSUB UnusedGlobals GOSUB UnusedLocals GOSUB GlobalLocalMix GOSUB DupeGlobalNames GOSUB TotRefCount GOSUB SubRefCount GOSUB GlobalVariableRpt GOSUB StringLiterals '--- for debugging purposes Nathan Maddox 9/29/09 'GOSUB ConstantsReport CLOSE hFile SLEEP 20 'Launch Log file in default Viewer. ShellExecute 0, "open", FilePathStr + DestFile, BYVAL 0, BYVAL 0, %SW_SHOWNORMAL EXIT SUB ConstantsReport: '------------------------------------------------------------------------------ PRINT# hFile, "" PRINT# hFile, sWork PRINT# hFile, " CONSTANTS NAME CONSTANT VALUE " PRINT# hFile, uline FOR I = 1 TO UBOUND(EqCnst) A$=EqCnst(I).EquateName + " "+FORMAT$(EqCnst(i).EquateVal) PRINT# hFile, A$ NEXT I RETURN ReportHeader: '------------------------------------------------------------------------------ PRINT# hFile, sWork PRINT# hFile, " PBcodec report: " UCASER(FileNameStr) + " + include files. " & _ "Generated " & DATE$ & ", " & TIME$ PRINT# hFile, STR$(gTotLines) + " lines scanned in " + FORMAT$(t, "0.000") + _ " seconds (" + FORMAT$(gTotLines / t * 60, "0") + " lines/minute)" PRINT# hFile, sWork RETURN ReportFiles: '------------------------------------------------------------------------------ IF UBOUND(Files) > -1 THEN PRINT# hFile, " MAIN + INCLUDE FILES" PRINT# hFile, uline inFile(0) = "Main source file" FOR I = 0 TO UBOUND(Files) PRINT# hFile, " " & LEFT$(Files(I) & aStr & SPACE$(58), 58) & "[" +inFile(I) + "]" NEXT I END IF RETURN UnUsedFunctions: '------------------------------------------------------------------------------ PRINT# hFile, "" PRINT# hFile, sWork PRINT# hFile, " UN-USED FUNCTIONS (exported, or in incl. files, may be used by other programs)" PRINT# hFile, uline IF iFuncts THEN FOR I = 0 TO iFuncts - 1 IF Functs(I).IsUsed = 1 AND Functs(I).iType > 1 THEN SELECT CASE UCASE$(Functs(I).zName) CASE "PBMAIN", "WINMAIN", "LIBMAIN", "PBLIBMAIN", "DLLMAIN" 'ignore these CASE ELSE fName = Files(Functs(I).FileNum) aStr = " FUNCTION " : aStr2 = "" IF Functs(I).iType = 3 THEN aStr = " CALLBACK " IF Functs(I).Exported THEN aStr2 = " <EXPORT>" PRINT# hFile, LEFT$(aStr & Functs(i).zName & aStr2 & SPACE$(52), 52) & " [" & _ MID$(fName, INSTR(-1, fName, "\") + 1) & "] :" STR$(Functs(I).LineNum) END SELECT END IF NEXT I END IF RETURN UnUsedSubs: '------------------------------------------------------------------------------ PRINT# hFile, "" PRINT# hFile, sWork PRINT# hFile, " UN-USED SUBS (exported, or in incl. files, may be used by other programs)" PRINT# hFile, uline IF iFuncts THEN FOR I = 0 TO iFuncts - 1 IF Functs(I).IsUsed = 1 AND Functs(I).iType = 1 THEN fName = Files(Functs(I).FileNum) aStr2 = "" IF Functs(I).Exported THEN aStr2 = " <EXPORT>" PRINT# hFile, LEFT$(" SUB " & Functs(i).zName & aStr2 & SPACE$(50), 50) & " [" & _ MID$(fName, INSTR(-1, fName, "\") + 1) & "] :" STR$(Functs(I).LineNum) END IF NEXT I END IF RETURN DecButNonExistant: '------------------------------------------------------------------------------ IF DeclCount THEN PRINT# hFile, "" PRINT# hFile, sWork PRINT# hFile, " DECLARED, BUT NON-EXISTING SUB/FUNCTION(S)" PRINT# hFile, uline FOR I = 0 TO DeclCount - 1 IF iFuncts > 0 THEN aStr = gDecl(I).uName + CHR$(0) ARRAY SCAN Functs(), FROM 1 TO LEN(aStr), = aStr, TO fDbl END IF IF fDbl = 0 THEN fName = Files(gDecl(I).FileNum) aStr2 = "" IF gDecl(I).iType = 1 THEN aStr = " SUB " ELSEIF gDecl(I).iType = 2 THEN aStr = " FUNCTION " ELSEIF gDecl(I).iType = 3 THEN aStr = " CALLBACK " END IF IF gDecl(I).Exported THEN aStr2 = " <EXPORT>" PRINT# hFile, LEFT$(aStr & gDecl(I).zName & aStr2 & SPACE$(50), 50) & " [" & _ MID$(fName, INSTR(-1, fName, "\") + 1) & "] :" STR$(gDecl(I).LineNum) END IF NEXT I END IF RETURN ExistingButNotDecl: '------------------------------------------------------------------------------ IF iFuncts THEN PRINT# hFile, "" PRINT# hFile, sWork PRINT# hFile, " EXISTING, BUT NON-DECLARED SUB/FUNCTION(S)" PRINT# hFile, uline FOR I = 0 TO iFuncts - 1 IF DeclCount THEN aStr = Functs(I).uName + CHR$(0) ARRAY SCAN gDecl(), FROM 1 TO LEN(aStr), = aStr, TO fDbl END IF IF fDbl = 0 THEN SELECT CASE UCASE$(Functs(I).zName) CASE "PBMAIN", "WINMAIN", "LIBMAIN", "PBLIBMAIN", "DLLMAIN" 'ignore these CASE ELSE fName = Files(Functs(I).FileNum) aStr2 = "" IF Functs(I).iType = 1 THEN aStr = " SUB " ELSEIF Functs(I).iType = 2 THEN aStr = " FUNCTION " ELSEIF Functs(I).iType = 3 THEN aStr = " CALLBACK " END IF IF Functs(I).Exported THEN aStr2 = " <EXPORT>" PRINT# hFile, USING$("####", Functs(I).IsUsed - 1) & _ LEFT$(aStr & Functs(I).zName & aStr2 & SPACE$(45), 45) & " [" & _ MID$(fName, INSTR(-1, fName, "\") + 1) & "] :" STR$(Functs(I).LineNum) END SELECT END IF NEXT END IF RETURN UnusedGlobals: '------------------------------------------------------------------------------ PRINT# hFile, "" PRINT# hFile, sWork PRINT# hFile, " UN-USED GLOBAL VARIABLES" PRINT# hFile, uline IF igVars THEN FOR I = 0 TO igVars - 1 IF gVars(I).IsUsed = 1 THEN fName = Files(gVars(I).FileNum) PRINT# hFile, " " & LEFT$(gVars(i).zName & SPACE$(47), 47) & " [" & _ MID$(fName, INSTR(-1, fName, "\") + 1) & "] :" & STR$(gVars(I).LineNum) END IF NEXT I END IF RETURN UnusedLocals: '------------------------------------------------------------------------------ PRINT# hFile, "" PRINT# hFile, sWork PRINT# hFile, " UN-USED LOCAL VARIABLES" PRINT# hFile, uline IF ilVars THEN FOR I = 0 TO ilVars - 1 IF lVars(I).IsUsed = 1 THEN fName = Files(lVars(I).FileNum) PRINT# hFile, " " & LEFT$(lVars(i).zName & SPACE$(47), 47) & " [" & _ MID$(fName, INSTR(-1, fName, "\") + 1) & "] :" & STR$(lVars(I).LineNum) END IF NEXT I END IF RETURN GlobalLocalMix: '------------------------------------------------------------------------------ IF igVars AND ilVars THEN FOR I = 0 TO igVars - 1 aStr = gVars(I).uName & CHR$(0) ARRAY SCAN lVars(), FROM 1 TO LEN(aStr), = aStr, TO cTmp IF cTmp THEN EXIT FOR NEXT IF cTmp THEN PRINT# hFile, "" PRINT# hFile, sWork PRINT# hFile, " GLOBAL/LOCAL MIX - WARNING!" PRINT# hFile, " Following global variable name(s) exist in both global and local" PRINT# hFile, " form. While the compiler allows this, special care must be taken" PRINT# hFile, " to avoid hard-to-find errors. Please check them out carefully." PRINT# hFile, uline FOR I = 0 TO igVars - 1 aStr = gVars(I).uName & CHR$(0) ARRAY SCAN lVars(), FROM 1 TO LEN(aStr), = aStr, TO lRes IF lRes THEN cTmp = 0 : fDbl = 0 fName = Files(gVars(I).FileNum) PRINT# hFile, " " & LEFT$(gVars(I).zName & SPACE$(47), 47) & " [" & _ MID$(fName, INSTR(-1, fName, "\") + 1) & "] :" & STR$(gVars(I).LineNum) DO cTmp = cTmp + lRes fName = Files(lVars(cTmp - 1).FileNum) PRINT# hFile, " local in " & _ MID$(fName, INSTR(-1, fName, "\") + 1) & " :" & STR$(lVars(cTmp - 1).LineNum) ARRAY SCAN lVars(cTmp), FROM 1 TO LEN(aStr), = aStr, TO lRes LOOP WHILE lRes END IF NEXT END IF END IF RETURN DupeGlobalNames: '------------------------------------------------------------------------------ IF igDbl THEN PRINT# hFile, "" PRINT# hFile, sWork PRINT# hFile, " DUPLICATE GLOBAL NAMES - WARNING!" PRINT# hFile, " Following global name(s) exist as both array and varíable." PRINT# hFile, " While the compiler allows this, special care must be taken" PRINT# hFile, " avoid hard-to-find errors. Please check them out carefully." PRINT# hFile, uline FOR I = 0 TO igDbl - 1 fName = Files(gDbl(I).FileNum) PRINT# hFile, " " & LEFT$(gDbl(I).zName & SPACE$(47), 47) & " [" & _ MID$(fName, INSTR(-1, fName, "\") + 1) & "] :" & STR$(gDbl(I).LineNum) NEXT END IF RETURN TotRefCount: '------------------------------------------------------------------------------ 'code added by Wayne Diamond, slightly altered by Borje Hagsten PRINT# hFile, "" PRINT# hFile, sWork PRINT# hFile, " TOTAL REFERENCE COUNT - (Count, Name, [declared in File] : at Line number)" PRINT# hFile, " Lists how many times the following has been called/used (zero = un-used)" PRINT# hFile, uline '------------------------------------------------------------------------------ IF iFuncts > 0 THEN PRINT# hFile, " FUNCTIONS:" FOR I = 0 TO iFuncts - 1 IF Functs(I).iType > 1 THEN SELECT CASE UCASE$(Functs(I).zName) CASE "PBMAIN", "WINMAIN", "LIBMAIN", "PBLIBMAIN", "DLLMAIN" 'ignore these CASE ELSE fName = Files(Functs(I).FileNum) aStr = "" IF Functs(I).Exported THEN aStr = " <EXPORT>" PRINT# hFile, USING$("####", Functs(I).IsUsed - 1) & " " & _ LEFT$(Functs(I).zName & aStr & SPACE$(43), 43) & " [" & _ MID$(fName, INSTR(-1, fName, "\") + 1) & "] :" & STR$(Functs(I).LineNum) END SELECT END IF NEXT I END IF RETURN SubRefCount: '------------------------------------------------------------------------------ PRINT# hFile, "" IF iFuncts > 0 THEN PRINT# hFile, " SUBS:" FOR I = 0 TO iFuncts - 1 IF Functs(I).iType = 1 THEN fName = Files(Functs(I).FileNum) aStr = "" IF Functs(I).Exported THEN aStr = " <EXPORT>" PRINT# hFile, USING$("####", Functs(I).IsUsed - 1) & " " & _ LEFT$(Functs(I).zName & aStr & SPACE$(43), 43) & " [" & _ MID$(fName, INSTR(-1, fName, "\") + 1) & "] :" & STR$(Functs(I).LineNum) END IF NEXT I END IF RETURN GlobalVariableRpt: '------------------------------------------------------------------------------ PRINT# hFile, "" IF igVars > 0 THEN PRINT# hFile, " GLOBAL VARIABLES:" FOR I = 0 TO igVars - 1 fName = Files(gVars(I).FileNum) PRINT# hFile, USING$("####", gVars(I).IsUsed - 1) & " " & _ LEFT$(gVars(I).zName & SPACE$(43), 43) & " [" & _ MID$(fName, INSTR(-1, fName, "\") + 1) & "] :" & STR$(gVars(I).LineNum) NEXT I END IF 'end of Wayne Diamond code RETURN StringLiterals: IF sStrCount THEN PRINT# hFile, "" PRINT# hFile, sWork PRINT# hFile, " STRING LITERALS" fName = "" FOR I = 0 TO sStrCount - 1 aStr = Files(VAL(PARSE$(sString(I), $TAB, 1))) aStr = MID$(aStr, INSTR(-1, aStr, "\") + 1) IF aStr <> fName THEN fName = aStr PRINT# hFile, "" IF I THEN PRINT# hFile, uline PRINT# hFile, " Line Text [" + fName + "]" PRINT# hFile, uline END IF PRINT# hFile, PARSE$(sString(I), $TAB, 2) + " " + _ PARSE$(sString(I), $TAB, 3) NEXT END IF '------------------------------------------------------------------------------ RETURN END SUB '************************************************************************ ' GetCommandFile - loads a received Path&File name into global array '************************************************************************ FUNCTION GetCommandFile(BYVAL CmdStr AS STRING, Fi() AS STRING) AS LONG LOCAL tmpName AS STRING, pStr AS STRING CmdStr = TRIM$(CmdStr) 'trim away ev. leading/ending spaces IF LEFT$(CmdStr, 1) = CHR$(34) THEN 'if in double-quotes CmdStr = MID$(CmdStr, 2) 'remove first quote pStr = CHR$(34) 'and use DQ as delimiter for PARSE$ ELSE pStr = " " 'else use space as delimiter END IF tmpName = TRIM$(PARSE$(CmdStr, pStr, 1)) IF LEN(tmpName) = 0 THEN EXIT FUNCTION IF (GETATTR(tmpName) AND 16) = 0 THEN 'make sure it isn't a folder Fi(0) = tmpName ELSE EXIT FUNCTION END IF FUNCTION = 1 'return number of collected files END FUNCTION '************************************************************************ ' GetDroppedFile - Function Loads File/Folder names into the global arrays '************************************************************************ FUNCTION GetDroppedFile( BYVAL hfInfo AS LONG, Fi() AS STRING) AS LONG LOCAL COUNT AS LONG, ln AS LONG, tmp AS STRING, fName AS ASCIIZ * %MAX_PATH COUNT = DragQueryFile(hfInfo, &HFFFFFFFF&, BYVAL %NULL, 0) 'get number of dropped files IF COUNT THEN 'If we got something ln = DragQueryFile(hfInfo, 0, fName, %MAX_PATH) 'put FileName into fString And get len IF ln THEN tmp = TRIM$(LEFT$(fName, ln)) IF LEN(tmp) AND (GETATTR(tmp) AND 16) = 0 THEN 'make sure it's a file, not a folder Fi(0) = tmp FUNCTION = 1 END IF END IF END IF CALL DragFinish(hfInfo) END FUNCTION '************************************************************************ ' Get PB/DLL 6 compiler's include dir (winapi folder) '************************************************************************ FUNCTION GetIncludeDir AS STRING LOCAL lRet AS LONG, hKey AS LONG LOCAL Buffer AS ASCIIZ * %MAX_PATH, SubKey AS STRING Buffer = "Software\PowerBASIC\PB/Win\7.00" SubKey = "Filename" IF RegOpenKeyEx(%HKEY_LOCAL_MACHINE, Buffer, 0, _ %KEY_QUERY_VALUE, hKey) = %ERROR_SUCCESS THEN lRet = RegQueryValueEx(hKey, BYVAL STRPTR(SubKey), _ BYVAL 0&, BYVAL 0&, Buffer, SIZEOF(Buffer)) IF LEN(Buffer) THEN FUNCTION = TRIM$(Buffer) IF hKey THEN RegCloseKey hKey IF LEN(TRIM$(Buffer)) THEN Buffer = TRIM$(Buffer) Buffer = LEFT$(Buffer, INSTR(-1, Buffer, ANY "\/")) ' Compiler path SubKey = LEFT$(Buffer, INSTR(-1, Buffer, "\Bin\")) + "WinAPI" ' WinAPI path Buffer = IniGetString("Compiler", "Include0", SubKey, Buffer + "PBWin.ini") IF LEN(TRIM$(Buffer)) THEN Buffer = TRIM$(Buffer) IF RIGHT$(Buffer, 1) <> "\" THEN IF RIGHT$(Buffer, 1) <> "/" THEN Buffer = Buffer + "\" END IF FUNCTION = TRIM$(Buffer) EXIT FUNCTION END IF END IF END IF Buffer = "Software\PowerBasic\PB/WIN\9.00\Compiler" SubKey = "Include" IF RegOpenKeyEx(%HKEY_CURRENT_USER, Buffer, 0, _ %KEY_QUERY_VALUE, hKey) = %ERROR_SUCCESS THEN lRet = RegQueryValueEx(hKey, BYVAL STRPTR(SubKey), _ BYVAL 0&, BYVAL 0&, Buffer, SIZEOF(Buffer)) IF LEN(Buffer) THEN FUNCTION = TRIM$(Buffer) ' MSGBOX Buffer FUNCTION = Buffer IF hKey THEN RegCloseKey hKey ELSE Buffer = "Software\PowerBasic\PB/WIN\9.00\Compiler" IF RegOpenKeyEx(%HKEY_CURRENT_USER, Buffer, 0, _ %KEY_QUERY_VALUE, hKey) = %ERROR_SUCCESS THEN lRet = RegQueryValueEx(hKey, BYVAL STRPTR(SubKey), _ BYVAL 0&, BYVAL 0&, Buffer, SIZEOF(Buffer)) IF LEN(Buffer) THEN FUNCTION = TRIM$(Buffer) IF hKey THEN RegCloseKey hKey END IF END IF END FUNCTION '¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤ ' Get string from ini file '¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤ FUNCTION IniGetString(BYVAL sSection AS STRING, BYVAL sKey AS STRING, _ BYVAL sDefault AS STRING, BYVAL sFile AS STRING) AS STRING LOCAL RetVal AS LONG, zResult AS ASCIIZ * %MAX_PATH RetVal = GetPrivateProfileString(BYVAL STRPTR(sSection), _ BYVAL STRPTR(sKey), _ BYVAL STRPTR(sDefault), _ zResult, SIZEOF(zResult), BYVAL STRPTR(sFile)) IF RetVal THEN FUNCTION = TRIM$(LEFT$(zResult, RetVal)) END FUNCTION '¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤ ' Check to see if the file has a #COMPILE metastatement '¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤ FUNCTION IsFileMain(BYVAL fName AS STRING) AS LONG LOCAL hFile AS LONG, txt AS STRING hFile = FREEFILE 'get a free file handle OPEN fName FOR INPUT AS hFile LEN = 16383 'open file IF ERR THEN 'if it failed RESET : ERRCLEAR 'reset, clear error FUNCTION = -2 : EXIT FUNCTION 'return -2 to indicate failure and exit END IF IF LOF(hFile) = 0 THEN 'if zero length file CLOSE hFile 'close it FUNCTION = -3 : EXIT FUNCTION 'return -3 to indicate empty file and exit END IF DO WHILE EOF(hFile) = 0 'loop through file LINE INPUT# hFile, txt 'line by line txt=TRIM$(Txt) 'NNM 9/22/09 txt=REMOVE$(Txt, ANY $TAB) 'NNM 9/22/09 IF LEN(txt) > 8 THEN 'if enough long txt = UCASE$(LTRIM$(txt)) 'adjust txt for compare IF (ASC(txt) = 35 OR ASC(txt) = 36) AND MID$(txt, 2, 8) = "COMPILE " THEN FUNCTION = -1 EXIT DO END IF IF LEFT$(txt, 9) = "FUNCTION " OR _ 'jump out once we hit a Sub or Function LEFT$(txt, 4) = "SUB " OR _ LEFT$(txt, 9) = "CALLBACK " OR _ LEFT$(txt, 7) = "STATIC " THEN FUNCTION = LOF(hFile) 'return length EXIT DO END IF END IF LOOP CLOSE hFile END FUNCTION '¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤ ' UCASER function, returns UCASE string without altering original '¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤ FUNCTION UCASER(BYVAL st AS STRING) AS STRING #REGISTER NONE LOCAL p AS STRING PTR p = STRPTR(st) ! mov eax, p ; move pointer to string into eax ! mov ecx, [eax-4] ; move length of string into ecx (counter) ! cmp ecx, 0 ; if length is 0, no string length ! je exitUCASER ; then exit beginUCASER: ! mov dl, [eax] ; move current char into dl ! cmp dl, 97 ; compare against value 97 (a) ! jb nextUCASER ; if dl < 97 then get next character ! cmp dl, 123 ; compare against value 123 ! jb makeUCASER ; if dl < 123 it is in 97-122 range, make Uppercase and get next ! cmp dl, 224 ; compare against value 224 (à) - extended ANSI ! jb nextUCASER ; if dl < 224 it is in 123-224 range, do nothing to it ! cmp dl, 247 ; compare against value 247 ! jb makeUCASER ; if dl < 247 it is in 224-247 range, make Uppercase and get next ! je nextUCASER ; if dl = 247, do nothing ! cmp dl, 255 ; compare against value 255 ! jb makeUCASER ; if dl < 255 it is in 248-255 range, make Uppercase and get next ! jmp nextUCASER ; else, on to next character makeUCASER: ! sub dl, 32 ; make lowercase by adding 32 to dl's value ! mov [eax], dl ; write changed char back into eax and fall through to nextUCASER nextUCASER: ! inc eax ; get next character ! dec ecx ; decrease ecx (length) counter ! jnz beginUCASER ; iterate if not zero (end of string) FUNCTION = st exitUCASER: END FUNCTION
Code:
' Main source code file: C:\PB\PBWin70\MyStuff\Utilities\PBcodec2\pbcodec.bas ' Resulting include file: C:\PB\PBWin70\MyStuff\Utilities\PBcodec2\pbcodec.inc ' ' Created by inClean v1.26, 08-11-2003, 01:09:26 ' Press Help-button for some useful information and tips. ' ' 25205 lines of include file data read and compared against ' 1494 lines of code in 7.97 seconds. ' '----------------------------------------------------------------- ' Equates: 38 '----------------------------------------------------------------- %WINAPI = 1 %TRUE = 1 %NULL = 0 %ERROR_SUCCESS = 0& %INVALID_HANDLE_VALUE = &HFFFFFFFF??? %KEY_QUERY_VALUE = &H1 %MAX_PATH = 260 ' max. length of full pathname %SW_SHOWNORMAL = 1 %WM_DESTROY = &H2 %WM_NOTIFY = &H4E %WM_INITDIALOG = &H110 %WM_COMMAND = &H111 %WM_TIMER = &H113 %WM_CTLCOLORSTATIC = &H138 %WM_DROPFILES = &H233 %WS_CAPTION = &H00C00000 ' WS_BORDER OR WS_DLGFRAME %WS_SYSMENU = &H00080000 %WS_MINIMIZEBOX = &H00020000 %WS_EX_CLIENTEDGE = &H00000200 %SWP_NOSIZE = &H1 %SWP_NOMOVE = &H2 %SWP_NOZORDER = &H4 %HWND_TOPMOST = &HFFFFFFFF??? %COLOR_INFOBK = 24 %IDOK = 1 %IDCANCEL = 2 %SS_CENTER = &H00000001 %SPI_GETWORKAREA = 48 %cmb1 = &H470 %HKEY_CURRENT_USER = &H80000001 %HKEY_LOCAL_MACHINE = &H80000002 %VER_PLATFORM_WIN32_NT = 2 %OFN_HIDEREADONLY = &H00000004 %OFN_FILEMUSTEXIST = &H00001000 %OFN_EXPLORER = &H00080000 ' new look commdlg %CDN_FIRST = 0-601 ' common dialog new %CDN_INITDONE = %CDN_FIRST - &H0000 %OFN_FILEBUFFERSIZE = 8192 %IDC_CheckBox1 = 130 %IDC_CheckBox2 = 131 '----------------------------------------------------------------- ' TYPE and UNION structures: 8 '----------------------------------------------------------------- TYPE RECT nLeft AS LONG nTop AS LONG nRight AS LONG nBottom AS LONG END TYPE TYPE FILETIME dwLowDateTime AS DWORD dwHighDateTime AS DWORD END TYPE TYPE WIN32_FIND_DATA dwFileAttributes AS DWORD ftCreationTime AS FILETIME ftLastAccessTime AS FILETIME ftLastWriteTime AS FILETIME nFileSizeHigh AS DWORD nFileSizeLow AS DWORD dwReserved0 AS DWORD dwReserved1 AS DWORD cFileName AS ASCIIZ * %MAX_PATH cAlternateFileName AS ASCIIZ * 14 END TYPE TYPE OSVERSIONINFO dwOSVersionInfoSize AS DWORD dwMajorVersion AS DWORD dwMinorVersion AS DWORD dwBuildNumber AS DWORD dwPlatformId AS DWORD szCSDVersion AS ASCIIZ * 128 'Maintenance string for PSS usage END TYPE TYPE NMHDR hwndFrom AS DWORD idfrom AS DWORD CODE AS LONG ' used for messages, so needs to be LONG, not DWORD... END TYPE TYPE OPENFILENAME lStructSize AS DWORD hWndOwner AS LONG hInstance AS LONG lpstrFilter AS ASCIIZ PTR lpstrCustomFilter AS ASCIIZ PTR nMaxCustFilter AS DWORD nFilterIndex AS DWORD lpstrFile AS ASCIIZ PTR nMaxFile AS DWORD lpstrFileTitle AS ASCIIZ PTR nMaxFileTitle AS DWORD lpstrInitialDir AS ASCIIZ PTR lpstrTitle AS ASCIIZ PTR Flags AS DWORD nFileOffset AS WORD nFileExtension AS WORD lpstrDefExt AS ASCIIZ PTR lCustData AS LONG lpfnHook AS DWORD lpTemplateName AS ASCIIZ PTR END TYPE TYPE OPENFILENAMEEX lStructSize AS DWORD hWndOwner AS DWORD hInstance AS DWORD lpstrFilter AS ASCIIZ PTR lpstrCustomFilter AS ASCIIZ PTR nMaxCustFilter AS DWORD nFilterIndex AS DWORD lpstrFile AS ASCIIZ PTR nMaxFile AS DWORD lpstrFileTitle AS ASCIIZ PTR nMaxFileTitle AS DWORD lpstrInitialDir AS ASCIIZ PTR lpstrTitle AS ASCIIZ PTR Flags AS DWORD nFileOffset AS WORD nFileExtension AS WORD lpstrDefExt AS ASCIIZ PTR lCustData AS LONG lpfnHook AS DWORD lpTemplateName AS ASCIIZ PTR '--- new Windows 2000 structure members --- pvReserved AS DWORD dwReserved AS DWORD FlagsEx AS DWORD END TYPE TYPE TAGOFNOTIFY hdr AS NMHDR lpOFN AS OPENFILENAME pszFile AS ASCIIZ PTR END TYPE '----------------------------------------------------------------- ' Declared Functions: 23 '----------------------------------------------------------------- DECLARE FUNCTION DragQueryFile LIB "SHELL32.DLL" ALIAS "DragQueryFileA" (BYVAL hDrop AS DWORD, BYVAL uiFile AS DWORD, lpStr AS ASCIIZ, BYVAL cch AS DWORD) AS DWORD DECLARE FUNCTION FindClose LIB "KERNEL32.DLL" ALIAS "FindClose" (BYVAL hFindFile AS DWORD) AS LONG DECLARE FUNCTION FindFirstFile LIB "KERNEL32.DLL" ALIAS "FindFirstFileA" (lpFileName AS ASCIIZ, lpFindFileData AS WIN32_FIND_DATA) AS DWORD DECLARE FUNCTION GetClientRect LIB "USER32.DLL" ALIAS "GetClientRect" (BYVAL hwnd AS DWORD, lpRect AS RECT) AS LONG DECLARE FUNCTION GetDlgItem LIB "USER32.DLL" ALIAS "GetDlgItem" (BYVAL hDlg AS DWORD, BYVAL nIDDlgItem AS LONG) AS DWORD DECLARE FUNCTION GetOpenFileName LIB "COMDLG32.DLL" ALIAS "GetOpenFileNameA" _ (lpofn AS OPENFILENAME) AS LONG DECLARE FUNCTION GetParent LIB "USER32.DLL" ALIAS "GetParent" (BYVAL hWnd AS DWORD) AS LONG DECLARE FUNCTION GetPrivateProfileString LIB "KERNEL32.DLL" ALIAS "GetPrivateProfileStringA" (lpApplicationName AS ASCIIZ, lpKeyName AS ASCIIZ, lpDefault AS ASCIIZ, lpReturnedString AS ASCIIZ, BYVAL nSize AS DWORD, lpFileName AS ASCIIZ) AS DWORD DECLARE FUNCTION GetSysColor LIB "USER32.DLL" ALIAS "GetSysColor" (BYVAL nIndex AS LONG) AS LONG DECLARE FUNCTION GetSysColorBrush LIB "USER32.DLL" ALIAS "GetSysColorBrush" (BYVAL nIndex AS LONG) AS LONG DECLARE FUNCTION GetVersionEx LIB "KERNEL32.DLL" ALIAS "GetVersionExA" (lpVersionInformation AS OSVERSIONINFO) AS LONG DECLARE FUNCTION GetWindowRect LIB "USER32.DLL" ALIAS "GetWindowRect" (BYVAL hWnd AS DWORD, lpRect AS RECT) AS LONG DECLARE FUNCTION IsCharAlphaNumeric LIB "USER32.DLL" ALIAS "IsCharAlphaNumericA" (BYVAL cChar AS BYTE) AS LONG DECLARE FUNCTION KillTimer LIB "USER32.DLL" ALIAS "KillTimer" (BYVAL hWnd AS DWORD, BYVAL nIDEvent AS LONG) AS LONG DECLARE FUNCTION MessageBeep LIB "USER32.DLL" ALIAS "MessageBeep" (BYVAL dwType AS DWORD) AS LONG DECLARE FUNCTION RegCloseKey LIB "ADVAPI32.DLL" ALIAS "RegCloseKey" (BYVAL hKey AS DWORD) AS LONG DECLARE FUNCTION RegOpenKeyEx LIB "ADVAPI32.DLL" ALIAS "RegOpenKeyExA" (BYVAL hKey AS DWORD, lpSubKey AS ASCIIZ, BYVAL ulOptions AS DWORD, BYVAL samDesired AS LONG, phkResult AS DWORD) AS LONG DECLARE FUNCTION RegQueryValueEx LIB "ADVAPI32.DLL" ALIAS "RegQueryValueExA" (BYVAL hKey AS DWORD, lpValueName AS ASCIIZ, BYVAL lpReserved AS LONG, lpType AS LONG, lpData AS ANY, lpcbData AS LONG) AS LONG DECLARE FUNCTION SetBkColor LIB "GDI32.DLL" ALIAS "SetBkColor" (BYVAL hdc AS DWORD, BYVAL crColor AS DWORD) AS DWORD DECLARE FUNCTION SetTimer LIB "USER32.DLL" ALIAS "SetTimer" (BYVAL hWnd AS DWORD, BYVAL nIDEvent AS LONG, BYVAL uElapse AS DWORD, BYVAL lpTimerFunc AS LONG) AS LONG DECLARE FUNCTION SetWindowPos LIB "USER32.DLL" ALIAS "SetWindowPos" (BYVAL hWnd AS DWORD, BYVAL hWndInsertAfter AS DWORD, BYVAL x AS LONG, BYVAL y AS LONG, BYVAL cx AS LONG, BYVAL cy AS LONG, BYVAL wFlags AS DWORD) AS LONG DECLARE FUNCTION ShellExecute LIB "SHELL32.DLL" ALIAS "ShellExecuteA" (BYVAL hwnd AS DWORD, lpOperation AS ASCIIZ, lpFile AS ASCIIZ, lpParameters AS ASCIIZ, lpDirectory AS ASCIIZ, BYVAL nShowCmd AS LONG) AS DWORD DECLARE FUNCTION SystemParametersInfo LIB "USER32.DLL" ALIAS "SystemParametersInfoA" (BYVAL uAction AS DWORD, BYVAL uParam AS DWORD, lpvParam AS ANY, BYVAL fuWinIni AS DWORD) AS LONG '----------------------------------------------------------------- ' Declared Subs: 2 '----------------------------------------------------------------- DECLARE SUB DragAcceptFiles LIB "SHELL32.DLL" ALIAS "DragAcceptFiles" (BYVAL hwnd AS DWORD, BYVAL fAccept AS LONG) DECLARE SUB DragFinish LIB "SHELL32.DLL" ALIAS "DragFinish" (BYVAL hDrop AS DWORD) '----------------------------------------------------------------- ' Functions: 3 (begins with declarations) '----------------------------------------------------------------- DECLARE FUNCTION IsWin2000orXP AS LONG DECLARE FUNCTION OpenCommDlg_Proc( BYVAL hWnd AS DWORD, BYVAL wMsg AS DWORD, _ BYVAL wParam AS DWORD, BYVAL lParam AS LONG ) AS LONG DECLARE FUNCTION OpenFileDialog (BYVAL hWnd AS DWORD, _ ' parent window BYVAL sCaption AS STRING, _ ' caption sFileSpec AS STRING, _ ' filename BYVAL sInitialDir AS STRING, _ ' start directory BYVAL sFilter AS STRING, _ ' filename filter BYVAL sDefExtension AS STRING, _ ' default extension dFlags AS DWORD) AS LONG ' flags '- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - FUNCTION IsWin2000orXP AS LONG LOCAL os AS OSVERSIONINFO os.dwOSVersionInfoSize = SIZEOF(os) IF GetVersionEx(os) THEN FUNCTION = ((os.dwPlatformId = %VER_PLATFORM_WIN32_NT) AND _ (os.dwMajorVersion > 4)) '5 or higher.. END IF END FUNCTION FUNCTION OpenCommDlg_Proc( BYVAL hWnd AS DWORD, BYVAL wMsg AS DWORD, _ BYVAL wParam AS DWORD, BYVAL lParam AS LONG ) EXPORT AS LONG LOCAL X AS LONG, Y AS LONG, R AS RECT, hftCombo AS DWORD, tNOTIFY AS TAGOFNOTIFY PTR SELECT CASE wMsg CASE %WM_NOTIFY tNOTIFY = lParam SELECT CASE @tNOTIFY.hdr.Code CASE %CDN_INITDONE 'CENTER DIALOG IN PARENT GetWindowRect GetParent(GetParent(hWnd)), R 'get parent's data - dialog is child of child.. X = R.nLeft + ((R.nRight - R.nLeft) \ 2) 'calculate parent's width Y = R.nTop + ((R.nBottom - R.nTop) \ 2) 'calculate parent's height GetWindowRect GetParent(hWnd), R 'get dialog's width and height X = X - (( R.nRight - R.nLeft ) \ 2) Y = Y - (( R.nBottom - R.nTop ) \ 2) SetWindowPos GetParent(hWnd), %NULL, X, Y, 0, 0, %SWP_NOSIZE OR %SWP_NOZORDER 'set centered pos 'INCREASE HEIGHT OF DROPPED LIST IN FILETYPE COMBO hftCombo = GetDlgItem(GetParent(hWnd), %cmb1) 'handle, Filetype combo IF hftCombo THEN 'if we get handle GetClientRect hftCombo, R 'get combo's width and set new height SetWindowPos hftCombo, %NULL, 0, 0, R.nRight, 200, %SWP_NOMOVE OR %SWP_NOZORDER END IF FUNCTION = %TRUE : EXIT FUNCTION 'CASE %CDN_HELP : BEEP END SELECT END SELECT END FUNCTION FUNCTION OpenFileDialog (BYVAL hWnd AS DWORD, _ ' parent window BYVAL sCaption AS STRING, _ ' caption sFileSpec AS STRING, _ ' filename BYVAL sInitialDir AS STRING, _ ' start directory BYVAL sFilter AS STRING, _ ' filename filter BYVAL sDefExtension AS STRING, _ ' default extension dFlags AS DWORD) AS LONG ' flags LOCAL ix AS LONG LOCAL Ofn AS OPENFILENAMEEX LOCAL szFileTitle AS ASCIIZ * %MAX_PATH REPLACE "|" WITH $NUL IN sFilter sFilter = sFilter + $NUL IF LEN(sInitialDir) = 0 THEN sInitialDir = CURDIR$ ix = INSTR(sFileSpec, $NUL) IF ix THEN sFileSpec = LEFT$(sFileSpec, ix) + SPACE$( MAX&(0, %OFN_FILEBUFFERSIZE - ix) ) ELSE sFileSpec = sFileSpec + $NUL + SPACE$( MAX&(0, %OFN_FILEBUFFERSIZE - (LEN(sFileSpec) + 1)) ) END IF IF IsWin2000orXP THEN ofn.lStructSize = LEN(OPENFILENAMEEX) ' if Win2K or later, use full size of new structure ELSE ofn.lStructSize = LEN(OPENFILENAME) ' else set size to old, smaller one's (76 bytes) END IF ofn.hWndOwner = hWnd ofn.lpstrFilter = STRPTR(sFilter) ofn.lpstrFile = STRPTR(sFileSpec) ofn.nMaxFile = LEN(sFileSpec) ofn.lpstrFileTitle = VARPTR(szFileTitle) ofn.nMaxFileTitle = SIZEOF(szFileTitle) ofn.lpstrInitialDir = STRPTR(sInitialDir) IF LEN(sCaption) THEN ofn.lpstrTitle = STRPTR(sCaption) END IF ofn.Flags = dFlags ofn.lpfnHook = CODEPTR(OpenCommDlg_Proc) IF LEN(sDefExtension) THEN ofn.lpstrDefExt = STRPTR(sDefExtension) END IF ofn.nFilterIndex = 1 ' nFilterIndex decides File type combo's ListItem 'Note: following Select Case table must be adjusted to match used Filter string ' (also remeber to do the same in OpenDlgHookProc procedure..) FUNCTION = GetOpenFilename(BYVAL VARPTR(ofn)) ix = INSTR(-1, sFileSpec, $NUL) IF ix THEN sFileSpec = LEFT$(sFileSpec, ix - 1) ELSE sFileSpec = "" END IF dFlags = ofn.Flags END FUNCTION
Comment