rubberduck-vba / Rubberduck

Every programmer needs a rubberduck. COM add-in for the VBA & VB6 IDE (VBE).
https://rubberduckvba.com
GNU General Public License v3.0
1.91k stars 299 forks source link

Insane slowdown with VBA 7.1 in CorelDRAW #5656

Closed some9000 closed 3 years ago

some9000 commented 3 years ago

Hello!

I understand that CorelDRAW VBA is a really niche usage case, but here we are...

In my case indentation was the main usage case. And it works great, being a port of the great Office Automation version.

However - for some reason there's an insane spike in CPU usage once Rubberduck is installed. Instantly CorelDRAW uses about 30% and spikes to 50% or more at times. Selecting objects takes seconds to show a frame, moving takes even more time. Something is really, really off. I tried disabling all I could () and it still happens. Also all the code analysis windows come up empty.

I understand that quite likely very few users here would have CorelDRAW for any testing. So besides this being an issue - is there any way to disable any and all real-time functions and leave only the code formatting?

daFreeMan commented 3 years ago

You've not given us much to go on...

some9000 commented 3 years ago

Hello, thanks for replying. Let's see...

Version: Rubberduck 2.5.1.5557

Code modules: Several hundred I guess... Mostly small quick functions, 99% of them completely localized. But there are quite many of them, at least 10000 lines of code total over several .gms files. Perhaps more.

Does Rubberduck show that it's still parsing when you're experiencing the slowdown? Its toolbar has "Pending" all the time, for example solid 20 minutes so far. All the while cpu usage jumps 25-50%. CorelDRAW is a vector graphics editor and even opening a larger file normally uses only about 20% of the CPU. The file loads and then the CPU use goes down completely unless some actions are taking place.

Once Rubberduck in uninstalled everything goes back to normal.

RubberduckLog.txt

Vogel612 commented 3 years ago

I wonder whether that's related to the log only comprising of COMExceptions:

2020-12-15 12:42:37.2136;ERROR-;Rubberduck.VBEditor.SafeComWrappers.SafeComWrapper`1;Unexpected COM exception while acquiring the host application object for application CorelDRAW via COM reflection.;System.Runtime.InteropServices.COMException (0x800401E3): Operation unavailable (Exception from HRESULT: 0x800401E3 (MK_E_UNAVAILABLE))
   at System.Runtime.InteropServices.Marshal.GetActiveObject(Guid& rclsid, IntPtr reserved, Object& ppunk)
   at System.Runtime.InteropServices.Marshal.GetActiveObject(String progID)
   at Rubberduck.VBEditor.SafeComWrappers.Abstract.HostApplicationBase`1.ApplicationFromComReflection(String applicationName) in C:\projects\rubberduck\Rubberduck.VBEEditor\SafeComWrappers\Abstract\HostApplicationBase.cs:line 27

Long story short: CorelDRAW seems to not conform to what rubberduck expects of the host application, namely an available COM Object in the "Running Objects Table"(ROT) with the ProgID CorelDRAW.Application that conforms to TApplication. This post on the coreldraw community forums (found via this stack overflow question) suggests that Corel is not correctly registered to the ROT.

We do already have a CorelDRAWApp, but apparently that doesn't deal with the specific version of Corel that you are using correctly. If you want Rubberduck in your CorelDRAW, that's where you'd fix it 😉

some9000 commented 3 years ago

We do already have a CorelDRAWApp, but apparently that doesn't deal with the specific version of Corel that you are using correctly. If you want Rubberduck in your CorelDRAW, that's where you'd fix it 😉

Given how Basic is the only language I basically (heh) remember that may be a little difficult.

Also my version of CorelDRAW is 2018, but since they have not changed anything with VBA for quite a while that probably isn't too important in general.

But back to my initial question - would it be possible to enable only the code formatting function (which works just fine)? Disable code analysis and such completely so it does not have to fail at it repeatedly (I assume that is that, since all those other menu items produce empty windows)?

Vogel612 commented 3 years ago

I don't think it's possible. The thing that doesn't work is literally the entry-point into the whole VBE for Rubberduck. As such I'd assume that even just reading the code to indent it already fails.

some9000 commented 3 years ago

I don't think it's possible. The thing that doesn't work is literally the entry-point into the whole VBE for Rubberduck. As such I'd assume that even just reading the code to indent it already fails.

Hmm, but indentation is the one thing that actually works just fine. Insane slowdown and repeated crashes when, for example, I delete a form element happen. But indentation works perfectly.

daFreeMan commented 3 years ago

Odd... RD doesn't do anything when you delete a form or element or anything else. It's only when you manually tell it to parse that it would even know that the form is now missing.

Other than key-hooks for shortcut key handling, RD doesn't do anything real time like the IDE does - i.e. knowing that a form has been added/deleted. Knowing that you've moved off of a line in the editor so it can pretty-print the line, etc.

some9000 commented 3 years ago

Odd... RD doesn't do anything when you delete a form or element or anything else. It's only when you manually tell it to parse that it would even know that the form is now missing.

Well, I have no idea what is happening, but it was one specific element (a text box) and it crashed each time as I tested it four times in a row. Once RD was uninstalled everything worked just fine. Now, after a couple of reinstalls, I could delete that object without a crash. Seems like it is just super unstable with CorelDRAW. And it still uses 30% of CPU constantly.

Sounds like I will have to abandon it for now or use the online code formatting tool or get the MZ-Tools (but buying it and using like 5% of the tools feels wrong).

retailcoder commented 3 years ago

For the record, "Pending" status is the idle state, it'll remain that way until a parse is triggered, either manually by clicking it, or automatically by having Rubberduck make any kind of code changes.

Deleting or adding a module (that includes a userform) also triggers a parse, I think - although these handlers could be tweaked to not trigger a parse if the state is "Pending", if that's not already what's happening.

We would probably just need an indenter setting to determine whether or not to parse after indenting, and the indenter commands to honor the setting.

However, discussions around the last few edge cases that currently break the indenter, involve solutions that would require the indenter to leverage parse trees - making a successful parse a prerequisite for indentation.

Without parse trees, Rubberduck is useless. Rubberduck is not a lightweight indenter add-in. You could grab the original Smart Indenter VB6 source code and tweak it to make it work for your purposes - but we're not going to ship a Rubberduck build that doesn't need to parse the source code and cannot run unit tests, that's... I'll be kind and not presume that was your intention, but that's literally taking 5 years of collaborative efforts by over 50 contributors and saying "oh, it's free so not even using 5% of it doesn't feel wrong at all".

Rubberduck is free... It's also provided as-is, in the hope it will be useful. Cheers!

some9000 commented 3 years ago

Sorry, did not mean to offend with that "free" comment. What I mostly meant was that indentation is what brought me here and I would more than likely also use all the awesome features you have been adding to Rubberduck over the years. But since they do not work at all at the moment and I am certainly not a skilled programmer or even a "programmer" at anything besides VBA it is basically hopeless for me to fix it.

Indentation is the one thing that does work. But with insane slowdown of the entire application throughout. Hence the comment that I will most likely have to look for some other solution.

Now to your above comments: I understand that "Pending" is the initial idle state, but it always stays on it. When pressing refresh or when not making the add-in load automatically and launching it well after CorelDRAW has opened.

And like stated above I don't need to do anything at all - not load anything, not enter any code or change anything on a form. The moment the VBA editor is opened the massive CPU usage starts instantly and never goes down. In comparison, with (trial) MZ-Tools the CPU usage is as expected.

More than likely it has to do with the way CorelDRAW acts with VBA. They don't have the best track record with their code. Especially for "niche" features like VBA support.

Once again, I am sorry if my comments sounded out of line. It's just that I cannot fix the problem, so looking for another solution is the only real option here (since CorelDRAW VBA is certainly a super-niche usage case and probably only useful to me and maybe a couple of other people, as we could see from that one post mentioned above).

Edit: I also added a topic in CorelDRAW developer forums, perhaps someone can see if it happens in all the versions of CorelDRAW (suspect it will, since VBA has not been updated for a long time, so most likely neither has their implementation).

retailcoder commented 3 years ago

I think we could try to catch the exception and possibly set a "bad init" flag that we could pick up a bit later (we can't tear down in the init callback) to gracefully tear down with an error message along the lines of...

Rubberduck could not properly be initialized and will now shut down and unload. COM registration of the host application is possibly broken, or the host isn't implementing an 'Application' object as expected.

And then we could have a <NoStartHosts> node added in the settings file with a child node like <Host Name="CorelDRAW" Version="*"> and then if the startup code finds the host app/version under this "no start" node, we could bail out of initialization before the splash screen gets displayed.

The result would be that Rubberduck would unload itself in that version of CorelDRAW, while still being able to load and run normally in other VBA hosts (e.g. Excel). It would ideally do the same when failing to load in an Access 2010 host that was installed after Office 2016 (different versions of Office components want to be installed in chronological order when running side-by-side).

Now that wouldn't leave no-op Rubberduck commands that do nothing but throw exceptions, ...but it would also make the indenter (and everything else) not available at all whenever the host app cannot be talked to.

Other add-ins (like MZ-Tools) don't parse your code, which means whatever modifications they do to your code are treating that code as plain text rather than tokens, which severely limits how accurate and ultimately how correct code changes can be: I haven't tested it, but I'm pretty sure MZ's "find all references" would turn up a lot of junk given something like this very evil code that melts one's brain, that Rubberduck correctly/accurately resolves.

Rubberduck hooks deep inside the VBIDE internals, and accesses a number of undocumented interfaces and pointers for various purposes, including the ability to run a unit test procedure from the add-in (early versions used Application.Run for that); we hook up IDE events that aren't exposed, and the many GBs of RAM hold the complete metadata about everything that's loaded in the IDE, including referenced libraries.

That's how Rubberduck features are all readily usable as soon as a parse run completes. Meanwhile (unless that changed?) MZ needs to bring up a progress indicator and process the code every time, and because its understanding of the code is text-based, its static code analysis capabilities are minimal.

But if RD can't parse for whatever reason, none of it matters... and it doesn't make much sense to ship an indenter-only Rubberduck; a better solution would be to build the indenter into its own lightweight add-in, and ship it separately from Rubberduck.

some9000 commented 3 years ago

I understand your approach that this is a tool which has all the options so making it partially usable does not make sense. Absolutely agree.

Some more on what I have tried here:

Once again uninstalled and installed Rubberduck and noticed that during the installation the Register the Rubberduck VBE Add-in screen pops up twice. Thought that perhaps something gets registered the wrong way, but ticking just one of them did not affect anything.

Then removed almost all of my projects from the VBA directory leaving just a single project with a couple hundred lines of code. When CorelDRAW is launched the resource usage looks like this:

Taskmgr_2020-12-16_19-41-38

Once I open the VBA editor and touch any of the Rubberduck functions (strangely this time the crazy resource usage did not start instantly). And within half a minute we are here:

Taskmgr_2020-12-16_19-43-11

And then it just stays around these values for as long as CorelDRAW is open. I also tried their latest 2020 version, but it absolutely uses the same VBA editor so nothing was different at all.

retailcoder commented 3 years ago

The VBE is the same in most 3rd-party host apps, the problem is with Corel's implementation of their VBA hosting; there should be an Application object, but Rubberduck can't find it in the host application's object model.

That would be for Corel to fix though, there's little we can do other than better handle this critical failure.

I have to admit the memory usage here looks very much like a memory leak, likely related to the COM exception being thrown.

I mean Rubberduck does use a lot of RAM, but that's way off the charts... especially if it can't even parse anything!

I hate to say it, but in this case I would recommend uninstalling Rubberduck, given the current build obviously isn't going to work with this particular host. Future Rubberduck versions may handle this without crippling CorelDRAW while still working fine in other hosts (e.g. Excel), but I unfortunately don't see Rubberduck working with this particular version of CorelDRAW, absent a patch from the publisher.

I'll post an update here if/when Rubberduck fixes this memory leak and cleanly handles this startup failure, or if/when Rubberduck's indenter is built into its own lightweight standalone indenter add-in that can import and consume indenter settings from both Smart Indenter and Rubberduck!

retailcoder commented 3 years ago

Some hosts require a per-machine registration (installer needs admin rights for this) and don't play well with per-user... could it be just that?

some9000 commented 3 years ago

Some hosts require a per-machine registration (installer needs admin rights for this) and don't play well with per-user... could it be just that?

I tried both You only and Anyone who uses this computer, nothing changed. I am currently working from home, so there are no limitations to anything (Admin user).

I'll post an update here if/when Rubberduck fixes this memory leak and cleanly handles this startup failure, or if/when Rubberduck's indenter is built into its own lightweight standalone indenter add-in that can import and consume indenter settings from both Smart Indenter and Rubberduck!

Thanks, that is some amazing support from your side. And I will post here if someone in the CorelDRAW dev forums has some idea on how to fix this behavior.

Just a small update: To be sure that there is no conflict between versions of CorelDRAW and any other applications or VBA settings or whatever, I completely uninstalled both versions of CorelDRAW I had, deleted all their leftover folders, cleared out all registry entries and then did a clean install.

Same problem. So it's their questionable VBA support for sure.

Another update: Working with the VBA project with this Add-in active apparently corrupted something in the forms area. Every time I tried to change something, entire VBA editor and CorelDRAW would crash instantly. I had to export all parts and then import them back into a new project for things to work again. Interestingly despite having all the same contents the new project file was smaller in file size.

retailcoder commented 3 years ago

Every time I tried to change something, entire VBA editor and CorelDRAW would crash instantly. I had to export all parts and then import them back into a new project for things to work again. Interestingly despite having all the same contents the new project file was smaller in file size.

Sounds like something got corrupted (probably related to the memory leak); exporting + reimporting all project components is the typical cure for it (ironically RD has features specifically for syncing a VBA project with files on disk, which exports and overwrites files and project components).

mansellan commented 3 years ago

I note that Corel do offer a 15 day trial (without needing CC registration), so it may be possible to debug this.

retailcoder commented 3 years ago

Linking #3347

some9000 commented 3 years ago

Hello again. Just wanted to say that the currently latest version works really well with CorelDRAW. Of course, indentation works, as previously. Code inspections work and I have cleaned up a lot of code thanks to them. Code metrics work, Code explorer works. Autocompletion works. Need to learn more about the functions in general to use them more often.

Also, in the latest version the insane slowdown mostly goes away if "Run inspections on successful parse" is disabled. So thanks a lot for all the work on this super useful add-in.

PS. Unless I am missing the option somewhere... Would be cool if code inspections could be done on Project/Module basis to speed things up and make the results a little clearer.

retailcoder commented 3 years ago

Hi there, very glad to hear about a happy ending here! Note that you can group (and filter) inspection results in several ways (by inspection/type/severity, ...and by module) using the various knobs & buttons toolbar at the top of the inspection results toolwindow. Cheers!

On Tue., Sep. 14, 2021, 06:38 Clemens Lieb, @.***> wrote:

Closed #5656 https://github.com/rubberduck-vba/Rubberduck/issues/5656.

— You are receiving this because you commented. Reply to this email directly, view it on GitHub https://github.com/rubberduck-vba/Rubberduck/issues/5656#event-5298687341, or unsubscribe https://github.com/notifications/unsubscribe-auth/ABL4HBEMD7LZB6E7THNPBIDUB4Q3NANCNFSM4U2SI7BA .

some9000 commented 3 years ago

I'm aware of that, of course, and absolutely use it to sort the results by modules. But with dozens of modules it still makes for a looong list that takes a bit to update. Just an idea for an option.