【问题标题】:GetComputerName() in Windows 7 on a Mac using VMWare Fails在 Mac 上使用 VMWare 的 Windows 7 中的 GetComputerName() 失败
【发布时间】:2014-06-05 20:11:10
【问题描述】:

带有 VMWare 的 Mac 上的 Windows 7。 GetComputerName 返回 ERROR_BUFFER_OVERFLOW (111),但有效长度为 16 且名称为空。任何想法为什么它会失败?它可以与其他 Windows 仿真一起正常工作。

这是演示失败的控制台应用程序代码:

// GetComputerName.cpp : Defines the entry point for the console application.  
//  

#include "stdafx.h"  

#ifdef _DEBUG  
#define new DEBUG_NEW  
#endif  

#include <string>   // for string  
#include <vector>   // for vector  

using std::vector;  
using std::string;   

#ifdef _UNICODE  
using std::wstring;   
#define string wstring    
using std::wostringstream;  
#define ostringstream wostringstream  
#else  
#endif  

typedef vector<TCHAR> VTChar; // vtc  

CWinApp theApp;  // The one and only application object  
using namespace std;  

int _tmain(int argc, TCHAR* argv[], TCHAR* envp[])  
{  
  TCHAR tcLocalComputerName[MAX_COMPUTERNAME_LENGTH + 1]= {_T('\0')};  
  DWORD dwComputerNameLength(MAX_COMPUTERNAME_LENGTH);  
  if(!::GetComputerName(tcLocalComputerName, &dwComputerNameLength))  
  {  
    string strErrorFormat(_T("GetComputerName failed with %d; returned length was %d."));  
    VTChar vtcError(strErrorFormat.size() + 20, 0);  
    _stprintf_s(&vtcError[0], vtcError.size(), strErrorFormat.c_str(), ::GetLastError(), dwComputerNameLength);  
    AfxMessageBox(&vtcError[0], MB_ICONEXCLAMATION);  
  }    
  else  
  {  
    string strFormat(_T("GetComputerName returned \"%s\""));  
    VTChar vtcError(strFormat.size() + 30, 0);  
    _stprintf_s(&vtcError[0], vtcError.size(), strFormat.c_str(), tcLocalComputerName);  
    AfxMessageBox(&vtcError[0], MB_ICONEXCLAMATION);  
  }  

  return 0;  
}  

一位同事使用它一段时间后发现,如果我们打第二个电话,它就会起作用。正在运行的应用实际上是以一种迂回的方式做到了这一点。

以下是实际运行的控制台应用程序的代码:

// GetComputerName.cpp : Defines the entry point for the console application.  
//  

#include "stdafx.h"  

#ifdef _DEBUG  
#define new DEBUG_NEW  
#endif  

#include <string>   // for string  
#include <vector>   // for vector  

using std::vector;  
using std::string;   

#ifdef _UNICODE  
using std::wstring;   
#define string wstring    
using std::wostringstream;  
#define ostringstream wostringstream  
#else  
#endif  

typedef vector<TCHAR> VTChar; // vtc  

CWinApp theApp;  // The one and only application object  
using namespace std;  

int _tmain(int argc, TCHAR* argv[], TCHAR* envp[])  
{  
  bool gotName(false);  
  TCHAR tcLocalComputerName[MAX_COMPUTERNAME_LENGTH + 1]= {_T('\0')};  
  DWORD dwComputerNameLength(MAX_COMPUTERNAME_LENGTH);  
  if(!::GetComputerName(tcLocalComputerName, &dwComputerNameLength))  
  {  
    AfxMessageBox(_T("First GetComputerName failed."));  
    if(!::GetComputerName(tcLocalComputerName, &dwComputerNameLength))  
    {  
      string strErrorFormat(_T("GetComputerName failed with %d; returned length was %d."));  
      VTChar vtcError(strErrorFormat.size() + 20, 0);  
      _stprintf_s(&vtcError[0], vtcError.size(), strErrorFormat.c_str(), ::GetLastError(), dwComputerNameLength);  
      AfxMessageBox(&vtcError[0], MB_ICONEXCLAMATION);  
    }  
    else  
      gotName= true;
  }    
  else
    gotName= true;  

  if(gotName)    
  {  
    string strFormat(_T("GetComputerName returned \"%s\""));  
    VTChar vtcError(strFormat.size() + 30, 0);  
    _stprintf_s(&vtcError[0], vtcError.size(), strFormat.c_str(), tcLocalComputerName);  
    AfxMessageBox(&vtcError[0], MB_ICONEXCLAMATION);  
  }  

  return 0;  
}  

【问题讨论】:

  • 请提供代码,包括所用变量的声明
  • 这极不可能与 VMware 有任何关系。显示您的代码。
  • 我会尽快发布。我同意它可能不是 VMWare,但代码是可靠的。它适用于各种风格的 Windows(我几年前写的)、运行 VM 的 PC 和 Mac。但是,不同应用程序中的相同代码可以在同一台机器上运行。我怀疑它与应用程序类型有关。 FWIW,“COMPUTERNAME”的 GetEnvironmentVariable 成功,但返回一个空名称。我知道要测试什么。
  • 这台电脑的名字到底是什么?
  • 实际名称为“WIN-N6LLD42BT79”

标签: windows vmware


【解决方案1】:

调试 Windows API 调用时,必须在调用失败后立即调用::GetLastError()

不是这个:

if(!::GetComputerName(tcLocalComputerName, &dwComputerNameLength))  
{  
    string strErrorFormat(_T("GetComputerName failed with %d; returned length was %d."));  
    VTChar vtcError(strErrorFormat.size() + 20, 0);  
    _stprintf_s(&vtcError[0], vtcError.size(), strErrorFormat.c_str(), ::GetLastError(), dwComputerNameLength);  
    AfxMessageBox(&vtcError[0], MB_ICONEXCLAMATION);  
}

但是这个:

if(!::GetComputerName(tcLocalComputerName, &dwComputerNameLength))  
{
    DWORD apiError = ::GetLastError();
    string strErrorFormat(_T("GetComputerName failed with %d; returned length was %d."));  
    VTChar vtcError(strErrorFormat.size() + 20, 0);  
    _stprintf_s(&vtcError[0], vtcError.size(), strErrorFormat.c_str(), apiError, dwComputerNameLength);  
    AfxMessageBox(&vtcError[0], MB_ICONEXCLAMATION);  
}   

像您的示例那样简单地声明一个字符串变量,可以覆盖线程最后错误值。如何?好吧,std::string 动态分配一个缓冲区来保存内容。这种动态分配需要调用分配器,它的内部堆中可能有足够的空间,或者可能需要增加堆。如果需要增加堆,将使用操作系统调用来执行此操作,现在您正在查看来自::VirtualAlloc 而不是::GetComputerName 的最后一个错误值。

【讨论】:

    【解决方案2】:

    解决办法是再次拨打电话。

    以下是实际运行的控制台应用程序的代码:

    // GetComputerName.cpp : Defines the entry point for the console application.  
    //  
    
    #include "stdafx.h"  
    
    #ifdef _DEBUG  
    #define new DEBUG_NEW  
    #endif  
    
    #include <string>   // for string  
    #include <vector>   // for vector  
    
    using std::vector;  
    using std::string;   
    
    #ifdef _UNICODE  
    using std::wstring;   
    #define string wstring    
    using std::wostringstream;  
    #define ostringstream wostringstream  
    #else  
    #endif  
    
    typedef vector<TCHAR> VTChar; // vtc  
    
    CWinApp theApp;  // The one and only application object  
    using namespace std;  
    
    int _tmain(int argc, TCHAR* argv[], TCHAR* envp[])  
    {  
      bool gotName(false);  
      TCHAR tcLocalComputerName[MAX_COMPUTERNAME_LENGTH + 1]= {_T('\0')};  
      DWORD dwComputerNameLength(_countof(tcLocalComputerName));  
      if(!::GetComputerName(tcLocalComputerName, &dwComputerNameLength))  
      {  
        dwComputerNameLength= _countof(tcLocalComputerName);  
        AfxMessageBox(_T("First GetComputerName failed."));  
        if(!::GetComputerName(tcLocalComputerName, &dwComputerNameLength))  
        {  
          DWORD dwLastError(::GetLastError());  
          string strErrorFormat(_T("GetComputerName failed with %d; returned length was %d."));  
          VTChar vtcError(strErrorFormat.size() + 20, 0);  
          _stprintf_s(&vtcError[0], vtcError.size(), strErrorFormat.c_str(), dwLastError, dwComputerNameLength);  
          AfxMessageBox(&vtcError[0], MB_ICONEXCLAMATION);  
        }  
        else  
          gotName= true;
      }    
      else
        gotName= true;  
    
      if(gotName)    
      {  
        string strFormat(_T("GetComputerName returned \"%s\""));  
        VTChar vtcError(strFormat.size() + 30, 0);  
        _stprintf_s(&vtcError[0], vtcError.size(), strFormat.c_str(), tcLocalComputerName);  
        AfxMessageBox(&vtcError[0], MB_ICONEXCLAMATION);  
      }  
    
      return 0;  
    }  
    

    【讨论】:

    • 这应该是对原始问题的修改,而不是单独的答案。
    • @GigaWatt:这是一个低质量的答案,它应该包含更多细节,如代码 sn-p 以及第一次和第二次调用时返回的值。但这是一个答案。
    • @BenVoigt - 我在编辑之前发布了该评论。检查修订历史记录。
    • @GigaWatt:最好在答案中包含“解决方案”代码。以及简要说明。
    • 顺便说一句,这些宏太可怕了。根据 UNICODE 考虑使用typedef std::wstring tstring;typedef std::string tstring;(然后删除using std::string;
    【解决方案3】:

    这是错误的:

    TCHAR tcLocalComputerName[MAX_COMPUTERNAME_LENGTH + 1]= {_T('\0')};  
    DWORD dwComputerNameLength(MAX_COMPUTERNAME_LENGTH);  
    

    documentation for GetComputerName 很清楚:

    lpnSize [输入,输出]

    在输入时,指定缓冲区的大小,以 TCHAR 为单位。

    所以正确的代码是

    TCHAR tcLocalComputerName[MAX_COMPUTERNAME_LENGTH + 1]= {_T('\0')};  
    DWORD dwComputerNameLength(MAX_COMPUTERNAME_LENGTH + 1);  
    

    甚至更好,

    TCHAR tcLocalComputerName[MAX_COMPUTERNAME_LENGTH + 1]= {_T('\0')};  
    DWORD dwComputerNameLength(_countof(tcLocalComputerName));  
    

    【讨论】:

    • 我会看看在这种情况下是否会有所不同。
    猜你喜欢
    • 2014-04-24
    • 2011-11-30
    • 2012-01-16
    • 1970-01-01
    • 1970-01-01
    • 2012-09-16
    • 2012-11-02
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多