Convert Drive Letters to UNC
I need to determine any given drive letter's actual location, whether local or mapped. How can I determine whether a simple drive letter is mapped to a network share, and if it is, how can I convert it to Universal Naming Convention (UNC) format?
A.This one's fairly simple. A quick call to the WNetGetConnection API returns the UNC name for any drive letter. However, most drives typically are not mapped, or a network might not even be in place. In these cases, WNetGetConnection returns an appropriate error code.
I've put together a loop that calls a DriveLetterToUNC function on each letter of the alphabet from C to Z (see Listing 1). The DriveLetterToUNC function prepares an adequate buffer by creating a string that's MAX_PATH characters long, then passes this string with the buffer length and drive letter to WNetGetConnection. In case the buffer is too small (it shouldn't be, but better safe than sorry), the routine expands the buffer and makes a second call to WNetGetConnection when ERROR_MORE_DATA is returned from the first.
Your code extracts the UNC name from the buffer by scanning for the first Null character and trimming just before it. For debugging purposes, or just general learning, I've also included a Select Case block that interprets any error codes returned. Remember, an error in this case is the expected behavior for local or otherwise nonmapped drives.
You can also use this routine to determine whether a specific network share is mapped, and if so, to which drive letter. To do this, construct a loop similar to the one in the Form_Click routine, but compare the return from each call to DriveLetterToUNC against the sharename you're seeking. No direct API call is available for this sort of reverse lookup, because it's possible that a user has mapped the same network share to multiple drive letters.
Q. Displaying Old Metafiles
I'm trying to "open" a Windows Metafile (WMF) format in order to get my hands on a metafile handle (hMF), which I can then use to play the metafile into a device context. How do I do this?
I've tried the GetMetaFile API, which returned zero. GetEnhMetaFile also returns zero. Is it possible to convert the old-style WMF to the newer enhanced metafile (EMF)? And, if so, how?
A. Odds are high that the metafiles you're attempting to open use an alternate format known as Adobe Placeable Metafile (APM). Many Windows applications export this variety of metafile because it is an enhancement of sorts over the original WMF format. Adobe defines a header that includes additional hints, such as an optimal reproduction rectangle.
The problem with APM files is that native API functions can't deal with this extra header. This would explain why your call to GetMetaFile failed. GetEnhMetaFile recognizes that the files you're attempting to open aren't the enhanced format, so it fails too.
As a generic approach, the best strategy is to try calling GetEnhMetaFile first (see Figure 1). If this call succeeds, then call GetEnhMetaFileHeader to retrieve the suggested bounding rectangle for display, or use coordinates of your own. The final step is a call to PlayEnhMetaFile, followed by a call to DeleteEnhMetaFile. It's simple and straightforward, as my PaintMetaFile routine shows (see Listing 2).
|Figure 1 Assure Support for All Metafiles.
If the call to GetEnhMetaFile fails, you'll need to branch into a much more complicated series of routines, starting with PlayOldMetafile. In this case, first try calling GetMetaFile, which, as you learned, fails if the APM header precedes the actual WMF data. If GetMetaFile fails, branch to another routine, GetPlaceableMetafile, which manually opens an APM file.
GetPlaceableMetafile works by opening the WMF for binary access, then scanning past the first 22 bytes of the filethe APM header. The next series of bytes comprises the METAHEADER structure. Reading this structure tells you the number of words of actual data that follow (which you can double to get the number of bytes). Allocate a byte array buffer, sized according to the header data; read the remainder of the file into this buffer; and close the file. You can now call SetMetaFileBitsEx to create a memory-based metafile, and return its handle, which other API functions can use.
Returning to the PlayOldMetafile routine, the next task is converting the memory-based metafile into the newer EMF format. Call GetMetaFileBitsEx to determine the size of the buffer required, allocate the buffer, and call this API again to fill the buffer with the raw metafile data. Pass the buffer to SetWinMetaFileBits for conversion from WMF to EMF format. Then you have the handle to the enhanced metafile, and can call PlayEnhMetafile to display it in any device context you choose. Make sure to call DeleteMetaFile or DeleteEnhMetaFile on memory-based metafiles after you're through with them.
Karl E. Peterson is a GIS analyst with a regional transportation planning agency and serves as a member of the Visual Basic Programmer's Journal Technical Review and Editorial Advisory Boards. Online, he's a Microsoft MVP and a section leader for several VBPJ forums. Find more of Karl's VB samples at www.mvps.org/vb.