Question

LoadLibrary on DLL file that's not on disk

Asked by: shrif

I'd like to know how I can call LoadLibrary and load a DLL file that's not physically located on any disk.  LoadLibrary loads a DLL file that's on disk and takes the files path name as a parameter.  I have the contents of the DLL in memory and would like LoadLibrary to load the DLL from memory instead.

As far as I can see, I have the following options.  I'd like some advice on which way to go and if anyone's got a better idea.

1.  Create my own network redirector and use a UNC path to LoadLibrary, having the redirector return the data to LoadLibrary from the in-memory-image
    NEGATIVE: A lot of work to create a redirector.

2.  Create a URL Moniker (protocol) that knows how to retrieve the data from memory and then pass in the URL to LoadLibrary (i.e. myurl://file.dll)
    NEGATIVE: LoadLibrary internally may call a low-enough level API to open the actual file where the API bypasses URL mapping -- that is, LoadLibrary may only work if it's an actual mounted file system.

3.  Use INJLIB or Microsoft's own "Detours" library to trap calls the CreateFile (or whatever), as they are called by LoadLibrary and return a file HANDLE that'll actually retrieve the file from memory.  Perhaps the HANDLE returned is a named-pipe and if that doesn't work. perhaps the calls to Read() are also trapped to return the data.  Depending on how much support LoadLibrary needs.
    NEGATIVES: The "Detours" library can't be used to do this on non-NT systems.  INLIB can be used, but the versions that are currently available on the Net (from May '94 issue of MSJ) only supported NT (no Windows 95 back then).  The author of INJLIB supposedly has updated INJLIB to work under newer Win32 OSs, but I can't seem to find that anywhere.

4.  Write the memory contents to disk and then call LoadLibrary.
    NEGATIVES:  There's no way to delete the file after calling LoadLibrary on it.  At least it didn't work when I tried it (yes, I called FreeLibrary on it.)
    WORKAROUND FOR NEGATIVE:
    Use MoveFileEx with MOVEFILE_DELAY_UNTIL_REBOOT (and corresponding technique for 95/98/me) to mark the file for deletion after reboot.

Okay, I've rambled on enough about this.  I'd like to hear some opinions about which way I should go and why.

It's hard to pronounce a "right answer" for this type of questions, so I guess the only thing I can do is give it to the person that gives me the best argument for a particular approach (weighing complexity vs. functionality, of course.)

I consider this a pretty advanced topic, so I'll set it for 300 points.

This Question has been solved and asker verified All Experts Exchange premium technology solutions are available to subscription members.

Subscribe now for full access to Experts Exchange and get

Instant Access to this Solution

  • Plus...
  • 30 Day FREE access, no risk, no obligation
  • Collaborate with the world's top tech experts
  • Unlimited access to our exclusive solution database
  • Never be left without tech help again

Subscribe Now

Asked On
2001-08-15 at 18:35:28ID20169199
Tags

loadlibrary

,

injlib

Topic

Windows Programming

Participating Experts
6
Points
300
Comments
32

Trusted by hundreds of thousands everyday for fast, accurate and reliable tech support.

  • "The time we save is the biggest benefit of Experts Exchange to Warner Bros. What could take multiple guys 2 hours or more each to find is accessed in around 15 minutes on Experts Exchange." Mike Kapnisakis, Warner Bros.
  • "Our team likes having a resource that is more secure than just using Google and most experts using this service really know their stuff. It's nice to look here first versus using Google." Dayna Sellner, Lockheed Martin
  • "Anytime that I've been stumped with a problem, 9 out of 10 times Experts Exchange has either the accepted solution or an open discussion of the potential solution to the problem." Kenny Red, eBay Inc.

See what Experts Exchange can do for you.

Got a question?

We've got the answer.

Experts Exchange has been collecting answers to technology questions since 1996…3 million and counting! If you have a question, chances are we already have your answer.

Screenshot of Experts Exchange Knowledgebase

Need individual assistance?

Our experts are ready to help.

If you can't find the exact answer you're looking for, ask our exclusive community of 50,000 experts. You’ll get a personalized answer from a trusted professional.

Screenshot of Experts Exchange Knowledgebase

Want to learn from the best?

Read articles from industry experts.

Thousands of free tech tips, tricks, how-to’s and tutorials are available in our peer reviewed articles section. See for yourself how smart our experts are, no login required.

Screenshot of an Article

Working on a long term project?

Store your work and research.

Save solutions to your questions, answers you’ve discovered through searching plus helpful articles in your personal knowledgebase for easy future access.

Screenshot of Experts Exchange Knowledgebase

Access the answers to your technology questions today.

Subscribe Now

30-day free trial. Register in 60 seconds.

What Makes Experts Exchange Unique?

Members of the expert community talk about why the experience at Experts Exchange is different than what you will find anywhere else.

Trusted by the world's most respected brands.

image of each brand's logo

Faithfully serving IT professionals since 1996.

Experts Exchange Logo

Try it out and discover for yourself.

Subscribe Now

30-day free trial. Register in 60 seconds.

Related Solutions

  1. LoadLibrary
    I am having some difficulty with the LoadLibrary function in the Windows API. When I try and load a dll (which I made) GetLastError returns 126 but the function DOES NOT return NULL. The documentation identifies this error as RROR_MOD_NOT_FOUND. I was certain I was specifyi...
  2. LoadLibrary
    I am having some difficulty with the LoadLibrary function in the Windows API. When I try and load a dll (which I made) GetLastError returns 126 but the function DOES NOT return NULL. The documentation identifies this error as RROR_MOD_NOT_FOUND. I was certain I was specifyi...
  3. DLL - LoadLibrary
    I am attempting to load a DLL by calling: RasHandle:= LoadLibrary('rasapi32.dll'); However I am getting the error: "Initialization of the dynamic link library <<my fn and path>> failed. The process is terminating abnormally." Would someone plea...
  4. loadLibrary
    Hi All! How can I in JBuilder loadLibrary("someName"); May be I must change some properties. Where I must put my "someName.dll"
  5. LoadLibrary DLL
    when i use the function loadLibrary from the main Application Form , every thing work fine. But when i try to do it from any other "sub form" (i.e. not the main form) I got an access violation error. What could be the reason ?! thank u Asi

Free Tech Articles

  1. WARNING: 5 Reasons why you should NEVER fix a computer for free.
    It is in our nature to love the puzzle. We are obsessed. The lot of us. We love puzzles. We love the challenge. We thrive on finding the answer. We hate disarray. It bothers us deep in our soul. W...
  2. SCCM OSD Basic troubleshooting
    SCCM 2007 OSD is a fantastic way to deploy operating systems, however, like most things SCCM issues can sometimes be difficult to resolve due to the sheer volume of logs to sift through and the dispe...
  3. Migrate Small Business Server 2003 to Exchange 2010 and Windows 2008 R2
    This guide is intended to provide step by step instructions on how to migrate from Small Business Server 2003 to Windows 2008 R2 with Exchange 2010. For this migration to work you will need the fo...
  4. Create a Win7 Gadget
    This article shows you how to create a simple "Gadget" -- a sort of mini-application supported by Windows 7 and Vista. Gadgets can be dropped anywhere on the desktop to provide instant information, ...
  5. Outlook continually prompting for username and password
    There have been a lot of questions recently regarding Outlook prompting for a username and password whilst using Exchange 2007. There are a few reasons why this would happen and I will try to cover t...
  6. Backup Exchange 2010 Information Store using Windows Backup
    There seems to be quite a lot of confusion around the ability to backup Exchange 2010 using the built in Windows Backup feature. This stems from the omission of this feature prior to Exchange 2007 s...

Cloud Class Webinars

  1. Avoiding Bugs in Microsoft Access
    Alison Balter takes and in-depth look at avoiding bugs in Access. In this webinar you will learn about using the immediate window to debug your applications, invoking the debugger, using breakpoints to troubleshoot, stepping through code, setting the next statement to execute, ...
  2. Top 10 Best New Features in Visio 2010
    Scott Helmers gives live demonstrations of the top 10 new features in Visio 2010. This webinar will teach you how to create compelling diagrams by adding shapes to the page with a single click, linking the shapes in a diagram to data in Excel (or SQL Server, or SharePoint), ...
  3. IT Consultant Business Secrets Revealed
    Michael Munger, Experts Exchange tech pro and IT consultant, pulls back the curtain on his very successful businesses and answers question on every IT consultant and business owner should know about. He shares secrets on what he did to solve the 5 most common problems in IT, ...
  4. Disaster Recovery and Business Continuity
    Quest CTO, Mike Billon, gives an overview of the steps involved in building a dunamic disaster recovery plan. Through case studies and an examination of software/hardware tooles for monitoring and testing, you'll gain a better understandin of where you are, where you want ...
  5. Organize Your Visio Diagrams with Containers and Lists
    Scott Helmers uses cross functional flowcharts, wireframe diagrams, data graphic legends and seating charts to teach you: how to ustilize all three new structured diagram components in Visio 2010, the best practices for organizeing shapes in previous version of Visio, how to organize ...
  6. How to Us Objects, Properties, Events and Methods in Microsoft Access
    Alison Dalter gives an in-depbth look at objects, properties, events and methods in Microsoft Access. In this webinar you will learn about using the object browser, referring to objects, working with properties and methods, working with object variables, understanding the ...

Join the Community

Give a Little. Get a Lot.

Join the community of experts here and help other tech pros by answering question in your area of expertise. You can earn FREE access to all Experts Exchange's premium features and resources.

Join the Community

Answers

 

by: jhancePosted on 2001-08-15 at 18:54:56ID: 6391123

This is an interesting question....

Perhaps you could comment on why you are wanting to do this.  Knowing what you are trying to do might spur some alternate ideas into my mind.

 

by: shrifPosted on 2001-08-15 at 18:59:17ID: 6391129

I need to download a DLL from a web site on an Intranet and call an exported function in it.  The client cannot leave temp files around.

 

by: jhancePosted on 2001-08-15 at 19:08:57ID: 6391142

>>The client cannot leave temp files around.

Why not?  Most systems today have megabytes of temp files lying about all over the place.  

I also don't understand why you can't delete the DLL when you are finished with it.  The file should be free to be deleted after you call FreeLibrary() on it.  But I'll have to admit that I've not tried this.

 

by: shrifPosted on 2001-08-15 at 19:19:55ID: 6391159

You know what, this is why I didn't originally state the reason behind it.

I am looking for a technical solution not someone's opinion of what I ought to do or not do.  Keep your opinions to yourself if you don't have a constructive solution to my problem.

I am only looking for technical answers -- I am not interested in whether you feel I should or shouldn't do something.

Thank you!

 

by: MadshiPosted on 2001-08-15 at 23:47:51ID: 6391576

>> 3.  Use INJLIB or Microsoft's own "Detours" library to trap calls the CreateFile (or whatever) [...] NEGATIVES: The "Detours" library can't be used to do this on non-NT systems.  INLIB can be used, but the versions that are currently available on the Net (from May '94 issue of MSJ) only supported NT (no Windows 95 back then).  The author of INJLIB supposedly has updated INJLIB to work under newer Win32 OSs, but I can't seem to find that anywhere.

Look here for my package, which is something like DetoursEx for winNT/2k/XP/9x/ME:

http://help.madshi.net/Data/madCodeHook.htm

The documentation is for the Delphi version of my package, but it's also available for ya C++ programmers.

However, I'm not sure how many APIs you will have to hook in order to get this whole thing running. LoadLibrary really goes VERY deep... CreateFile is only one part of it. As far as I know CreateFile internally uses memory mapped files for loading dlls - and as far as I know, it doesn't call CreateFileMapping, but instead an internal function, something like InternalCreateFileMapping, which is not exported...   :-(

>> 4.  Write the memory contents to disk and then call LoadLibrary. NEGATIVES:  There's no way to delete the file after calling LoadLibrary on it.  At least it didn't
work when I tried it (yes, I called FreeLibrary on it.)

This is exactly the point where we should work at. Normally when you load a dll and then unload it again, you *CAN* delete it. I'm 100% sure about that. There can be several reasons, why it's different in your case:

(1) Maybe the dll called LoadLibrary for itself, so your FreeLibrary call only deferenced the loader count, but didn't really unload the dll. Please check GetModuleHandle after having called FreeLibrary to make sure the dll is really detached from your process.
(2) Maybe the dll is loaded into other processes. This can be the case if the dll is using SetWindowsHookEx or other methods to go into remote processes.
(3) Maybe the dll uses some APIs which are very sensitive. E.g. if your dll uses MCI and doesn't cleanly uninit it, the dll remains in use until the next reboot.

I would suggest investing time into finding out why you can't delete the dll - because you should be able to. And that would be absolutely the easiest and best solution for you. No hacking into deep system APIs...

Regards, Madshi.

 

by: shrifPosted on 2001-08-16 at 00:09:21ID: 6391614

Regards,
    Thanks.  I'll give you more info on not being able to delete the DLL.  Okay, the new DLL is called temp.dll.  I have another DLL call main.dll.  Say a process implictly loads main.dll (by linking to main.lib, the import library).  When the process is invoked, main.dll's DllMain() gets called.  In there, in the "process attach", I create temp.dll and call LoadLibrary on it, caching the returned hinstance.  When the process terminates, it calls main.dll's DllMain() with "process detach".  In there, I call FreeLibrary on the cached hinstance of temp.dll and verify that no one else has the DLL loaded.  Right after the call to FreeLibrary, I attempt to delete temp.dll, but it fails.  However, if the process invokes some well-known routine in main.dll, which in turns does the same logic as above, calling FreeLibrary on the hinstance, then temp.dll *can* be deleted.

I believe that the same behavior occurs when the process loads main.dll explictly (via a call to LoadLibrary).

Now, I did this first about 6 years ago and at the time I was testing under NT 3.51 and the newly released Windows 95 and don't recall if the behavior was on both systems.  Suffice it to say, the solution should work on all Win32 systems.

Thanks for madCodeHook -- I'll check it out.

 

by: FengYuanPosted on 2001-08-16 at 00:22:53ID: 6391645

5. Simulate LoadLibrary on the DLL yourself.

   5.1 Allocate a big enough virtual memory block, preferably at the preferred address of the DLL.
   5.2 Unpack the DLL into the memory, according to section alignment. Patch relocation if relocated.
   5.3 Load new DLLs needed by the DLL (use normal LoadLibrary).
   5.4 Patch DLL's import table.
   5.5 Call DLL's entry point.

www.fengyuan.com

 

by: shrifPosted on 2001-08-16 at 00:30:37ID: 6391664

FengYuan,
     I'm not sure if reimplementing much of the loader is really the best strategy -- I wouldn't really know where to start doing something like that.

 

by: MadshiPosted on 2001-08-16 at 00:41:50ID: 6391684

>> In there, I call FreeLibrary on the cached hinstance of temp.dll and verify that no one else has the DLL loaded.

Please call GetModuleFileName(cachedhinstance) before calling FreeLibrary to verify that the cached hinstance is correct (probably it is, just to be sure). Then please after having called FreeLibrary call GetModuleHandle('test.dll') to check whether the dll is still loaded. It should not.

>> Right after the call to FreeLibrary, I attempt to delete temp.dll, but it fails.

What does GetLastError say?

Regards, Madshi.

 

by: MadshiPosted on 2001-08-16 at 00:44:47ID: 6391694

Hi FengYuan,

hmmm... what if the dll internally calls GetModuleFileName with its own HInstance value to find out the full path where the dll file is loaded from? That call would fail, would it not? I mean, your suggestion is not guaranteed to work with all dlls, some dlls might not work correctly because GetModuleFileName (and related APIs) fail, or am I wrong? Apart from that I do like your suggestion...

Regards, Madshi.

 

by: shrifPosted on 2001-08-16 at 00:48:37ID: 6391705

I like it!  I'll try this out in a test project and let you guys know.

 

by: ZoppoPosted on 2001-08-16 at 01:05:53ID: 6391755

Hi shrif,

I don't know which OS you're working on, but in following article it's mentioned that
at least with Win98 you can't call FreeLibrary() within DllMain within DLL_PROCESS_DETACH:
http://support.microsoft.com/support/kb/articles/Q214/7/84.ASP

hope that helps,

ZOPPO

 

by: MadshiPosted on 2001-08-16 at 01:32:23ID: 6391807

Good link, Zoppo! What does that mean? It's evidently not recommended to do any LoadLibrary/FreeLibrary calls in DllMain within PROCESS_ATTACH/DETACH events. So the solution to the problem is "simply" to do the loading & freeing at another location in your program.

Regards, Madshi.

 

by: jhancePosted on 2001-08-16 at 03:17:27ID: 6392088

>>>I am looking for a technical solution not someone's
>>>opinion of what I ought to do or not do.  Keep your
>>>opinions to yourself if you don't have a constructive
>>>solution to my problem.

>>>I am only looking for technical answers -- I am not
>>>erested in whether you feel I should or shouldn't
>>>do something.


Well just EXCUSE ME for trying to understand your problem and help!@


 

by: FengYuanPosted on 2001-08-16 at 10:33:38ID: 6393880

6. Dummy DLL.

   6.1 Wipe out code/data in the DLL.
   6.2 Write to disk.
   6.3 LoadLibrary the DLL.
   6.4 Restore old code/data.

www.fengyuan.com

 

by: ShaunWildePosted on 2001-08-16 at 14:57:10ID: 6394922

I just ran the following code snippet

#include "stdafx.h"
#include <windows.h>

int main(int argc, char* argv[])
{
     ::CopyFile("dllunload.dll","dlltemp.dll",FALSE);
     HMODULE hModule=::LoadLibrary("dlltemp.dll");
     ::FreeLibrary(hModule);
     ::DeleteFile("dlltemp.dll");
     return 0;
}


and the dlltemp was unloaded fine and deleted.

 

by: NickRepinPosted on 2001-08-18 at 22:13:57ID: 6402905

Most easiest way, not elegant though - just because the Windows does not allow to do anything else.

In DLL_PROCESS_DETACH, create the .BAT file and call CreateProcess() on it.

-----------------
@echo off
again:
del drive:\path\temp.dll
if not exist drive:\path\temp.dll goto quit
echo waiting
echo waiting
... several times
echo waiting
echo waiting
goto again

quit:
del drive:\path\nameOfTheBatFileItself.bat
--------------

This BAT file will delete the DLL first, then itself second.

 

by: NickRepinPosted on 2001-08-18 at 22:37:51ID: 6402921

There is no way to really free another dll inside DLL_PROCESS_DETACH, so the bat file is the only option, in my humble opinion. CreateProcess() should use DETACHED_PROCESS of course.

This solution is a universal one for any vesion of Windows, and it is much more reliable that any API interception - detour etc.

Of course if you have time you can improve your skills by writting URL monikers or network redirectors. The only disadvantage is that they are separate programs that need to be distributed, installed etc.

As to the memory-based DDLs, I wish this could be possible. Unfortunately the 100% emulation is not possible, at least without a need to hack Windows. It means this way is not reliable as well.

 

by: shrifPosted on 2001-08-18 at 22:53:51ID: 6402939

Thanks Nick.
The batch file way is my current approach.  I actually use a tiny win16 program that gets launched and waits and tries 256 times to delete a given exe.  It's win16 because the same solution was used for both win16/win32 programs (yes, this is old code.)

 

by: shrifPosted on 2001-08-18 at 22:54:28ID: 6402940

Madshi,
     Your madCodeHook looks pretty awesome.  I'll give it a try.  If it works, I'll use that approach.  I'll let you know.

Thanks.

 

by: shrifPosted on 2001-08-18 at 23:06:07ID: 6402960

Madshi,
     Your madCodeHook looks pretty awesome.  I'll give it a try.  If it works, I'll use that approach.  I'll let you know.

Thanks.

 

by: ShaunWildePosted on 2001-08-19 at 01:56:48ID: 6403146

my earlier code snippet - shows that FreeLibrary does unload the dll - I even experimented by adding GetProc addresses and calling code before calling FreeLibrary - still unloaded and deleted.

do you have anything else in your code keeping the library loaded or file locked? Have you closed all the handles that you used to create the file on the disk?

 

by: shrifPosted on 2001-08-19 at 08:00:52ID: 6403696

Shaunn, when you posted the comment of which you speak, it was obvious that you didn't read the previous comments because there I explained the conditions under which FreeLibrary wasn't working with me.  I didn't bother to respond to you because I just got through explaining it in a comment prior to yours.

Then, another user, Zoppo, confirmed my findings by posting the knowledgebase article describing the scenario.

Did you miss that comment, too?

 

by: MadshiPosted on 2001-08-19 at 08:58:21ID: 6403831

Some thoughts:

(1) Are both the process and the main.dll written by you? Then why don't you simply export a function from main.dll, which unloads and deletes test.dll. You can then call this exported function from the process, before you close the process. That would be by far the easiest and cleanest solution (at least IMHO).

(2) If you want to play with madCodeHook, I would suggest using a different approach then the one you thought about. Simulating a DLL load from memory is too difficult, I think. Why not hooking PostQuitMessage and ExitProcess? You can then in the callback function unload the test.dll and delete it - and then thereafter call continue with PostQuitMessage/ExitProcess. However, I think this is overkill. I like (1) much more. Or alternatively Nick's batch solution.

Regards, Madshi.

 

by: MadshiPosted on 2001-08-19 at 09:00:04ID: 6403837

Shaun, as far as I understand your code (I'm not too sure, because I'm a Delphi programmer) you're doing all the stuff in the initialization of an application. The problem that shrif has occurs in the finalization of a dll. That are quite different things.

 

by: ShaunWildePosted on 2001-08-19 at 10:31:07ID: 6404023

Shrif

> it was obvious that you didn't read the previous
> comments because there I explained the conditions under
> which FreeLibrary wasn't working with me

I was responding to the comment

<snip>

4.  Write the memory contents to disk and then call LoadLibrary.
   NEGATIVES:  There's no way to delete the file after calling LoadLibrary on it.  At least it didn't
work when I tried it (yes, I called FreeLibrary on it.)

</snip>


the fact I missed your ramble about app -> dll -> dll - was due to the fact I didn't refresh seeing the question - and then posting the comment

However since the comment about not using FreeLibrary in DllMan is mentioned in the helpfile see FreeLibrary (which I assumed you read) and that you didn't respond to Zoppos comment - I assumed that it didn't apply in your case

so no it wasn't obvious that I hadn't read the above comments quite the opposite - I had read them but misinterprted you lack of response to other comments

The fact is you might as well do what madshi suggested and rework your code - something jhance would have mentioned earlier - eg tell us what you want to do and we'll see how to do it - rather then go a really complex route - a slight rework of your code would be a lot easier


 

by: NickRepinPosted on 2001-08-20 at 00:36:27ID: 6405306

There is another possibility, but it is a hack.

UnmapViewOfFile(LPCVOID(hTempDll));
CloseHandle(hSomeInternalFileHandleForTempDll);
DeleteFile("temp.dll")

hSomeInternalFileHandleForTempDll is a file handle which is obtained via CreateFile("Temp.Dll") by Windows loader. It is possible to enumerate all opened handles and find the handle which is associated with a given file name.

 

by: NickRepinPosted on 2001-08-20 at 01:33:22ID: 6405456

This works on my NT4

#include <windows.h>
#include <iostream.h>
#include <conio.h>

void main()
{
   HINSTANCE hTempDll=LoadLibrary("b.dll");
   if(!hTempDll)
   {
      cout<<"Cannot load DLL"<<endl;
      return;
   }

   CHAR buf[MAX_PATH];
   GetModuleFileName(hTempDll,buf,sizeof(buf));

   if(!DeleteFile(buf))
   {
      cout<<"1st DeleteFile failed - as expected"<<endl;
   }

   UnmapViewOfFile(hTempDll);
   
   if(DeleteFile(buf))
   {
      cout<<"Deleted!"<<endl;
      FreeLibrary(hTempDll);
   }
}

 

by: shrifPosted on 2001-08-20 at 20:53:42ID: 6408475

Holy smoke, Nick!  That's incredible.

Do you want a job?

:)

Thanks.  Let me give this a shot and I'll get back to you.

20120131-EE-VQP-002

3 Ways to Join

30-Day Free Trial

The Experts

98% positive feedback on 31,087 answers since March 2000. angeliii is a Microsoft Most Valuable Professional for his work with MS SQL Server & Develoment.

He has also proven his knowledge of Visual Basic Programming, PHP Scripting and Oracle Databases.

The Experts

97% positive feedback on 10,752 answers since July 2000. lrmoore has more than 18 years experience in the networking industry.

The six-time Mircosoft MVPs specialties include firewalls, virtual private networking, and network management.

Testimonials

"...and excellent source for support... Kind of like having your very own IT dept." Electriciansnet

Testimonials

"I was apprehensive at signing up at first. However... it has already made my life as an IT administrator much easier." JaCrews

Testimonials

"WOW! You guys have great, active, and knowledgeable people on here." moore50

Business Clients

Business Clients

In the Press

"If you’ve got a question... Experts Exchange can supply an answer.”

In the Press

"...an invaluable aid for both IT professionals and those who require tech support."

In the Press

"where IT professionals provide quick answers on just about any topic"

Business Account Plans

Loading Advertisement...