How can I debug a referenced DLL file from Visual Studio 2013? - vb.net

To start, I know this question has been asked a million times all over the place, but as I have no experience with VB/Visual Studio, I can't find a solution that I can make sense of.
I am creating a new VB.net project(solution?), and am making calls to functions from a C library that are in a dll file. The dll file does have a pdb file and they are both stored at the same location.
In the code below it shows how I declare the functions in my VB.net code, but I have not figured out how to attach the pdb file to the project.
Declare Function InitRelay Lib "Z:\Devel\RelayAPI\Debug\RelayAPI.dll" (ByVal setbaud As Action(Of Short), ByVal getit As Func(Of Short, Short), ByVal putit As Action(Of Short), ByVal flushit As Action, ByVal delay As Action(Of Short)) As Byte
Declare Sub FreeRelay Lib "Z:\Devel\RelayAPI\Debug\RelayAPI.dll" ()
...
I am getting an exception somewhere in the DLL file, but the way I have it set up, I can not debug the dll file. Whether its adding breakpoints, or print statements, I need a way to see where in the dll the project fails.
Questions I have looked at:
How to debug a referenced dll - I tried following the menu path given in the accepted answer, but when I go to Project >> Project Properties I see no Build option. It also says I can load symbols directly in the IDE if I don't want to copy any files, but I cannot find an explanation on how to do it. EDIT - As Plutonix says below, C# Build is the equivalent of VB's Compile tab. I checked and my Debug Info is set to Full, so this does not solve my problem.
Debugging a third-party DLL in Visual Studio? - This talks about a DLL in a .NET language but mine is in C. It also only tells you how to view the code, which I already can do. I have access to the .c and .h files that are used to create the dll, I just cannot debug them at runtime.

When you debug a DLL, you can start debugging from:
The project used to create the executable that calls the DLL.
- or -
The project used to create the DLL itself.
There are a couple of ways to debug a reference DLL file using VS 2013, so here the method Microsoft uses
-->To specify an executable for the debug session
In Solution Explorer, select the project that creates the DLL.
From the View menu, choose Property Pages.
In the Property Pages dialog box, open the Configuration Properties folder and select the Debugging category.
In the Command box, specify the path name for the container. For example, C:\Program Files\MyApplication\MYAPP.EXE.
In the Command Arguments box, specify any necessary arguments for the executable.
Here I included 2 different methods for debugging a DLL file directly from Microsoft.
1> http://msdn.microsoft.com/en-us/library/605a12zt.aspx (Native Mode)
2> http://msdn.microsoft.com/en-us/library/kbaht4dh.aspx (Mixed Mode)
If this was anyhelp to you or solved your problem please make sure to drop a "vote up"
Ref. All information is from personal experience and Microsoft

Related

How to debug VC++ dll in VB6

I tried a few different ways, but none of them works.
Method 1 I tried:
Start the VB program and run until before the DLL runs.
Open VC++ (no project) and select Build | Start Debug | Attach to Process
Attach to the VB program
Open the DLL source code file in VC++, select a breakpoint in the code.
Continue running the VB program, and it didn't jump to the VC++.
Method 2 I tried:
"After a long struggle found the answer for this. Actually we have to give the path of VB6.exe in the Projects->settings->debug->category->general->Executable for debug session.Then when you try to debug the VC++ dll by having a breakpoint in the function that needs to be checked,a new VB6 IDE would be opened.There please select the VB6 Dll project that actually calls the VC++6 dll. run that application and when the function call to the VC++6 comes in the VB6 function, automatically the control goes to the VC++ IDE and you can debug it as usua" From MSDN---->It just went to the next line of code in VB application, didn't go to the VC++ IDE like method 1.
The VB application declares dll file like this:
dim query as object
query=CreateObject("ClientServer.getResultClass")
query.execute(parameter1,parameter2)
I'm not sure if I need to put the debug dll into a specific place or I may need to register the debug dll file (I checked gedit, the ClientServer.getResultClass is registered).
You're on the right track with Method 1. You need to make sure you attach the 'Native' debugger, and that the DLL includes debug info, and that the source code matches the DLL. If all three conditions are met, it should work. Note that it's almost always necessary to use a freshly built DLL to ensure that the third condition is met.

VBA Excel Cannot find DLL

I am currently trying to add control to a Power Analyzer in an excel tool. The company provides USB drivers and the appropriate modules and DLLs. I added the DLLs to the System32 folder to ensure they were read in the path. After importing the modules and trying to run the program, I get the error "File Not Found". I then tried to hard code the location of the DLL and I received the same error.
I've looked around the internet and the only issue I could find was possibly a dependency missing from the DLL. An example of the line I'm trying to use is:
Declare Function TmSend Lib "tmctl.dll" (ByVal id As Long, ByVal msg As String) As Long
This line is apart of the module provided by the manufacturer. Is there something I'm missing to get this to work? I want to make sure before I contact the manufacturer.
EDIT:
It appears that the manufacturer uploaded a corrupt DLL causing the issue to arise. When checking the file with Dependency Walker, it failed to even read the DLL.
I see from your question that you've tried all the normal things (making sure the dll is on your path &c.)
You now need to examine the dll carefully. Download this: http://www.dependencywalker.com/
Then use it to open your dll. All the missing dependent dlls will be clearly displayed. Put those on your path too and you're done.
(To clear up some confusion: you will not need to register this dll or add a reference to it.)

"run-time error '453' can't find dll entry point" from vb.net compiled dll referenced by vba

I am coding in vb.net through visual studio 2008. I have successfully compiled a dll file from my code but I continue to get "Run-time error '453'" when I try to reference the dll in vba. I understand there is some sort of compiling error that occurs when using vb.net. Does anyone have any suggestions to fix/overcome this issue? I would like to avoid translating the code to another language as much as possible.
Here is a simple sample code that I have been trying to get functioning:
Example.dll:
Public Class Class1
Function Square(ByVal x As Double, ByRef y As Double)
y = x * x
Return 0
End Function
End Class
Macro in Example.xlsx:
Private Declare Function Square Lib "\Example.dll" (ByRef x As Double, ByRef y As Double)
Sub Test()
Dim x, y As Double
x = 2
y = 0
Call Square(x, y)
MsgBox (y)
End Sub
Thank you,
Katlynn
Ok, a truckload of issues here and assumptions are incorrect.
First up, when you use declare in VBA to a .dll, you cannot use relative path names.
So you have:
Private Declare Function Square Lib
"\Example.dll" (ByRef x As Double, ByRef y As Double)
You can’t use \Example.dll
You have to specify the FULL path name. Eg:
C:\mytestApp\Example.dll
So even if vb.net did produce a working .dll, you have to use a full path name – no relative path name is allowed.
You can place the .dll in the standard windows path names that are searched for .dll’s (so c:\windows\system32), and thus NOT have to use a full path name.
However, these days with security, adding or just tossing a .dll into a windows system folder tends to have a LOT of security issues and HUGE hassles. (windows makes this hard, and so does any virus software). So you have to use a full path name.
Next up:
Using declare in VBA is a means to call the windows API, or what we call windows x32 bit library code. This is not COM (ActiveX), but has to be raw windows x32 (or x64) native windows code.
So this is not a ActiveX, or “com” object, but raw code that you call. A standard vb.net (or any .net language) does NOT produce windows native code. The correct term is
Managed code = .net code. This code is NOT native windows code.
Un-managed code = raw windows code.
So you have to create un-managed code to use DECLARE in VBA.
So you have to use:
X86 assembler
C++
VB6
Or ANY development tool that can produce raw x32 (or if using access x64, then raw x64 native windows code).
In visual studio these days you "can" produce native windows code, but you have to use un-managed code, and that thus means c++. (c#, or vb.net don't produce native code or dll's).
So you can use c++, or VB6 or even a assembler to create these .dll’s.
Such .dlls do NOT require registration. And as noted you don’t create an “instance” of the object in VBA code, but call it directly.
These types of .dll’s (simple external library code calls) thus do not appear as a COM object. And if you in VBA editor go tools->references, then you not see these libraries appear. However, they can be ease to use, since you don't have to create a instance of the object I VBA code - you just call such code like your example.
Because the path name is hard coded with this approach, then it often a pain to use the DECLARE statement (since it is determined at VBA compile time, and not runtime). This would mean you have to place that .dll in the SAME location for each computer you deploy to. If you move or change the folder, then your code would fail.
To get around this issue, you can use the LOADLIBARY call in VBA. This will allow you at runtime to set (determine) the location of the .dll. So most developers will thus simple place the .dll in the SAME folder as the running application (same folder as the Access or in this case Excel file).
However, this assumes you create a standard windows .dll.
Can I create such native windows .dll’s in .net with vb.net?
It turns out you can with some external add-in’s for VS. I often use this approach to create these dll’s, since then I don’t have to build COM interface code, and it is VERY simple to use.
I then combine the above with VBA using a LOADLIBRARY call, and that works quite well. So in VS you can use a NuGet package (add in) and pick a .dll export add-in utility. There are several, but I used the RGeseke DLLimport with great success. These are free 3rd party choices here.
While the above reduces some hassles, you will have to adopt the VBA loadlibrary code to make this a practical choice (or always place the .dll in the same location). I also recommend this approach if you have some existing .dll’s, and want to interface to that code but don’t want to learn say c++. So I do use this approach to consume existing dll’s in vb.net, and thus in turn from Access. In effect this trick allows you to write interfaces to windows .dll code in a nice familiar language like vb.net.
However, if you not used LOADlibrary from VBA (and VB6) in the past, and are not up to speed, then I will suggest you choose the next option.
Creating COM (ActiveX) from vb.net
This is likely the best approach. And it is the most common approach. However, you have to trade off having to create a COM object in vb.net, and THEN register it on the target computer.
So, the only hassle is this requirement to register the .dll on the target computer.
Having to register (regasm.exe) the COM object on the target machine often requires elevated rights. And with companies so security conscious these days, then this installing requirement can be a hassle, but it still likely the best option.
Here is a working example of your code in vb.net.
Imports System.Runtime.InteropServices
<ClassInterface(ClassInterfaceType.AutoDual)>
Public Class Class1
Function Square(ByVal x As Double) As Double
Dim y As Double
y = x * x
Return y
End Function
End Class
Note the above including of interop, and the autoDuel setting in code. This is what allows .net to create a standard windows COM object interface that can be consumed by VBA, VB6, windows scripting, or just any platform that supports COM objects.
Settings you need for this to work:
FORCE the .net project to x86. (you using Excel x32).
So in VS go build->configuration manager. Click on platform in the grid, and choose new, choose x86 and click ok.
You should now have this:
Next up, ensure that the project is made com visible. This check box is USUALLY checked for you by default. All .net classes tend to be marked this way. But I seen it become un-checked when you mess with the previous step of changing the build to x86. So do a quick look at this setting.
Project->properties
Now on Application area, click on assembly information box.
You need to ensure this check box is set:
So above takes only a few seconds.
So check the above (they are usually are already set for you).
Next, we have to tell VS to register this COM object on our development computer. (this is that regasm.exe requirement).
So, in compile area, check this box:
Now, the above check box in VS is ONLY for your development computer and convenience. It simply does a regasm for you, and this is the magic that exposes the class as a COM object for use in VBA or ANY system that supports COM.
Note that the above check box is ONLY for your convenience on your development machine. It does NOT change, modify or do ANYTHING to the code or project.
Now to deploy this code to other machines, you have to provide a batch file or some other means to execute the regasm.exe command. As I pointed out, these does make deployment a greater hassle then the .dll approach, but you trade off other ease of coding here.
As this point, compile (build) the above.
Once you done so, you find now in the VBA editor, you can go tools->references and you find your project as a registered COM object for consuming in VBA.
You see this: (my project was call Testcom2.
And note that once you do set this reference, you MUST EXIT excel if you make changes or re-compile the .net project. (because EXCEL will have locked and have that .dll in use once you set this reference). So just remember if you going to re-compile the .net code, make sure you exit Excel.
And I changed you code a bit, since a function returns a value, and you always returning 0. You could use a call and use a Sub if you wanted, but you HAVE function defined in vb.net and did not define a sub.
So in VBA, we now have this:
Sub TEst55()
Dim cMySquare As New TestCom2.Class1
Dim a As Double
Dim b As Double
a = 10
b = cMySquare.Square(a)
Debug.Print b
End Sub
Note how even intel-sense works as I type, so the function show up as a method in VBA.
And even the types and parms show up while you type in VBA such as:
And hitting f5 in VBA to run the code, we get this as output:
100
Its been a while since I've done this so I'm not sure if its necessary anymore but did you try adding all of the COM attributes?
http://support.microsoft.com/Default.aspx?kbid=817248

VB6 API Declaration Path

I have the following declaration in a Module:
Private Declare Function gzopen Lib "ZLIB.DLL" (ByVal filePath As String, ByVal mode As String) As Long
The following code line in a function fails, with a 'File Not Found: ZLIB.DLL' error:
lGZFileHandle = gzopen(sPath, "rb")
I'm aware that ZLIB doesn't need to be registered. My question is, where does ZLIB.DLL need to live in order for my code to work? I also know that this code is working on another machine. Currently I have ZLIB.DLL in the same folder as the application exe.
UPDATE
To my relief, the code does work when compiled. But does not work whilst running in the IDE (it does on a different machine). I still have ZLIB.DLL in the application folder.
This means that the application path must be being checked for loading the DLL.
To get around this I have tried:
Private Declare Function SetDllDirectory Lib "Kernel32" Alias "SetDllDirectoryA" (ByVal path As String) As Long
and then in the function:
SetDllDirectory App.path
This seems to allow the DLL to load, but I then get a 'Bad DLL calling convention' error instead. The plot thickens.
SOLVED
The answer seems to be here: http://www.zlib.net/DLL_FAQ.txt. It's a case of RTFM I suppose.
So, bizzarely whilst in the IDE, the STD_CALL convention is in force, but once compiled the C style calling convention suffices. It still doesn't explain why it works on a different machine in the IDE. Ho hum.
Thanks all for pointing me in the right direction.
VB6 strayed a bit from the search protocol suggested by Ken (this link is the quick reference).
The usual problem is that the .exe path (search location #1 on the list) is not the path of your VB program, but rather the VB6 IDE. So putting the DLL in the location of your VB program is no good -- unless you change the 'Start In' location of your VB6 shortcut to point to that location.
Alternately, you can put the DLL in one of the other locations specified in my link.
When running through the Visual Studio IDE, all relative files need to be placed in the following folder:
C:\Program Files\Microsoft Visual Studio\VB98\
This is because the exe that is running while debugging resides in that folder. This will allow you to debug without changing any paths.
ZLib has to be in the standard DLL load search path. See the MSDN LoadLibrary documentation for specifics on the way DLLs are found and the order of the search for them.
Are you sure ZLIB doesn't have to be registered?
I suggest you register it and try again.
EDIT
Try putting the DLL in your System folder. I believe your program will check there for it.

add custom DLL search path # application startup

I'm racking my brain trying to come up with an elegant solution to a DLL load problem. I have an application that statically links to other lib files which load DLLs. I'm not loading the DLLs directly. I'd like to have some DLLs in another folder other than the folder that the executable is in. Something like %working_folder%\dlls - I'd rather not have dozens (yes ... dozens) of DLLs in my %working_folder%.
I'm trying to develop something that is part of the main app that will adjust the search path # startup. The problem I'm running into is that this new custom DLL path isn't in the system search path. When I start the app it crashes (STATUS_DLL_NOT_FOUND) because the necessary DLLs are not in the appropriate places. What I'd like to do is to check # startup if this new custom DLL folder is in the process environment variable search path and if not add it. Problem is, the application attempts to load all these DLLs before the app executes one line of code.
How do I fix this? I've considered writing a help app that starts first, adjusts the environment variables appropriately and the launches the main app via CreateProcess. This will work I'm sure of it but it makes things difficult on the developers. When they debug the main app they're not going to launch a helper app first - not that they could even do that.
I've tried the registry app path feature with no success. Same chicken and egg problem as before.
What can I do here?
I found Matthew's answer worked for me.
In visual studio 2012 goto your project properties and in
Configuration Properties->Linker->Input->Delay Loaded Dlls
add each dll file that you want to not load until needed.
Although it no longer needs to run before main, this is my code to set the new search path
class RunBeforeMain
{
public:
RunBeforeMain()
{
const TCHAR* dllPathEnvName= name of env variable to directory containing dlls
const TCHAR* pathEnvName= TEXT("Path");
TCHAR newSearchPath[4096];
::GetEnvironmentVariable(dllPathEnvName, newSearchPath, MAX_PATH);
//append bin
_tcscat_s(newSearchPath, MAX_PATH, TEXT("bin;"));
size_t length = _tcslen(newSearchPath);
//append existing Path
::GetEnvironmentVariable(pathEnvName, newSearchPath + length, 4096-length);
::SetEnvironmentVariable(pathEnvName, newSearchPath);
}
};
static RunBeforeMain runBeforeMain; //constructor code will run before main.
[Edit - after re-reading the question I see that the problem you're having is that the DLLs are getting loaded before main starts]
I'm guessing that those libraries are written in C++ and are loading the DLLs from the constructor of some objects in global scope. This is problematic. Allow me to quote Yossi Kreinin:
Do it first thing in main(). If you use C++, you should do it first thing before main(), because people can use FP in constructors of global variables. This can be achieved by figuring out the compiler-specific translation unit initialization order, compiling your own C/C++ start-up library, overriding the entry point of a compiled start-up library using stuff like LD_PRELOAD, overwriting it in a statically linked program right there in the binary image, having a coding convention forcing to call FloatingPointSingleton::instance() before using FP, or shooting the people who like to do things before main(). It’s a trade-off.
[Original answer below]
See this page for the search algorithm used for loading DLLs. You can use SetDllDirectory() to add a directory to the DLL search path.
You also should be able to add a directory to the PATH environment variable using GetEnvironmentVariable() and SetEnvironmentVariable().
Another option is to change the current working directory to the folder containing the DLLs with SetCurrentDirectory(). Just make sure to change the working directory back after loading the DLLs if you ever load any files using relative filenames.
My recommendation is to use delayload linking for the DLLs and call SetDllDirectory() early enough so it can find them when the methods/functions are invoked.