« first day (1592 days earlier)      last day (1588 days later) » 

4:00 PM
@TweetingDuck LOL
 
is it possible to have an enum accessible from multiple modules?
 
Mug. Looks like any time " is entered it's putting in """
 
@KySoto Just make it Public.
 
it is public
 
Are the modules in the same project?
 
4:08 PM
it was giving me unknown type errors
yes
 
And they're standard modules?
 
Yes
 
@Comintern If you want, I can implement the new caching later today. After all, the old caching mess is my doing.
 
i moved all of my enums to a central module
and everything exploderbroke
 
@KySoto How do you try to access it?
 
4:10 PM
an example
Public Sub SaveAll(ByVal argSaveTable As String, ByVal argForm As String, Optional ByVal argFieldName As Variant = "", Optional ByVal argValue As Variant = Null, Optional ByVal argFieldType As mscFieldType = mscString, Optional ByVal argQryOrTbl As mscSourceType = mscTableDef, Optional ByVal argCustomSaveTag As String = "s")
 
@IvenBach that's weird.. I had no repro for it last time either
 
@M.Doerner If you have the time, that would be great. I can always ignore the tests until it gets sorted out too.
 
so i am using those enums as parameter types
 
Does that work within the same module as the enums?
 
yes, when its in the same module everything is good
when i move it to another, it goes exploderboom
Public Enum mscSourceType
    mscTableDef = 0
    mscQueryDef = 1
    mscParaQueryDef = 2
End Enum
that is an example, they are all public
 
4:13 PM
Is that enum defined in multiple modules?
 
no.
 
2.2.4007 goes Me.Range(|) -> Me.Range()"|, so I'll take Me.Range(""|") as an improvement. sigh
 
@KySoto Try fully qualifying it with the project name - As VBAProject.mscSourceType, where VBAProject is the containing project's code name.
 
they are all in the same project
this is access vba not excel
or do you mean the module name
 
How does Access scope the project? I.e., what shows up in the libraries combo for it in the Object Browser?
 
4:19 PM
ok, repro'd. wtf
that's a no-go
 
What does "ingore" mean in that context? Not assign to toFindCell1? In order to properly answer this, we'd need to see more code than the line you want to suppress an error on. Otherwise, your next question will most likely be "why doesn't X work now that I ignore a .Find error". — Comintern 10 secs ago
Seriously?
 
@KySoto I think your problem is related to a VBA quirk I stumbled upon a few months ago: apparently, you cannot define constants of a custom type defined in another module.
If my observation is right, you cannot make parameters of an enum type defined in another module optional.
 
@Comintern fyi, the scoping is the same between the two. In fact, I expect it to be the same everywhere
 
Project scoping is the same, but AFAIK there is no explicit module scoping in Access.
 
hm, I think that's incorrect.
what you can't do is use Eval or database engine expression that includes module references, but that's outside VBA
 
4:31 PM
Then, I just remembered incorrectly from this chat.
 
btw, I just tried out public sub foo(optional bar as enumInothermodule)
no problem?
or did I not understand?
 
@this I meant "how does it name the top level namespace". Apparently it's Database1.
 
@Comintern cue "if you don't X, then you don't need Y" smartguy.gif
 
default is same as the database's name when you create it
 
You have to provide a default value.
 
4:32 PM
but it can get out of sync - create a new database named Database1, then late rename the file to Foo.accdb, the vb project is still Database1, IIRC.
 
@MathieuGuindon Yep - you don't need to catch what isn't thrown.
@this Excel is the same way - everything is VBAProject unless you specifically change the code name.
 
That's super clever, and I didn't think about a "double negative" like that. I added it to my code, and it worked like a charm, thank you! — Anoplexian 51 secs ago
I'm thinking of making an Excel-specific inspection just for Range.Find.
 
IKR?
 
i think i remember seeing other writing a wrapper function around teh Range.Find to workdaorund some of the quirks
 
one day, Rubberduck will cause SO to think VBA is dead, because no more daily dupes
 
4:36 PM
Sometime I wonder if RD should be transpiling C# to VBA....
 
you mean VBA to C#?
 
but then I think of JS and I step back.
 
no, C# to VBA, under the assumption that Office never actually do anything for desktop automation and that JS API is never good enough.
that way we can write clean code and be expression, without worrying about the resulting boilerplate code that results in VBA.
 
We could put that in a paste handler. Ctrl-C in VS, Ctrl-V in VBE to get the transpiled VBA.
Now that the UI is figured out, we'll just wait for you to write it.
 
4:38 PM
Oh, ok, should only take me... 4 decades. Give or take.
If you help me, it'll only take 5 decades.
 
Let's just call it 4-6 decades.
 
but if Mat or Max join and help too, it'll take 6-8 decades.
 
there it is
 
4:46 PM
> The generalized form of this inspection would be "never assume an object-returning function will return an actual object reference", or "always verify whether an object-returning function returned Nothing", but that would be overly defensive IMO.

However `Range.Find` is such a common trap, it deserves its own dedicated inspection. Where `foo` is an `Excel.Range`:

```vb
r = foo.Find(bar).Row ' if bar isn't found in range foo, .Row will throw error 91.
'other code
```

Should quick-fi
 
@Duga <nerdsnipe-alert>this inspection would be a good opportunity to developer a service for setting up the customized quickfixes, in similar vein to how R# helps us set up the declarations in the for/foreach block.</nerdsnipe-alert>
 
QuickFix for that shouldn't be that difficult. Shouldn't the member access expression always be replaceable with an intermediate variable?
 
^ better
 
@this ...and that's why we have 2 IsMissing...Inspections.
 
@this meh.. we can't really programmatically know what code needs to be inside that if block, can we?
 
4:58 PM
@MathieuGuindon that's the point - allowing user to interact with the quickfix before finalizing it, no?
 
@Comintern You gave mug free points with your answer in a comment.
 
@this oooh
 
> The quickfix shouldn't be horribly difficult - I think pretty much every case would be "fixable" by just replacing the member access expression with an intermediate variable and then adding a boilerplate test with a TODO marker:

```
Public Sub Foo()
If Range("A:A").Find.Row = 1 Then
Debug.Print "Row 1"
End If
End Sub
```
...QF applied...

```
Public Sub Foo()
Dim canIHazRange As Range
Set canIHazRange = Range("A:A").Find("Something")
If canIHazRange
 
that service would make several quickfixes easier for where we can't deterministically fix the code.
But ComIntern's suggestion is safer, so we have a way so for this particular inspection, we don't need that.
 
@Duga It should absolutely use canIHazRange as the intermediate too.
 
5:00 PM
I'd just prompt for a valid name
and default to findResult or something
 
@Comintern and mousing over it should have that cheeseburger cat, too?
 
Yes!
 
> @comintern I'd rather have the .Row member call securely inside the added conditional block though. Without inverting the condition ("Not <s>result</s> canIHasRange Is Nothing"), running the code as-is would still throw error 91. We definitely can make the illegal member call safe, plus it shows the user where the "safe" code goes.
 
@M.Doerner well i figured thats what was going on
 
@IvenBach lol yeah I'd never have guessed what the problem was without @Comintern's comment! :D
 
5:10 PM
> @retailcoder I can definitely see that:

```
Public Sub Foo()
Dim canIHazRange As Range
Set canIHazRange = Range("A:A").Find("Something")
If Not canIHazRange Is Nothing Then
If canIHazRange.Row = 1 Then
Debug.Print "Row 1"
End If
End If
End Sub
```
About the only difference there would be finding where the logical reach of the block needs to be contained to. Slightly trickier due to `GoTo` or `GoSub` allowing it to jump out of the block.
 
Cominterns a smort duck. I have lerned lots from him.
 
> That's why my suggestion was to just put the throwing member call inside the conditional block, and let the user move the rest of the code (with an auto-TODO comment/marker) :smiley:

I don't think we can reliably automatically determine what the entire conditional block should be.
 
FWIW, the QuickFix could do a check for presence of GoTo or GoSub or Exit *** and thus refuse to fix.
Simpler to implement than that hypotehical service, I'm sure.
 
I don't think it matters. the member call can be solidified automatically. the problem is what follows.
 
@this Exit should be fine unless there is an assignment to a global. Stop too.
 
5:14 PM
or we could add Debug.Assert Not canIHazRange Is Nothing and let the user figure the rest
that could be confusing though. if Range.Find bites you, you probably aren't familiar with Debug.Assert yet.
 
think of it as a way to remind SO that VBA isn't dead.
 
We could always replace the code with the equivalent:
Dim findResult As Range
Set findResult = Range("A:A").Find("Something")
If findResult Is Nothing Then
    Err.Raise 91    'TODO - handle this better.
End If
^ Non-breaking change.
 
oooh I like
I like very much
prediction: within the next 6 months, a question will pop up on SO asking "why is Rubberduck quickfix raising error 91 here?"
A: it's not changing your code, just making the behavior explicit and easier to actually fix
 
5:30 PM
> Plot twist: we should probably pop a result for this too:

Dim result As Range
Set result = Range("A:A").Find("foo")
bar = result.Row '<< flag?

That would involve a bit of [code-path-analysis] though.
 
5:42 PM
Trying to figure out the adding of the @Folder annotation for code modules. Is there any way I can actually view what the code contains? I'm looking at Rubberduck.VBEEditor.SafeComWrappers.VBA.VBAComponent currently.
 
it's deeper than that
 
i'm 99% sure you don't need that
you should be working inside Rubberduck.Parsing, no?
 
the actual code is in the ICodeModule
 
I thought we should want to deal with the annotation from the parsed tree, not any COM objects.
 
@this we do... but then at one point you need to actually add it, no?
I wouldn't involve the rewriters for this
 
5:45 PM
#ReadingComprehensionFail
i was fixated on "viewing what code contains"
 
@IvenBach @this is correct - you shouldn't use the VBIDE API to figure out whether a module has a @Folder annotation
that's all worked out already
 
I'm trying to figure out how to get started.
 
get the ModuleDeclaration; IIRC it should have an Annotations list that you can inspect
wait hold on, are we talking about existing modules, or newly-added modules?
 
Newly imported module.
 
what is the format of this module then?
 
5:49 PM
That should trigger a re-parse.
 
Is it already inside the project or is it still a text file floating outside?
 
The one I'm currently working with is a .bas module
 
so it's still a file. Ok - I figure that we don't want to trigger re-parsing until we have injected the @Folder annotation before we import it.
That would minimize the parsing's efforts in exchange for extra work on developer (that's you!)'s part.
Since it's just a text file you could probably a very simple regex to search if it has a @Folder annotation somewhere.
 
I plan to invoke the import method and before the reparse is completed either Find&Replace the folder annotation or add it. That way it's only parsed once.
 
otherwise, to add it after the attributes section.
 
5:52 PM
@this Or a not so simple regex... Debug.Print "Should I put a @Folder annotation here?"
 
Hey.... we have CodeString!
why can't we use that?
 
because the useful bits aren't merged yet :)
 
We also have a parser. :-)
 
It's jumping around and I don't fully understand why. I know the SafeComWrapper is doing something but the abstraction lasagna is hard to digest.
 
@MathieuGuindon ....CodeString....
 
5:54 PM
How hard would it be to parse a free-standing file without resolving it?
 
that's exactly what CodeString is for!
 
CodeString means to represent a logical line of code though
 
we used to have a CodeStringParser but Max refactored the parser to take CodeString as well as a IModule?
 
hmm I might have missed that part
 
there is now no restriction on where the code came from; we are now able to parse code whether it comes as a string or from a module, etc.
 
5:56 PM
:feels a SmarterIndenter coming on...:
 
and IINM, that can be done w/o resolving, too. At least that's what the CodeStringParser originally did.
So Iven should be able to cram that string representing the module in the parser and get himself a spiffy nice parse tree and find the annotation he wants.
heck, he can use rewriter, too!
then finalize the import without touching COM at all
 
@this I'm still before the first fork in the road. Ya'll are 37 miles ahead of me.
 
sorry - i'll backtrack a bit.
Unless Mat / Com says otherwise, this is what you want to do....
first, don't touch anything COM!
COM = Toxic waste
 
I'm still trying to locate where the declarations are.
 
touch it, sky falls, OK?
So you do have a file. That file is just a text file, OK?
 
6:01 PM
Yes.
 
@IvenBach Do you have access to a parser state?
 
1) you need to extract the text out of the file... File.ReadAll*** method, maybe, stuff it in a string variable.
 
@Comintern I don't know. At some point I think so but it's likely burried in some other object.
 
2) create an instance of parser that will take a code string.... let me see if I can find that....
 
Oh wait. If you're parsing the file to be imported, you don't need one.
You only need a parse tree, no declarations required.
 
6:04 PM
github.com/rubberduck-vba/Rubberduck/blob/next/Rubberduck.Core/… is my entry point. From there I can see that it gets imported and reparse is requested.
 
right. parse the text file, tweak the text file accordingly, import the text file, done
 
While inside there I can't figure out how to find the code it's importing.
 
you have a filename; get the text string from the file
File.ReadAllLines or something
 
I thought we got rid of it since Max did a PR that refactored and cleaned up the parser but I guess not? @M.Doerner can you confirm if we should be using this parser for string literals?
 
6:05 PM
(although, you'll probably want to abstract that behind an interface if you ever want to be able to unit-test the command)
 
After checking to see if it exists.
 
Psuedo-code:
 
And having everything wrapped in try-catch blocks because you're doing IO work.
 
Anyway, continuing - so you run the parser using this parser above (it's ok to new it up), you'll have a parse tree which you can then harvest for the annotations and either update or insert an annotation
@Comintern that could be limited to the File.ReadAllLines, no?
 
6:06 PM
Yeah, probably.
 
We don't need to do any further IO work once we have it in a string?
 
Figure out file you want to import; //done with `filename`
Regarding `@Folder` Annotation (Add annotation | Update);
Import file;
 
import can be done using string-insertion method... do we expose that?
 
break it down further. smaller steps.
 
^ you're missing the parse step
 
6:07 PM
I'd check to see if it exists too though - that way the components.Import(filename); wouldn't throw either.
 
@this yes, but would that import member attributes?
 
oooh, forgot about that
 
We could just name the default folder "Broken Imports".
:ducks:
 
so it'll be more like 1) extract file content into string, 2) parse, 3) locate annotation and update or insert, 4) rewrite, 5) create temp file, 6) import from that file
and since 1 and 5 are IO, those need to be tried'n' catched caught(?).
 
I'd do 6 too.
If there's heavy IO pressure, that could fail even if 1 and 5 succeed.
 
6:11 PM
yeah.
 
@this tried and imprisoned executed yeah caught is fine
 
but this still achieves the goal - no COM handling
 
well the actual import is through COM
 
@MathieuGuindon fined
 
6:14 PM
-_- im having trouble finding the conversion stuff for secur32
can you guys point me to where the ref is?
 
secur32?
 
@MathieuGuindon at least it's already test'n'tried so no need to reinvent the wheel and spilling the toxic waste everywhere, no?
 
yeah
its basically so you can do a proper kerberos handshake
 
Give me an example function.
 
6:16 PM
i started to convert them, so they have ptrsafe, but they arent done,
Private Declare PtrSafe Function CompleteAuthToken Lib "secur32" (ByRef phContext As SecHandle, ByRef pToken As SecBufferDesc) As Long
 
^ pro tip: google <name of function name> Windows function
 
@Comintern Might be hte thing
i was hoping i could just get the whole kit at once rather than go through like 10-15 functions
 
look to the left sidebar
 
yeah, its what i need
well what @Comintern gave me is anyway
 
6:19 PM
hmm. lnteresting, secur32 apparently has 2 headers. the first link above was for ntsecura.h while com's link was for sspi.h.
 
Where's the SecHandle struct? That looks like it just takes a pointer.
 
coms link was the good one
Private Type SecBufferDesc
    ulVersion As Long
    cBuffers As Long
    pBuffers As Long
End Type
 
That's the output.
 
its not EXACTLY the same since it asks for unsigned long
but whatever. it works
 
6:20 PM
O_o Not on 64-bit it doesn't.
Private Declare PtrSafe Function CompleteAuthToken Lib "secur32" (ByVal phContext As LongPtr, ByRef pToken As SecBufferDesc) As Long
 
i mean in hte type
 
SecBufferDesc isn't 64-bit safe either.
 
welll crap
 
Private Type SecBufferDesc
    ulVersion As Long
    cBuffers As Long
    pBuffers As LongPtr
End Type
 
looks like im going to have to wrap that in the if then
 
6:23 PM
Anything that's documented as a pointer or a handle needs to be LongPtr.
 
so anything that says buffer is a longptr?
 
@Comintern Interesting, last week, there was a guy who claimed he got away with just converting everything from Long to LongPtr, on the claim that he was in a hurry to get it working on 64-bit and it worked. I'm having a teensy weensy hard time believing him.
@KySoto Not necessarily. Consult the documentation. :)
 
No, a buffer is just a block of memory. The memory address of the buffer is a LongPtr.
 
i really dont feel like i know enough
 
I say consult primarily because you can't trust them to be consistent with how they set up the declaration.
 
6:25 PM
to be doing this
especially since the thing im operating on was something i found
 
you MUST always read the documentation and convert it properly.
 
the problem is i cant decipher the documentation
 
The important thing is to focus on the header declarations
 
when i see 20+ full caps character words i start going derp face
 
and follow the data types.
 
6:26 PM
pBuffers

Pointer to an array of SecBuffer structures.
 
makes sense
 
BTW, here's an exercise just to help in case where you're not sure from the documentation --- you should make this page your BFF:
 
Note that ByRef pToken As SecBufferDesc is good unless you're manually copying the memory buffer. That's what PtrSafe does for you.
 
so if you run across a data type that you don't recognize, it'll be listed here. As a convention, SCREAM_CASE are alias for some other C++ data type. It is common for a data type to be an alias of an alias of an alias of an alias
Let's use HWND as an example. We already know it's a pointer but you can still work it out by following it.
So if you find HWND on the page, it'll say typedef HANDLE HWND. So find HANDLE because that's an alias. it then says typedef PVOID HANDLE. So find PVOID which says void *, which is the true C++ data type cos it's not SCREAM_CASE
This process works for any other data types so you can ultimately resolve and after a while, it becomes second nature to know which is a pointer and which is just a dumb ol' integer data type.
 
they really had to alias void*?
(wait is void* the same as void *?)
 
6:32 PM
Yes, it's the same
That's C/C++ for ya!
 
IDK, I don't trust anything I read in C/C++. there's always a naughty gnome that pops out of nowhere to take what I understand, shred it to pieces, and laugh at me like a madman.
 
4
A: What is PVOID data type?

IsmaelThis and other mnemonic like BOOL, LPCTSTR have it origin with Windows, which BTW was developed before the existence of a C standard, and to not depend in a particular compiler it used its own types. You can check the Old New Thing blog for more stories about to the Windows development history, ...

 
> which BTW was developed before the existence of a C standard
 
@MathieuGuindon I don't blame ya. Fortunately, reading a declaration is much much easier than trying to read actual C/C++ code. shudders.
 
I always envision epic battles between Ritchie and Kernighan about the "correct" syntax for declaring a pointer. Unfortunately, they compromised and everyone lost.
 
6:36 PM
@Comintern I remember someone actually claiming that they did it deliberately because they didn't want dumb people coming in to program. O_o
 
Explains a lot about the [c++] tag in comparison to the [vba] tag.
 
#Hacktoberfest #UpForGrabs: a much needed (this #VBA bug is way too common!), library-specific inspection to locate member calls made directly against the result of Excel.Range.Find, e.g.: r = Range.Find(bar).Row https://github.com/rubberduck-vba/Rubberduck/issues/4440
 
@TweetingDuck slowpoke
 
HTH does a production application have a freak'n view with a divide by zero error in it?
It isn't even EF.
 
@Comintern you don't need a app for that. You could do that purely in t-sql
CREATE VIEW derp AS SELECT 1/0;
I bet nobody tested for cases where the divisor was zero
 
6:44 PM
Yeah, you'd think that somebody would have noticed it before it shipped though.
 
"oh, it's OK. Nobody'll put zero in that column. No worries."
 
I mean, it's the main cash receipts view for crying out loud.
No wonder I'm converting data from it...
 
"After all, if they did have zero, they'd be out of business, right? Ha ha ha!"
Sadly, I've run in one too many division by zero errors in various production database. :\
 
"Reported profits are way down this month. Can't figure out why..."
 
so somehow i managed to discover there is an atom datatype
i dont get it, but yeah, its a thing
 
6:53 PM
yeah we use that in RD, IINM
 
uhhh... the heck is the atom datatype?
 
yeah i read that, and it didnt make much sense
i guess i'll give it a second go
is it... kinda like a dictionary?
 
Yep. It's basically a Dictionary<int, string> with an ancient API to manage accessibility.
 
Please try to not split it.
 
6:57 PM
Thermonuclear access violation?
 
what if you were only splitting alpha radiation off of thallium?
 

« first day (1592 days earlier)      last day (1588 days later) »