I am having a problem. The following code should output a single line describing my local instance of SQL. After lots of poking and prodding I have found that the code succeeds when it is compiled with the "Target Framework" set to v3.5, but it fails to return any instances when the "Target Framework" is set to anything higher. There is no error, exception, warning or other explanation. I know that it is not simply taking longer to find the instance because it reaches the final "Console.Readkey()" within .04 seconds when the target is v3.5.
I suppose what I really want to know is: How can I make this work without changing the Target Framework? I would rather not if I don't have to since I have written the rest of my project under the default (v4.5.2) and don't know what consequences might arise from doing so.
P.S. Bonus points if you can tell me why this doesn't work after v3.5.
Module Module1
Sub Main()
Dim datatable As DataTable = System.Data.Sql.SqlDataSourceEnumerator.Instance.GetDataSources()
For Each row As DataRow In datatable.Rows
For i As Integer = 0 To (datatable.Columns.Count - 1)
Console.Write(row.Item(i) & vbTab)
Next
Console.WriteLine()
Next
Console.ReadKey()
End Sub
End Module
Unfortunately, you appear to be experiencing this reported bug.
If it looks like the bug report matches your problem, consider voting to have it fixed.
I am trying to get the installation path of Office programs as this microsoft kb article suggests (since Office start menu shortcuts don't point to paths anymore; thank you Microsoft).
Of course, the KB example uses C++ and native libraries, which I tried to replicate in VB.NET with the following code
<Runtime.InteropServices.DllImport("msi.dll")> Public Shared Function MsiLocateComponent(szComponent As String, ByRef lpPathBuf As Char(), ByRef pcchBuf As Integer)
End Function
I call this function from the following, which I expect to return a message box with at least the dot (if the rest fails). Instead, I get nothing at all, so I assume that the code runs into some sort of error (which is silent though because I get no exception).
Shared Function DealWithWinInstallerPath(ProgramPath As String) As String
Dim sPath(300) As Char
Dim sSize As Integer = 300
Dim state As Integer = MsiLocateComponent("{019C826E-445A-4649-A5B0-0BF08FCC4EEE}", sPath, sSize)
MsgBox(state & ".")
End Function
(Note that the function has an argument that will be used in the future, but its contents are just for testing purposes).
Am I declaring the function incorrectly? Passing the wrong arguments? Is msi.dll not the right name for the library? The msdn database doesn't help much either.
For managed code, the Microsoft.Deployment.WindowsInstaller interop assembly found in Windows Installer XML's (WiX) Deployment Tools Foundation (DTF) is the way to go. DTF's ComponentInstallation class has a read only property called Path that encapsulates the call to MsiLocateComponent()
Once installed, you can find the DLL in C:\Program Files (x86)\WiX Toolset v3.8\SDK.
You can also read through the source code for pointers on how to P/Invoke MSI API calls.
MsiGetComponentPath is preferred if you read the MSDN docs, and there's an interop example here:
http://www.pinvoke.net/default.aspx/msi.MsiGetComponentPath
I need to get code to retrieve the Windows userID for the current session in VB (for Access 2013) on a 64-bit system.
I've tried the solution suggested at How to get logged-in user's name in Access vba?, but apparently this doesn't work on my 64-bit machine. I've also tried to figure out how to integrate the info at http://msdn.microsoft.com/en-us/library/office/gg278832.aspx, but I can't figure it out.
I am a NOVICE VB programmer, so I really need the actual code to do this. (I can [probably] figure out how & why the code does what it does after I see it, but I can't come up with it from scratch at this point.)
I'm hoping this answer will be helpful to others, too.
Thanks so much!
Aloha,
-pt
This should work, too:
Dim wshNet As Object
Set wshNet = CreateObject("WScript.Network")
MsgBox "Hello, " & wshNet.UserName & "!"
Set wshNet = Nothing
The answer you linked to works on a 32 bit version of access. For 64 bit versions, you need to use a pointer-safe signature:
Private Declare PtrSafe Function GetUserName Lib "advapi32.dll" Alias
"GetUserNameA" (ByVal lpBuffer As String, nSize As LongPtr) As Long
(it might work with nSize As Long - I don't have a 64-bit access at hand)
I'm currently working on an application for my personal use. The idea is that you can open it up and reach all kind of stats of your computer (Recycle bin, Drives, Network and much more). Now I was working with the SHQueryRecycleBin from Win API.
Though I have some problems. And I've tried to look over outdated solutions for VB6 or VB.NET solutions that simply didn't work. I used the code reference from this source and to retrieve the size and count of files I used this source.
I put it in an timer, and after those 100 ticks (as I set it) were ran, I got this error:
File I/O of a structure with field 'cbSize' of type 'UInt32' is not valid.
The type of cbSize is UInteger which (apparently) automatic changes to an UInt32 - I think it's based on the system.
You should note that I'm on an Windows 7 x86 (64-bit). If have an solution for this or another piece of code that is easier than use Win API, let me know.
I have looked at the System.Management but wanted an bullet proof code that could interact with most systems.
I don't have vb.net handy to test, but the following code works perfectly well in vb6:
In a module:
Public Type SHRECYCLEBININFO
cbSize As Long
i64Size As Currency
i64NumItems As Currency
End Type
Public Declare Function SHQueryRecycleBin Lib "shell32.dll" Alias "SHQueryRecycleBinA" (ByVal pszRootPath As String, pSHQueryRBInfo As SHRECYCLEBININFO) As Long
And in a form:
Private Sub Command1_Click()
Dim info As SHRECYCLEBININFO
Dim res As Long
info.cbSize = Len(info)
res = SHQueryRecycleBin("C:\", info)
MsgBox "size: " & (info.i64Size * 10000) & " bytes" & vbCrLf & "items: " & (info.i64NumItems * 10000)
End Sub
Note the use of type "currency" - this is because vb6 doesn't have a normal data type for 64-bit integers. Type Currency is using 8 bytes, but keeps 4 decimal places, hence the multiplication by 10000 to get the results.
For a very long time, when I have an error handler I make it report what Project, Module, and Procedure the error was thrown in. I have always accomplished this by simply storing their name via constants. I know that in a Class you get the name programmatically with TypeName(Me), but obviously that only gets me one out of three pieces of information and only when I'm not in a "Standard" module.
I don't have a really huge problem with using constants, it's just that people don't always keep them up to date, or worse they copy and paste and then you have the wrong name being reported, etc. So what I would like to do is figure out a way to get rid of the Constants shown in the example, without losing the information.
Option Compare Binary
Option Explicit
Option Base 0
Option Private Module
Private Const m_strModuleName_c As String = "MyModule"
Private Sub Example()
Const strProcedureName_c As String = "Example"
On Error GoTo Err_Hnd
Exit_Proc:
On Error Resume Next
Exit Sub
Err_Hnd:
ErrorHandler.FormattedErrorMessage strProcedureName_c, m_strModuleName_c, _
Err.Description, Err.Source, Err.Number, Erl
Resume Exit_Proc
End Sub
Does anyone know ways to for the code to tell where it is? If you can conclusively show it can't be done, that's an answer too:)
Edit:I am also aware that the project name is in Err.Source. I was hoping to be able to get it without an exception for other purposes. If you know great, if not we can define that as outside the scope of the question.
I am also aware of how to get the error line, but that information is of course only somewhat helpful without knowing Module.Procedure.
For the project name, the only way I can think of doing this is by deliberately throwing an error somewhere in Sub Main(), and in the error handling code, save the resulting Err.Source into an global variable g_sProjectName. Otherwise, I seem to remember that there was a free 3rd party DLL called TLBINF32.DLL which did COM reflection - but that seems way over the top for what you want to do, and in any case there is probably a difference between public and private classes. And finally, you could use a binary editor to search for the project name string in your EXE, and then try to read the string from the position. Whilst it is frustrating that the names of every project and code module is embedded in the EXE, there seems to be no predictable way of doing this, so it is NOT recommended.
There are several questions here.
You can get the Project Name by calling App.Name
You cannot get the name of the method you are in. I recommend using the automated procedure templates from MZ Tools, which will automatically put in all the constants you need and your headache will be over.
The last piece is possibly having to know the name of the EXE (or lib) that invoked your ActiveX DLL. To figure this out, try the following:
'API Declarations'
Private Declare Function GetModuleFileName Lib _
"kernel32" Alias "GetModuleFileNameA" (ByVal _
hModule As Long, ByVal lpFileName As String, _
ByVal nSize As Long) As Long
Private Function WhosYourDaddy() As String
Dim AppPath As String
Const MAX_PATH = 260
On Error Resume Next
'allocate space for the string'
AppPath = Space$(MAX_PATH)
If GetModuleFileName(0, AppPath, Len(AppPath)) Then
'Remove NULLs from the result'
AppPath = Left$(AppPath, InStr(AppPath, vbNullChar) - 1)
WhosYourDaddy = AppPath
Else
WhosYourDaddy = "Not Found"
End If
End Function
Unfortunately, you'll need to have individual On Error GoTo X statements for individual modules and procedures. The project is always stored in Err.Source. The VBA error handling isn't all that great in this area -- after all, how much good does the project name as the source of the error, as opposed to procedure/module, do you.
If you manually or programatically number your lines (like old-school BASIC), you can use ERL to list the line number the error occurred on. Be warned, though, that an error that occurs on a line without a number will make ERL throw its own error, instead of returning a zero. More information can be found at this blog post.
If you're using Access 2007 (not sure about other Office apps/versions), try this code snippet dug out of the help documentation:
Sub PrintOpenModuleNames()
Dim i As Integer
Dim modOpenModules As Modules
Set modOpenModules = Application.Modules
For i = 0 To modOpenModules.Count - 1
Debug.Print modOpenModules(i).Name
Next
End Sub
And Microsoft includes these remarks:
All open modules are included in the
Modules collection, whether they are
uncompiled, are compiled, are in
break mode, or contain the code
that's running.
To determine whether an individual
Module object represents a standard
module or a class module, check the
Module object's Type property.
The Modules collection belongs to the
Microsoft Access Application object.
Individual Module objects in the
Modules collection are indexed
beginning with zero.
So far, I haven't been able to find anything on referencing the current Project or Procedure. but this should point you in the right direction.
I suggest you take a look at CodeSMART for VB6, This VB6 addin has a customizable Error Handling Schemes Manager, with macros that will insert strings for module name, method name, etc., into your error handling code with a single context menu selection.
Has some other very nice features as well - a Find In Files search that's superior to anything I'd seen till ReSharper, a Tab Order designer, and much more.
At my previous employer, we used this tool for many years, starting with the 2005 version. Once you get used to it,it's really hard to do without it.