user-0 提问: WinMain的疑问

回复:
user: user-1
content: 引用 9 楼 六道佩恩 的回复:这个0x00400000我以前也查看过值， windows现在既然这么设计，应该能说明现在在逐渐脱离对实例句柄的使用了吧？我学windows编程几个月了，基本都没用到过实例句柄，一般都是设置的NULL。 也不能这样说，那是你还没涉及到复杂的情况，其实hInstance句柄还是很有用的 比如说上面的用于标识自定义资源的所在位置，还有类所在的空间等  The window class name is not sufficient to identify the class uniquely. Each process has its own window class list, and each entry in the window class list consists of an instance handle and a class name. For example, here's what the window class list might look like if a program has two DLLs, both of which register a class name "MyClass", passing the DLL's handle as the HINSTANCE.      HINSTANCE   Class name 1. USER32.DLL   Static 2. USER32.DLL   Button 3. USER32.DLL   Listbox 4. USER32.DLL   Combobox 5. USER32.DLL   Edit 6. A.DLL             MyClass 7. B.DLL             MyClass  When it comes time to create a window, each module then passes its own HINSTANCE when creating the window, and the window manager uses the combination of the instance handle and the class name to look up the class. CreateWindow("MyClass", ..., hinstA, ...); // creates class 6 CreateWindow("MyClass", ..., hinstB, ...); // creates class 7 CreateWindow("MyClass", ..., hinstC, ...); // fails  This is why it is okay if multiple DLLs all register a class called "MyClass"; the instance handle is used to tell them apart.  There is an exception to the above rule, however. If you pass the CS_GLOBALCLASS flag when registering the class, then the window manager will ignore the instance handle when looking for your class. All of the USER32 classes are registered as global. Consequently, all of the following calls create the USER32 edit control: CreateWindow("edit", ..., hinstA, ...); CreateWindow("edit", ..., hinstB, ...); CreateWindow("edit", ..., hinstC, ...);  If you are registering a class for other modules to use in dialog boxes, you need to register as CS_GLOBALCLASS, because as we saw earlier the internal CreateWindow call performed during dialog box creation to create the controls passes the dialog's HINSTANCE as the HINSTANCE parameter. Since the dialog instance handle is typically the DLL that is creating the dialog (since that same HINSTANCE is used to look up the template), failing to register with the CS_GLOBALCLASS flag means that the window class lookup will not find the class since it's registered under the instance handle of the DLL that provided the class, not the one that is using it.  In 16-bit Windows, the instance handle did other things, too, but they are no longer relevant to Win32.  A common mistake is to pass the HINSTANCE of some other module (typically, the primary executable) when registering a window class. Now that you understand what the HINSTANCE is used for, you should be able to explain the consequences of registering a class with the wrong HINSTANCE.  另外，路径中其实有中文和空格也是可以的，甚至有括号也无妨，加双引号括起来就OK MessageBox(NULL, GetCommandLine(), TEXT("Title"), MB_OK);  例如 "E:\T43\ASM\MASM32\Windows\Windows 核心编程\Windows 核心编程(第5版)\HelloWin\HelloWin.exe" 123 "avbc 123"

user: user-0
content: 引用 8 楼 Intel0011 的回复:https://stackoverflow.com/questions/15462064/hinstance-in-createwindow  I found in MSDN dated from 2001 for CreateWindow and CreateWindowEx  hInstance  Windows 95/98/Me: [in] Handle to the instance of the module to be associated with the window.  Windows NT/2000/XP: This value is ignored.   这是一个实例的句柄，在98等系统下是有不同意义的，而在2000中你会发现它的默认值都是0x00400000 这个0x00400000我以前也查看过值， windows现在既然这么设计，应该能说明现在在逐渐脱离对实例句柄的使用了吧？我学windows编程几个月了，基本都没用到过实例句柄，一般都是设置的NULL。

user: user-1
content: https://stackoverflow.com/questions/15462064/hinstance-in-createwindow  I found in MSDN dated from 2001 for CreateWindow and CreateWindowEx  hInstance  Windows 95/98/Me: [in] Handle to the instance of the module to be associated with the window.  Windows NT/2000/XP: This value is ignored.   这是一个实例的句柄，在98等系统下是有不同意义的，而在2000中你会发现它的默认值都是0x00400000

user: user-1
content: 刚查看了一下MSDN，这个LoadCursor出错方式确实比较奇葩 Remarks The LoadCursor function loads the cursor resource only if it has not been loaded; otherwise, it retrieves the handle to the existing resource. This function returns a valid cursor handle only if the lpCursorName parameter is a pointer to a cursor resource. If lpCursorName is a pointer to any type of resource other than a cursor (such as an icon), the return value is not NULL, even though it is not a valid cursor handle.

user: user-1
content: 引用 2 楼 六道佩恩 的回复:很奇怪，LoadCursor那里，我测试了，结果也一样，按理说不是应该NULL报错吗，怎么用NULL反而正确，用实例句柄反而出问题？包括CreateWindow也是一样，我指定NULL也没有产生错误。这是不是说，现在Windows内部在逐渐脱离对示例句柄的使用？ 这个是没有问题的，给LoadCursor传NULL表示加载系统预先定义图标，传hInstance表示加载自定义的图标，你没有定义图标资源当然报错。对于CreateWindow，现在版本的Windows确实是对hInstance变为可选的参数了，可以不用传hInstance 另外，含空格和中文字符的路径确实比较容易出现问题

user: user-0
content: 引用 4 楼 轻箬笠 的回复:看楼主这路径，有没有可能是中文的问题。我测试的时候，没碰到路径只有一半的问题 一语惊醒梦中人！感谢！

user: user-2
content: 看楼主这路径，有没有可能是中文的问题。我测试的时候，没碰到路径只有一半的问题

user: user-0
content: 引用 1 楼 Intel0011 的回复://第三问：目前没发现你说的问题，只是要注意，如果路径中含有空格需要使用双引号将之括起来 你看看我的测试结果：  我最开始也是以为有空格，但你看第二行GetCommandLine的结果，是没有空格的，实际上也确实没有空格。我还把代码文件放不同地方测试，都有这种问题，放桌面甚至什么都不显示。

user: user-0
content: 引用 1 楼 Intel0011 的回复://* #define UNICODE #define _UNICODE //*/ #include <Windows.h> #include <tchar.h> #include <stdio.h>  #pragma comment(lib, "gdi32") #pragma comment(lib, "user32")  #pragma comment(linker, "/subsystem:windows,5.1.2600")  LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);  int WINAPI _tWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPTSTR szCmdLine, int iCmdShow) {    static TCHAR szAppName[] = TEXT("HelloWin");    HWND         hwnd;    MSG          msg;    WNDCLASS     wndclass;        //*    {       TCHAR str[MAX_PATH];       //wsprintf(str, TEXT("%d"), Number_Object);       //第一问：下面的结果表明hPrevInstance确实已经不使用了       //其实hPrevInstance是Win16下的产物，之所以现在还保留是因为将Win16程序迁移到Win32时不必修改Win16的代码       //如果Win32模型中去掉hPrevInstance，则将Win16程序迁移到Win32时将修改大量已存在的Win16代码       _stprintf(str, TEXT("%p %p"), hInstance, hPrevInstance); // hInstance:00400000 hPrevInstance:00000000       MessageBox(GetActiveWindow(), str, TEXT("Test"), MB_OK);    }    //*/     RtlZeroMemory(&wndclass, sizeof(wndclass));    wndclass.style         = CS_HREDRAW | CS_VREDRAW;    wndclass.lpfnWndProc   = WndProc;    wndclass.hInstance     = hInstance;    wndclass.hIcon         = LoadIcon(NULL, TEXT("#32512"));        SetLastError(0);    //第二问：hInstance还是有用的    wndclass.hCursor       = LoadCursor(NULL, IDC_ARROW); // GetLastError:0(操作成功完成), wndclass.hCursor:00010003    //wndclass.hCursor       = LoadCursor(hInstance, IDC_ARROW); // GetLastError:1812(指定的映像文件不包含资源区域), wndclass.hCursor:00000000    //*    {       TCHAR str[MAX_PATH];       wsprintf(str, TEXT("%u %p"), GetLastError(), wndclass.hCursor);       MessageBox(GetActiveWindow(), str, TEXT("Test"), MB_OK);    }    //*/    wndclass.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);    wndclass.lpszMenuName  = NULL;    wndclass.lpszClassName = szAppName;        //第三问：目前没发现你说的问题，只是要注意，如果路径中含有空格需要使用双引号将之括起来    //*    {       TCHAR str[MAX_PATH];       wsprintf(str, TEXT("%s"), szCmdLine);       MessageBox(GetActiveWindow(), str, TEXT("Test"), MB_OK);    }    //*/     if (!RegisterClass(&wndclass))    {       MessageBox(NULL, TEXT("This program requires Windows NT series!"), szAppName, MB_ICONERROR);       return -1;    }          hwnd = CreateWindowEx(WS_EX_APPWINDOW,         // A tool window does not appear in the task bar or in the window that appears when the user presses ALT+TAB.                          szAppName,                  // window class name                          TEXT("The Hello Program"),  // window caption                          WS_OVERLAPPEDWINDOW,        // window style                          500,//CW_USEDEFAULT,              // initial x position                          200,//CW_USEDEFAULT,              // initial y position                          320,//CW_USEDEFAULT,              // initial x size                          320,//CW_USEDEFAULT,              // initial y size                          NULL,                       // parent window handle                          NULL,                       // window menu handle                          hInstance,                  // program instance handle                          NULL);                      // creation parameters     //第四问：第四个参数是另一个程序运行此程序时给这个程序制定的显示状态吗？ --> 是的，你可以为你写的程序建立一个快捷方式，然后右键单击快捷方式，在运行方式项选择"常规窗口"、"最小化"、"最大化"看看运行结果即可    //第四个参数传给ShowWindow    ShowWindow(hwnd, iCmdShow);    UpdateWindow(hwnd);        {       BOOL bRet;       while ((bRet = GetMessage(&msg, NULL, 0, 0)) != 0)       {          if (bRet == -1)          {             MessageBox(NULL, TEXT("GetMessage Error."), TEXT("Message"), MB_ICONERROR);             return -1;          }          else          {             TranslateMessage(&msg);             DispatchMessage(&msg);          }       }    }        return msg.wParam; }  LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) {      switch (message)    {       case WM_DESTROY:          PostQuitMessage(0);          return 0;    }    return DefWindowProc(hwnd, message, wParam, lParam); }  很奇怪，LoadCursor那里，我测试了，结果也一样，按理说不是应该NULL报错吗，怎么用NULL反而正确，用实例句柄反而出问题？包括CreateWindow也是一样，我指定NULL也没有产生错误。这是不是说，现在Windows内部在逐渐脱离对示例句柄的使用？

user: user-1
content: //* #define UNICODE #define _UNICODE //*/ #include <Windows.h> #include <tchar.h> #include <stdio.h>  #pragma comment(lib, "gdi32") #pragma comment(lib, "user32")  #pragma comment(linker, "/subsystem:windows,5.1.2600")  LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);  int WINAPI _tWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPTSTR szCmdLine, int iCmdShow) {    static TCHAR szAppName[] = TEXT("HelloWin");    HWND         hwnd;    MSG          msg;    WNDCLASS     wndclass;        //*    {       TCHAR str[MAX_PATH];       //wsprintf(str, TEXT("%d"), Number_Object);       //第一问：下面的结果表明hPrevInstance确实已经不使用了       //其实hPrevInstance是Win16下的产物，之所以现在还保留是因为将Win16程序迁移到Win32时不必修改Win16的代码       //如果Win32模型中去掉hPrevInstance，则将Win16程序迁移到Win32时将修改大量已存在的Win16代码       _stprintf(str, TEXT("%p %p"), hInstance, hPrevInstance); // hInstance:00400000 hPrevInstance:00000000       MessageBox(GetActiveWindow(), str, TEXT("Test"), MB_OK);    }    //*/     RtlZeroMemory(&wndclass, sizeof(wndclass));    wndclass.style         = CS_HREDRAW | CS_VREDRAW;    wndclass.lpfnWndProc   = WndProc;    wndclass.hInstance     = hInstance;    wndclass.hIcon         = LoadIcon(NULL, TEXT("#32512"));        SetLastError(0);    //第二问：hInstance还是有用的    wndclass.hCursor       = LoadCursor(NULL, IDC_ARROW); // GetLastError:0(操作成功完成), wndclass.hCursor:00010003    //wndclass.hCursor       = LoadCursor(hInstance, IDC_ARROW); // GetLastError:1812(指定的映像文件不包含资源区域), wndclass.hCursor:00000000    //*    {       TCHAR str[MAX_PATH];       wsprintf(str, TEXT("%u %p"), GetLastError(), wndclass.hCursor);       MessageBox(GetActiveWindow(), str, TEXT("Test"), MB_OK);    }    //*/    wndclass.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);    wndclass.lpszMenuName  = NULL;    wndclass.lpszClassName = szAppName;        //第三问：目前没发现你说的问题，只是要注意，如果路径中含有空格需要使用双引号将之括起来    //*    {       TCHAR str[MAX_PATH];       wsprintf(str, TEXT("%s"), szCmdLine);       MessageBox(GetActiveWindow(), str, TEXT("Test"), MB_OK);    }    //*/     if (!RegisterClass(&wndclass))    {       MessageBox(NULL, TEXT("This program requires Windows NT series!"), szAppName, MB_ICONERROR);       return -1;    }          hwnd = CreateWindowEx(WS_EX_APPWINDOW,         // A tool window does not appear in the task bar or in the window that appears when the user presses ALT+TAB.                          szAppName,                  // window class name                          TEXT("The Hello Program"),  // window caption                          WS_OVERLAPPEDWINDOW,        // window style                          500,//CW_USEDEFAULT,              // initial x position                          200,//CW_USEDEFAULT,              // initial y position                          320,//CW_USEDEFAULT,              // initial x size                          320,//CW_USEDEFAULT,              // initial y size                          NULL,                       // parent window handle                          NULL,                       // window menu handle                          hInstance,                  // program instance handle                          NULL);                      // creation parameters     //第四问：第四个参数是另一个程序运行此程序时给这个程序制定的显示状态吗？ --> 是的，你可以为你写的程序建立一个快捷方式，然后右键单击快捷方式，在运行方式项选择"常规窗口"、"最小化"、"最大化"看看运行结果即可    //第四个参数传给ShowWindow    ShowWindow(hwnd, iCmdShow);    UpdateWindow(hwnd);        {       BOOL bRet;       while ((bRet = GetMessage(&msg, NULL, 0, 0)) != 0)       {          if (bRet == -1)          {             MessageBox(NULL, TEXT("GetMessage Error."), TEXT("Message"), MB_ICONERROR);             return -1;          }          else          {             TranslateMessage(&msg);             DispatchMessage(&msg);          }       }    }        return msg.wParam; }  LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) {      switch (message)    {       case WM_DESTROY:          PostQuitMessage(0);          return 0;    }    return DefWindowProc(hwnd, message, wParam, lParam); }