-
Oct 31st, 2022, 02:06 PM
#1
Redirect where Debug.Print goes.
It'd be nice if I could figure out how to redirect where Debug.Print goes.
I've got a little persistent DebugPrint program I often use. It's easy to use, as I just remove the dot from my Debug.Print statements. However, it'd be even more cool if I could just redirect everything.
At first, I created an auto-instantiating class named "Debug". That worked just fine.
However, there are still two problems:
1) This class still doesn't override the internal Debug object.
2) "Print" is a reserved word and can't be used as a procedure name.
So drat. Any ideas?
Last edited by Elroy; Oct 31st, 2022 at 02:16 PM.
Any software I post in these forums written by me is provided “AS IS” without warranty of any kind, expressed or implied, and permission is hereby granted, free of charge and without restriction, to any person obtaining a copy. Please understand that I’ve been programming since the mid-1970s and still have some of that code. My contemporary VB6 project is approaching 1,000 modules. In addition, I have a “VB6 random code folder” that is overflowing. I’ve been at this long enough to truly not know with absolute certainty from whence every single line of my code has come, with much of it coming from programmers under my employ who signed intellectual property transfers. I have not deliberately attempted to remove any licenses and/or attributions from any software. If someone finds that I have inadvertently done so, I sincerely apologize, and, upon notice and reasonable proof, will re-attach those licenses and/or attributions. To all, peace and happiness.
-
Oct 31st, 2022, 03:56 PM
#2
Re: Redirect where Debug.Print goes.
I was actually just looking at it this weekend. I still want a debug.clear (I use the persistent debug window as well thank you
I was look at vb5 because I could get the debug symbols for vba5.dll to load, it should be very similar in vb6
the pcode for debug.print triggers opcode FF11 _lblEX_Debug2
Code:
0FBD898C > A1 D49EBE0F MOV EAX,DWORD PTR DS:[FBE9ED4] -> 001516D4 0FA66720 VBA5.DWIN::`vftable'
0FBD8991 50 PUSH EAX
0FBD8992 33C0 XOR EAX,EAX
0FBD8994 8A06 MOV AL,BYTE PTR DS:[ESI]
0FBD8996 46 INC ESI
0FBD8997 FF2485 909BBD0F JMP DWORD PTR DS:[EAX*4+FBD9B90]
vtable
$ ==> >0FB562F5 VBA5.DWIN::QueryInterface
$+4 >0FB54BC5 VBA5.DWIN::AddRef
$+8 >0FB54BCD VBA5.DWIN::Release
$+C >0FB56173 VBA5.DWIN::PrintText
$+10 >0FB5622E VBA5.DWIN::SetColumn
$+14 >0FB562DE VBA5.DWIN::GetColumn
$+18 >0FB5654E VBA5.RECORD::LinesInserted
$+1C >0FB56572 VBA5.RECORD::LinesDeleted
$+20 >0FB54BC1 VBA5.RECORD::LinesChanged
$+24 >0FB54BC4 VBA5.RECORD::TxtmgrChange
$+28 >0FB54BA6 VBA5.LNBUFZ::`scalar deleting destructor'
$+2C >0FB40A34 VBA5.LNBUF::EnsureSize
$+30 >0FB409B7 VBA5.LNBUF::Clear
$+34 >0FB4098B VBA5.LNBUF::Free
$+38 >0FB40E71 VBA5.LNBUFZ::GetXszDelim
$+3C >0FB40AB8 VBA5.LNBUF::ReallocBuffer
$+40 >0FB40F7E VBA5.LNBUFZ::IsEqual
$+44 >00000000
After the debug object is loaded it goes on to to VBA5.DWIN::QueryInterface VBA5.IID_IVbaPrint
then calls __vbaPrintObj which eventually leads to
.text:0FB56173 ; int __stdcall DWIN::PrintText(DWIN *__hidden this, LPCWCH lpWideCharStr)
I havent traced it further yet but my first stab would be to hook that
symbols for 5/6: http://sandsprite.com/vb-reversing/vb_symbols.zip
Btw if anyone has working symbols for vba6.dll I’d love a copy. (Or if you can find a way to load those in the zip)
Last edited by dz32; Oct 31st, 2022 at 04:56 PM.
-
Nov 1st, 2022, 04:04 AM
#3
Re: Redirect where Debug.Print goes.
 Originally Posted by dz32
I was look at vb5 because I could get the debug symbols for vba5.dll to load
That's clever! Do you a PDB or a DBG for the debug symbols of VBA5.DLL?
Edit: Oops, you linked it already. I'll snatch it before admin take it down :-))
cheers,
</wqw>
-
Nov 1st, 2022, 06:22 AM
#4
Re: Redirect where Debug.Print goes.
I got super lucky finding those files lol. I think I first stumbled across the ms knowledge base articles
Q188588: VB5SP3DS Contains Visual Basic SP3 Debugging Symbols
Q176547: Vb5sp2ds Contains Visual Basic SP2 Debugging
Then I had to try to find the actual downloads from the 90s. Eventually an ancient mirror of the ms ftp server from that era was found.
To open the .dbg debug symbols in IDA you must use the MSDIA parser I use a batch file:
[path]\ida.exe -Opdb:msdia %1
Olly seems happy with most of them. in at least one case, only my 2004 copy of IDA 4.8 would properly parse the dbg file so I included that idb as well
I still haven’t found anything that can handle the vba6.dbg symbols maybe I will have to try to find a tool to parse/export the data
Ms used to be generous with thier symbols. A bunch more info available in the zips parent directory page.
One other note vba print obj had a call to deserialize in it. It looks like debug.print might be able to do more fancy stuff than I imagined like deserialize some complex types like if you pass it a class object? Might have to implement an extra interface though. Or how get/put handle udts? Dunno need to examine it more could be nothing 🤷
Last edited by dz32; Nov 1st, 2022 at 06:39 AM.
-
Nov 1st, 2022, 11:26 AM
#5
Re: Redirect where Debug.Print goes.
dz32 thank you so much for vba5.dbg!
Regarding to question you could create a global object and implement IVBAPrint interface then you can use Print method. The other way is redirecting just by placing your implementation of IVBAPrint to _lblEX_Debug2 opcode handler. It's quite straightforward.
Last edited by The trick; Nov 1st, 2022 at 11:30 AM.
-
Nov 1st, 2022, 02:24 PM
#6
New Member
Re: Redirect where Debug.Print goes.
 Originally Posted by dz32
I was look at vb5 because I could get the debug symbols for vba5.dll to load, it should be very similar in vb6
Hello.
The Trick has just told me that he managed to get Debug Symbols for VBAx.DLL (aka EB part in EB/Ruby terminology). Our further conversation led me to this topic and your discovery.
This is cruical exploration in context of VB reverse-engineering, I must say.
As you know, I have spent some years trying to reverse-engineer VB6 as a whole product. Diving into msvbvm guts was relatively easy work, while digging into VBAx.DLL was really challenging, since you need to guess purpose of every function, every variable, and there is no hint except of your own interpretation of what's going to happen at this particular code.
So, I was wondered to match my own guessed function/variable names with "official" ones to check how accurate was my assumptions regarding nature of things that functions do and tasks they are supposed to solve.
It's now less than a hour passed since I opened your DBG file, but I've already matched dozens of entities with my own reverse-engineering results. I think the next few days or weeks will be very exciting.
So, as I mentioned before, I discovered/reverse-engineered/described like 2000 or more functions/classes/variables from VBA6.DLL.
For obvious reasons they were given temporary names (guessed names) which are different to authentic ones (which are now available from VBA5.DBG). However, for many of these functions I have very descriptive articles describing each argument, the behaviour of function and C languange pseudo-code illustrating how original source code might look like.
I will be definitely usefull if all information I collected during these year can be merged information that can be extracted from this DBG.
Probably I should make public portal and open all my reverse-engineering documentations, so that you can take function/method from this DBG and read what does it do and what arguments does it take from my articles?
One major problem is that names within my work do not match official or authentic Microsoft names (available in DBG). They need to be matched manually, at least until I/we make a tool that can match names by analyzing/traversing CFG/EFG (code flow graph/execution flow graph) of two binaries (VBA6.DLL and VBA6.DLL).
Here's some observations I've already made (even though I got VBA5.DBG less than a hour ago):
1. Official names of functions and variables seem to be more brief than names assigned by me. However, they are less obvious and often confusing.
2. They didn't follow one consistent naming scheme. Some functions do have prefixes indicating their relation to a particular component of EB engine, and some don't. Some classes are named using CCamelCaseClass scheme, some are use UPPERCASE names with lots of abbriations.
3. For instance, there is class which I called CSmallHeap. It turned out that it was originally called BLKMGR32 (bulk memory allocations manager).
4. There is a lack of consistency in how they call a single thing or conception in different places.
Let me make small introduction into how VB IDE represents BASIC code under the hood. VB IDE is an example of very clever technique where parsing/analyzing and compilation of source code starts at the moment of inserting it into IDE window. VB IDE does not store source code as big plain text, nor it stores it as an array of lines or rows. When you finishing editing a line of code by pressing Enter of moving caret to another line using mouse or keyboard arrows, this line is parsed, analyzed and converted to more compact binary format of representation. Code isn't represented as text, lines of text or parts of lines of text internally. Additional internal structures and entries are created exactly when you type a new line with declaration of new Sub or variable. In other words, at any given moment of time VB IDE already knows all its subs, functions and other entities defined in code, contrary to traditional compilers which start to parse/analyze code only when compilation/run pass is invoked.
I use the following terminology.
1. Line as a text. The line of VBcode exist in form of pure text only during line editing process. As soon as you finish line by pressing Enter or moving caret, a line will undergo few transformations. The first one is parsing and building PCR tree from sequence of characters.
2. PCR tree. PCR stands for Parsed Code Representation. PCR tree consists of nodes, a node may represent a whole statement and its subnodes may represent some details of statements, literals, name references and so on. For every syntactically correct line of VB code PCR tree can be built and is actually built during parsing process. Syntax error encountered during parsing abort process of PCR tree construction and leave PCR tree unfinished. In any case, PCR tree is short-living form of VB-code source line representation.
3. No matter whether line was successfully parsed or there was an error (Syntax error), yet another form of representation is used for long-term storage of VB code lines. I called this BSCR. BSCR stands for Binary Source Code Representation. Before I discovered BSCR, I though PCR is actually used for long-term source code storage. Although PCR is "binary" too, there are major differences between PCR and BSCR. PCR is short-living and BSCR is for long-term storage. PCR tree is made of nodes, each node is a structure containing 32-bit pointers to child PCR nodes (if any). PCR tree therefore can be rearranged or inserted into another PCR tree (so it becomes subtree) just be setting 1 pointer. In contrast to PCR, BSCR is a linear sequence of 16-bit words (I call them BSCR entities). There is no pointers in BSCR representations. The relationship between entities in BSCR is encoded by the order in which BSCR entities lie in memory rather than by pointers to child elements. Therefore BSCR data can be easily moved in memory to a new location. While PCR trees can only represent syntactically correct lines of VB codes, BSCR supports representing invalud code. While comments and labels are not part of PCR trees, they are always part of BSCR data for code lines.
4. When source code must be rendered on a screen, saved into file on disk or temporarely represented as a text for performing search (Ctrl+F), the reverse transformation takes place. I call this TSCR. TSCR stands for Text(ual) Source Code Reconstruction. Sometimes I call initial form in VB-code representation as TSCR too (in this case TSCR is likely to be Textual Source Code Representation). TSCR does more than reconstructing text (a sequence of characters that can be rendered on a screen) which matches original line of source code, it also generates syntax-highlighting map and provides calling side with a so-called capturing feature: having a logical reference to some sub-expression within the line, you can determine which range of characters it spans (used for mouse-hovering tips, yellow highlighting of current statement during step-by-step execution and so on).
With all names that I assigned (by guessing) during my work, I use a prefix (Parsed/Pcr/Bscr/Tscr) to determine which mechanism this function relates to. The authentic names do not follow this rule, and sometimes the same thing is called differently which brings confusion (at least, in my opinion).
The thing that I call PCR is turned out to be called PT (parsing tree, obviously?).
The next stage which I call BSCR and BSCR entities is sometimes referred to as Opcodes, and sometimes as Pcode. This annoys be, because term 'PCode' is already used for byte code of VB virtual machine, and BSCR is definitely is not the same as P-code. Opcodes isn't very suitable name too, because it creates confustion with opcodes of P-code or opcodes of native code x86 (yet again, BSCR entities are neither P-code opcodes nor x86 machine code opcodes).
All functions involved into reconstructing text representation for BSCR representations turned out to have "Ulist" prefix in its names. What is U in Ulist? Who knows...
Here is example of matching my names against authentic names:
class CBscrLines
- Class CSmallHeap turned out to be BLKMGR32
- Class CVbaProject turned out to be GEN_PROJECT
- Class CBscrLines turned out to be OPCODE_MGR
- mynmParserParseLine turned out to be static method parser::parseOneLine
- mynmParserCommitPcrNode turned out to be ptCreateOperNode
- mynmTscrReconstructLine turned out to be ListOneLine
- mynmTscrProcessLineBscr turned out to be ListOpcodes
- tblBscrToTextHandlers array turned out to be g_fnListRules
- mynmTscrEmitParticles turned out to be ListRule
- CBucketTree class turned out to be RECLIST
- CBucketTree::TraverseTreeOfElements turned out to be RECLIST::FTraverse
- mynmTscrEmitKeyword turned out to be SingleWord
- mynmTscrEmitTwoKeywords turned out to be DoubleWord
- mynmTscrStartNewStatement turned out to be ResetGlobals
- mynmTscrHandleDefXxxStatement turned out to be UListDeftype
- mynmTscrHandleForEachStatement turned out to be UListForEach
- mynmCbLengthOfBscrVl turned out to be CbVariableSizeOpcode
- mynmXstackCleanUp turned out to be parser::parseRsrcRelease
- CMSNR class (module-specific name-related, represents module scope actually) turned out to be TYPE_DATA class (very misleading name...).
- mynmBscrWriteCodeLine is actually parser::generatePcode.
- mynmParserParseOptionStatement is actually called parser::parseOptionStmt
and so on. Hundreds or thousands of such entities.
I understand, however, that for you both my name and original Microsoft's name don't make much sense.
Anyway, I am amazed by this DBG file. Even though original names looks unfamiliar to me and misleading in some case, this is a great source of information about those functions and classes that haven't been toched by my reversing process at all.
-
Nov 1st, 2022, 03:38 PM
#7
Re: Redirect where Debug.Print goes.
I have been tracking down this type of information and exploring what I can while creating a vb6 disassembler and pcode debugger:
http://sandsprite.com/vbdec/
There is also a link there for an archive of vb6 reserving resources as well as a rebuild the old vb-decompiler.theautomaters.com
message board. The top level site also has a series of my papers on vb6 reversing.
 Originally Posted by firehacker
Probably I should make public portal and open all my reverse-engineering documentations, so that you can take function/method from this DBG and read what does it do and what arguments does it take from my articles?
Thats great, I am excited to hear what you uncover. I would love to read through any/all of the work that you would be willing to share. I have read through some of the articles on vbstreets and you have really done amazing work. (I aim to read everything on vbstreets in time!)
I still spend my holidays and weekends exploring this stuff mostly just because I love vb6. This years vacation was spent discovering how to extract full function prototypes from vb6 IDispatch implementation: http://sandsprite.com/papers.php?expand=0&show=34
I have mostly been exploring the runtime and exe file format still. I had not even really even looked at the ide symbols yet. Its awesome that you are already a master with them though. Your work did get me thinking about looking at the IDE as the next piece of the puzzle.
Sysenter-eip article on Vb compiler leaks info from host ( http://sandsprite.com/vb-reversing/VBParser/ ) had a copy of vba6.dbg which I could not load. This is what gave me the idea to start searching for vba5 symbols.
So much of this information can be easily lost to the ages. I do think it is important to publish as much as we can. The more people who understand it the better I think. VB6 is beautiful on the inside and out.
Last edited by dz32; Nov 1st, 2022 at 04:12 PM.
-
Nov 7th, 2022, 07:17 PM
#8
Re: Redirect where Debug.Print goes.
 Originally Posted by dz32
One other note vba print obj had a call to deserialize in it. It looks like debug.print might be able to do more fancy stuff than I imagined like deserialize some complex types like if you pass it a class object? Might have to implement an extra interface though. Or how get/put handle udts? Dunno need to examine it more could be nothing 🤷
One little tidbit I never knew about debug.print
So you can pass debug.print a class as an argument. If that class has a default function, printObject will call its default method and display its output. kinda neat if you wanted to incorporate a complex dump method as default to get easy output
Last edited by dz32; Nov 7th, 2022 at 07:46 PM.
-
Nov 8th, 2022, 02:53 AM
#9
Re: Redirect where Debug.Print goes.
 Originally Posted by dz32
One little tidbit I never knew about debug.print
So you can pass debug.print a class as an argument. If that class has a default function, printObject will call its default method and display its output. kinda neat if you wanted to incorporate a complex dump method as default to get easy output
This *had* to be implemented otherwise something like Debug.Print MyRecordset!ID would have not been able to work as expected and would have left a lot of people scratching their heads :-))
cheers,
</wqw>
-
Nov 8th, 2022, 03:52 AM
#10
Re: Redirect where Debug.Print goes.
isnt that the magic of the bang operator though? rs("id") is already a base value type not an object?
the following works
Code:
'class 1
'this is the default method of the class
Function def(x) As String
def = x
End Function
------------
'form1
Private Sub Form_Load()
Dim c As New Class1
MsgBox c!test
End Sub
-
Nov 8th, 2022, 04:14 AM
#11
Re: Redirect where Debug.Print goes.
rs!ID is rs("ID") is ADODB.Field instance so rs!ID.Value is valid syntax to access property Value of the ADODB.Field instance.
cheers,
</wqw>
-
Nov 8th, 2022, 04:28 AM
#12
Re: Redirect where Debug.Print goes.
aghh gotcha, makes sense thanks
-
Nov 15th, 2022, 02:09 PM
#13
Re: Redirect where Debug.Print goes.
 Originally Posted by Elroy
It'd be nice if I could figure out how to redirect where Debug.Print goes.
I've got a little persistent DebugPrint program I often use. It's easy to use, as I just remove the dot from my Debug.Print statements. However, it'd be even more cool if I could just redirect everything.
At first, I created an auto-instantiating class named "Debug". That worked just fine.
However, there are still two problems:
1) This class still doesn't override the internal Debug object.
2) "Print" is a reserved word and can't be used as a procedure name.
So drat. Any ideas?
The problem is not Print, the problem is Debug.
You cannot normally use 'Debug' as the name of a procedure because it is a reserved keyword.
You could name a class Debug, but that does not serve for the purpose.
You'll need to edit the VBA6.DLL and change where 'Debug' is written in the reserved keywords list with something else, for example DxBxg.
I have done it, if you want the DLL, I can send it to you privately.
About the Print method, it is not a problem.
-
Nov 15th, 2022, 06:36 PM
#14
Re: Redirect where Debug.Print goes.
 Originally Posted by Eduardo-
The problem is not Print, the problem is Debug.
You cannot normally use 'Debug' as the name of a procedure because it is a reserved keyword.
You could name a class Debug, but that does not serve for the purpose.
You'll need to edit the VBA6.DLL and change where 'Debug' is written in the reserved keywords list with something else, for example DxBxg.
I have done it, if you want the DLL, I can send it to you privately.
About the Print method, it is not a problem.
Hi Eduardo,
Hmm, did you just open the VBA6.DLL in a hex editor and search for "Debug"? If that's all it is, I can certainly do that.
Any software I post in these forums written by me is provided “AS IS” without warranty of any kind, expressed or implied, and permission is hereby granted, free of charge and without restriction, to any person obtaining a copy. Please understand that I’ve been programming since the mid-1970s and still have some of that code. My contemporary VB6 project is approaching 1,000 modules. In addition, I have a “VB6 random code folder” that is overflowing. I’ve been at this long enough to truly not know with absolute certainty from whence every single line of my code has come, with much of it coming from programmers under my employ who signed intellectual property transfers. I have not deliberately attempted to remove any licenses and/or attributions from any software. If someone finds that I have inadvertently done so, I sincerely apologize, and, upon notice and reasonable proof, will re-attach those licenses and/or attributions. To all, peace and happiness.
-
Nov 15th, 2022, 07:02 PM
#15
Re: Redirect where Debug.Print goes.
 Originally Posted by Elroy
Hi Eduardo,
Hmm, did you just open the VBA6.DLL in a hex editor and search for "Debug"? If that's all it is, I can certainly do that.
I used another one that had already the 'Tab' keyword changed by Shaggrat.
Then, I compared that DLL with the original one using WinMerge, and could see in what section the keywords were.
I found the 'Debug' keyword there, changed it to Dxbxg (using WinMerge), and tested that it worked.
-
Nov 15th, 2022, 08:51 PM
#16
Re: Redirect where Debug.Print goes.
Or do a search and destroy in memory so it’s only active when you want it
-
Nov 15th, 2022, 08:57 PM
#17
Re: Redirect where Debug.Print goes.
 Originally Posted by dz32
Or do a search and destroy in memory so it’s only active when you want it
I have thought about that, but it seemed more complicated to do at first sight.
If you have code to do it, it would be nice to test it.
Edit:
It would be good because it would be possible to post a Debug object replacement without having to edit the DLL, but... I'm thinking that if you start the IDE with full compilation it won't even run, because it would see the Debug keyword used before you can change the keyword list...
Last edited by Eduardo-; Nov 15th, 2022 at 10:35 PM.
-
Nov 15th, 2022, 11:44 PM
#18
Re: Redirect where Debug.Print goes.
I opened up vb6 and attached ollydbg native debugger then opened up the memory view window and did a search for the string. I can’t remember which one did the trick it might have been in heap memory by the time vb6 was loaded. Eventually there was one where debug keyword was no longer blue and intellisense didn’t work in it anymore. Then I crested a module named debug but I could not implement a print method so gave up. Your technique sounds to solve that.
Once you find the right instance to replace manually then you can devise a way to find it programmatically. Trick or firehacker might know where already. This might be the harder way to go about it honestly I just poked at it briefly to see if it might be a quick win and did get results. The hooking thing is smoother but requires more fancy stuff.
-
Nov 15th, 2022, 11:54 PM
#19
Re: Redirect where Debug.Print goes.
As I said: I don't think it would be possible because the program wouldn't have the chance to run, since the compiler will detect the procedure named 'Debug' and would not even run one line of the program.
-
Nov 16th, 2022, 10:10 AM
#20
Re: Redirect where Debug.Print goes.
Code:
' //
' // Debug redirect
' // by The trick
' //
Option Explicit
Private Enum PTR
[_]
End Enum
Private Declare Function GetModuleHandle Lib "kernel32" _
Alias "GetModuleHandleW" ( _
ByVal lpModuleName As PTR) As PTR
Private Declare Sub GetMem4 Lib "msvbvm60" ( _
ByRef pAddr As Any, _
ByRef pDst As Any)
Private Declare Sub GetMemPtr Lib "msvbvm60" _
Alias "GetMem4" ( _
ByRef pAddr As Any, _
ByRef pDst As Any)
Private Declare Sub GetMem8 Lib "msvbvm60" ( _
ByRef pAddr As Any, _
ByRef pDst As Any)
Private Declare Sub PutMemPtr Lib "msvbvm60" _
Alias "PutMem4" ( _
ByRef pDst As Any, _
ByVal pVal As PTR)
Private Function ReplaceDebugObject( _
ByVal pObj As PTR) As PTR
Static s_pCurObject As PTR
Dim hVBA As PTR
Dim pNTHdr As PTR
Dim pStart As PTR
Dim pEnd As PTR
Dim cSign As Currency
Dim lLength As Long
Dim lOldProtect As Long
If s_pCurObject = 0 Then
hVBA = GetModuleHandle(StrPtr("vba6"))
If hVBA = 0 Then Exit Function
GetMem4 ByVal hVBA + &H3C, pNTHdr
pNTHdr = pNTHdr + hVBA
GetMem4 ByVal pNTHdr + &H12C, pStart
pStart = pStart + hVBA
GetMem4 ByVal pNTHdr + &H128, lLength
pEnd = pStart + lLength - 8
Do While pStart <= pEnd
GetMem8 ByVal pStart, cSign
If cSign = 511398171365990.4051@ Then
GetMemPtr ByVal pStart + &H11, pStart
GetMemPtr ByVal pStart + &H44, pStart
GetMemPtr ByVal pStart + &H1, s_pCurObject
Exit Do
End If
pStart = pStart + 1
Loop
End If
If s_pCurObject = 0 Then
Err.Raise 51
End If
GetMemPtr ByVal s_pCurObject, ReplaceDebugObject
PutMemPtr ByVal s_pCurObject, pObj
End Function
Private Sub Form_Load()
Dim pOriginal As PTR
Me.AutoRedraw = True
pOriginal = ReplaceDebugObject(ObjPtr(Me))
Debug.Print "test"
Debug.Print "Hello", "world", Spc(10); "1234"; Tab(3); "vb6"
ReplaceDebugObject pOriginal
End Sub
-
Nov 16th, 2022, 10:41 AM
#21
Re: Redirect where Debug.Print goes.
Just I want to note that what The trick have published is not what I said it was not possible, but something else. FWIW.
BTW: Very good The Trick!
-
Nov 16th, 2022, 10:52 AM
#22
Re: Redirect where Debug.Print goes.
How does this work when you compile a project to an executable?
Or better said, what is the effect on the compiled executable?
-
Nov 16th, 2022, 11:37 AM
#23
Re: Redirect where Debug.Print goes.
 Originally Posted by Arnoutdv
How does this work when you compile a project to an executable?
Or better said, what is the effect on the compiled executable?
It depends on the executable.
-
Nov 16th, 2022, 01:07 PM
#24
Re: Redirect where Debug.Print goes.
tadah magic
awesome
works perfect with Eduardos IVBPrint interface too
Last edited by dz32; Nov 16th, 2022 at 01:14 PM.
-
Nov 16th, 2022, 09:43 PM
#25
Re: Redirect where Debug.Print goes.
 Originally Posted by The trick
Code:
' //
' // Debug redirect
' // by The trick
' //
Option Explicit
Private Enum PTR
[_]
End Enum
Private Declare Function GetModuleHandle Lib "kernel32" _
Alias "GetModuleHandleW" ( _
ByVal lpModuleName As PTR) As PTR
Private Declare Sub GetMem4 Lib "msvbvm60" ( _
ByRef pAddr As Any, _
ByRef pDst As Any)
Private Declare Sub GetMemPtr Lib "msvbvm60" _
Alias "GetMem4" ( _
ByRef pAddr As Any, _
ByRef pDst As Any)
Private Declare Sub GetMem8 Lib "msvbvm60" ( _
ByRef pAddr As Any, _
ByRef pDst As Any)
Private Declare Sub PutMemPtr Lib "msvbvm60" _
Alias "PutMem4" ( _
ByRef pDst As Any, _
ByVal pVal As PTR)
Private Function ReplaceDebugObject( _
ByVal pObj As PTR) As PTR
Static s_pCurObject As PTR
Dim hVBA As PTR
Dim pNTHdr As PTR
Dim pStart As PTR
Dim pEnd As PTR
Dim cSign As Currency
Dim lLength As Long
Dim lOldProtect As Long
If s_pCurObject = 0 Then
hVBA = GetModuleHandle(StrPtr("vba6"))
If hVBA = 0 Then Exit Function
GetMem4 ByVal hVBA + &H3C, pNTHdr
pNTHdr = pNTHdr + hVBA
GetMem4 ByVal pNTHdr + &H12C, pStart
pStart = pStart + hVBA
GetMem4 ByVal pNTHdr + &H128, lLength
pEnd = pStart + lLength - 8
Do While pStart <= pEnd
GetMem8 ByVal pStart, cSign
If cSign = 511398171365990.4051@ Then
GetMemPtr ByVal pStart + &H11, pStart
GetMemPtr ByVal pStart + &H44, pStart
GetMemPtr ByVal pStart + &H1, s_pCurObject
Exit Do
End If
pStart = pStart + 1
Loop
End If
If s_pCurObject = 0 Then
Err.Raise 51
End If
GetMemPtr ByVal s_pCurObject, ReplaceDebugObject
PutMemPtr ByVal s_pCurObject, pObj
End Function
Private Sub Form_Load()
Dim pOriginal As PTR
Me.AutoRedraw = True
pOriginal = ReplaceDebugObject(ObjPtr(Me))
Debug.Print "test"
Debug.Print "Hello", "world", Spc(10); "1234"; Tab(3); "vb6"
ReplaceDebugObject pOriginal
End Sub
This is amazing. I've seen The Trick do that memory searching of a library before. And, if I wasn't out camping, I was hoping to use his work and do that myself with the VB6.DLL library. But he beat me to it. Also, he probably got it done in a 10th the time it would have taken me.
I'm exhausted right now from setting up a campsite, but this looks absolutely wonderful ... CodeBank worthy.
Thank You!!!
Any software I post in these forums written by me is provided “AS IS” without warranty of any kind, expressed or implied, and permission is hereby granted, free of charge and without restriction, to any person obtaining a copy. Please understand that I’ve been programming since the mid-1970s and still have some of that code. My contemporary VB6 project is approaching 1,000 modules. In addition, I have a “VB6 random code folder” that is overflowing. I’ve been at this long enough to truly not know with absolute certainty from whence every single line of my code has come, with much of it coming from programmers under my employ who signed intellectual property transfers. I have not deliberately attempted to remove any licenses and/or attributions from any software. If someone finds that I have inadvertently done so, I sincerely apologize, and, upon notice and reasonable proof, will re-attach those licenses and/or attributions. To all, peace and happiness.
-
Nov 16th, 2022, 11:14 PM
#26
Re: Redirect where Debug.Print goes.
 Originally Posted by Elroy
CodeBank worthy.
I was thinking in an add-in that offers to save the text sent to the Debug.Print to a file.
My idea is:
Output to the immediate window as usual but at the same time save the text in a file.
Save it in different files each run, like:
ProjectFileName_Debug_1.txt
ProjectFileName_Debug_2.txt
ProjectFileName_Debug_3.txt
Being the max number of files configurable. Once the max number is reached, delete the older one.
ProjectFileName would be the file name of the *.vbp file. If the project is not already saved, then it does not write to a file.
At the start of each file, put the date and time (Now).
But... I don't think I'm going to do it right now anyway.
I share my thoughts in case someone else is interested.
-
Nov 17th, 2022, 08:02 AM
#27
Re: Redirect where Debug.Print goes.
Here's actually my idea/usage. I've got this little PersistentDebugPrint program so that I can survive IDE crashes as well as get much more in the output window before it scrolls off the top. The program has a feature where it puts a BAS stub into the clipboard that can be quickly inserted into any program I'm developing.
However, currently, to use it, you call DebugPrint (notice, no period). So, I search-and-replace "Debug.Print" with "DebugPrint" to use it. But, it'd be super nice if I could just have a call named something like "DoDebugRedirect" that I could comment in-or-out to use the PersistentDebugPrint, and not have to replace all my Debug.Print statements.
So, I'll be looking at working it all into a call to a BAS Sub DoDebugRedirect(bTrueFalse As Boolean) type call.
Any software I post in these forums written by me is provided “AS IS” without warranty of any kind, expressed or implied, and permission is hereby granted, free of charge and without restriction, to any person obtaining a copy. Please understand that I’ve been programming since the mid-1970s and still have some of that code. My contemporary VB6 project is approaching 1,000 modules. In addition, I have a “VB6 random code folder” that is overflowing. I’ve been at this long enough to truly not know with absolute certainty from whence every single line of my code has come, with much of it coming from programmers under my employ who signed intellectual property transfers. I have not deliberately attempted to remove any licenses and/or attributions from any software. If someone finds that I have inadvertently done so, I sincerely apologize, and, upon notice and reasonable proof, will re-attach those licenses and/or attributions. To all, peace and happiness.
Posting Permissions
- You may not post new threads
- You may not post replies
- You may not post attachments
- You may not edit your posts
-
Forum Rules
|
Click Here to Expand Forum to Full Width
|