VC++ solves the problem of full path dll loading failure by viewing the ReactOS open source code (with source code)

content

1. Problem example

2. Go to cmd.exe and use regsvr32 to manually register the control

3. Go to the ReactOS open source code to check the implementation of regsvr32 and find clues to solve the problem

3.1. Introduction to ReactOS open source operating system

3.2. Use Source Insight to open the ReactOS source code and find the code of the regsvr32.exe program

4. Go to Microsoft MSDN to view the meaning of the LOAD_WITH_ALTERED_SEARCH_PATH parameter


       In some cases, we need to call LoadLibrary to dynamically load the dll library to obtain the interface in the dll library. But sometimes the loading fails. Even if the full path of the dll library is passed in, the loading will fail. We have encountered such a problem more than once in the project. Today we will see how to solve this problem.

1. Problem example

       We make the installation package through code, and no longer use packaging tools such as inno setup and installshield . The operations such as file copying, reading and writing the registry, and registering controls in the installation package are all done through code. During a test, it was found that the registration of a control failed. The code for registering the control is as follows:

void RegCtrl( LPCTSTR lpszDllPath )
{
    if ( lpszDllPath == NULL )
    {
        return;
    }

    CString strLog;
    strLog.Format( _T("[RegCtrl] lpszDllPath: %s."), lpszDllPath );
    WriteLog( strLog );

    // 1、先将库动态加载起来
    HINSTANCE hInstance = LoadLibrary( lpszDllPath )
    if ( NULL == hInstance )
    {
        strLog.Format( _T("[RegCtrl] load dll failed, GetLastError: %d."), GetLastError() );
        WriteLog( strLog );
    }

    // 2、获取库中的DllRegisterServer函数接口,调用该接口去完成控件的注册
    typedef HRESULT (*DllRegisterServerFunc)(void);
    DllRegisterServerFunc dllRegisterServerFun = (DllRegisterServerFunc)GetProcAddress( hInstance, "DllRegisterServer" );
    if ( dllRegisterServerFun != NULL )
    {
        HRESULT hr = dllRegisterServerFun();
        strLog.Format( _T("[RegCtrl] DllRegisterServer return: %d"), hr );
        WriteLog( strLog );
    }
    else
    {
        strLog.Format( _T("[RegCtrl] Get DllRegisterServer address failed. GetLastError: %d"), GetLastError() );
        WriteLog( strLog );
    }

    FreeLibrary( hInstance );
}

In the code, load the control dll through the full path of the dll file , then obtain the DllRegisterServer interface in the control dll, and call the DllRegisterServer interface to complete the registration of the control.

        According to the printed log, it failed when calling LoadLibrary to load the control dll library. We passed the full path of the control dll to the LoadLibrary interface, and the control dll file can also be found in this path. This is a bit confusing. Obviously, the full path of the control dll is passed in, and the control dll file also exists in the path. Why does the dll library fail to load? This is a little too weird!

2. Go to cmd.exe and use regsvr32 to manually register the control

       The installation package program could not load the dll library, we thought we could try to go to the cmd window and use regsvr32 to manually register the dll control. Open the cmd window, manually drag the dll file into the cmd window to obtain the path of the dll file, and press the Enter key to register the control: (Here is the ImageOle.dll control of Feiqiu as an example)

regsvr32 "C:\Program Files\feiq\GifDll\ImageOle.dll"

Manual registration can be successfully registered normally. When using regsvr32 to manually register, the system's regsvr32.exe program is called. The regsvr32.exe program should also need to load the control dll file. The regsvr32.exe program can successfully load the library. Could it be that the way the regsvr32.exe program loads the library is different from the way we install the package program?

3. Go to the ReactOS open source code to check the implementation of regsvr32 and find clues to solve the problem

       I have downloaded the source code of the open source operating system ReactOS before . The internal implementation of the system library in ReactOS is very similar to that of Windows, and the provided system API interface is basically the same. We often check the internal implementation of the API functions and underlying libraries in ReactOS to understand the internal implementation of the Windows system to assist in troubleshooting the problems we encountered in the development process.

3.1. Introduction to ReactOS open source operating system

       ReactOS is a free and open source operating system similar to Windows XP system based on Windows NT architecture. It aims to achieve full application and driver device compatibility with NT and Windows operating system binaries. By using similar architecture and providing complete public interface.
       ReactOS has been continuously maintained. You can find the download address of the ReactOS source code on the reactos official website, and use svn to download the ReactOS source code.

       ReactOS open source code is very useful for us Windows software developers. We can view the internal implementation of API functions, the internal implementation of the system exe, and the implementation code of any module inside the ReactOS system. ReactOS is relatively close to the Windows system. You can get a general understanding of the internal implementation of the Windows system by viewing the ReactOS code, which is very beneficial for us to troubleshoot Windows software problems!

3.2. Use Source Insight to open the ReactOS source code and find the code of the regsvr32.exe program

There is no Visual Studio project file        in the ReactOS source code. You cannot use Visual Studio to open and view the source code. You can use Source Insight to view the source code. As for how to use Source Insight , you can refer to an article I wrote about Source Insight before:

Use Source Insight to view and edit the source codehttps : //blog.csdn.net/chenlycly/article/details/124347857Becauseregsvr32 is an independent exe, not a function, you need to find the .c source file corresponding to the program. So I tried to search the file list with regsvr32 as the keyword and found theregsvr32.c file. Find the_tWinMainfunction in the file, and see the code to load the dll library file in the main function, as follows:

In the code, the LoadLibraryEx interface is called to load the dll library, the incoming parameter is LOAD_WITH_ALTERED_SEARCH_PATH , and the DllRegisterServer in the dll control library is also obtained for registration.

        There should be a reason for regsvr32.exe to use this method to load library files, so we also refer to its practice, change the code to load the dll library to call LoadLibraryEx, and pass in LOAD_WITH_ALTERED_SEARCH_PATH, as shown below:

HINSTANCE hInstance = LoadLibraryEx( lpszDllPath, NULL, LOAD_WITH_ALTERED_SEARCH_PATH )
if ( NULL == hInstance )
{
    strLog.Format( _T("[RegCtrl] load dll failed, GetLastError: %d."), GetLastError() );
    WriteLog( strLog );
}

After changing to the above code, the problem of library loading failure no longer occurs. The above code is really useful!

       Later, other modules also encountered the problem of library loading failure, and they were also replaced with the above code. As a result, there was no problem again. This problem of failure to load the library through the absolute path of the library is not a must, it only occurs on individual machines.

4. Go to Microsoft MSDN to view the meaning of the LOAD_WITH_ALTERED_SEARCH_PATH parameter

       In order to understand the meaning of the LOAD_WITH_ALTERED_SEARCH_PATH parameter , we went to the description page of the LoadLibraryEx API function on Microsoft MSDN and found the description of the LOAD_WITH_ALTERED_SEARCH_PATH parameter:

LOAD_WITH_ALTERED_SEARCH_PATH:(0x00000008)

If this value is used and lpFileName specifies an absolute path, the system uses the alternate file search strategy discussed in the Remarks section to find associated executable modules that the specified module causes to be loaded. If this value is used and lpFileName specifies a relative path, the behavior is undefined.
If this value is not used, or if lpFileName does not specify a path, the system uses the standard search strategy discussed in the Remarks section to find associated executable modules that the specified module causes to be loaded.

This value cannot be combined with any LOAD_LIBRARY_SEARCH flag.

From the above description, we know that if the LOAD_WITH_ALTERED_SEARCH_PATH parameter is set, the system will use the alternate file search strategy search strategy. What is this search strategy like?

       Continue to look down on the description page of the LoadLibraryEx function and see the "Dynamic-Link Library Search Order" hyperlink, which is a detailed description page of the dynamic link library loading order. From the page we can see that if the LOAD_WITH_ALTERED_SEARCH_PATH parameter is not set, the Standard Search Order for Desktop Applications standard search order is used :

1、The directory from which the application loaded.
2、The system directory. Use the GetSystemDirectory function to get the path of this directory.
3、The 16-bit system directory. There is no function that obtains the path of this directory, but it is searched.
4、The Windows directory. Use the GetWindowsDirectory function to get the path of this directory.
5、The current directory.
6、The directories that are listed in the PATH environment variable. Note that this does not include the per-application path specified by the App Paths registry key. The App Paths key is not used when computing the DLL search path.

        If the LOAD_WITH_ALTERED_SEARCH_PATH parameter is set, the system uses the Alternate Search Order for Desktop Applications search order :

1、The directory specified by lpFileName.
2、The system directory. Use the GetSystemDirectory function to get the path of this directory.
3、The 16-bit system directory. There is no function that obtains the path of this directory, but it is searched.
4、The Windows directory. Use the GetWindowsDirectory function to get the path of this directory.
5、The current directory.
6、The directories that are listed in the PATH environment variable. Note that this does not include the per-application path specified by the App Paths registry key. The App Paths key is not used when computing the DLL search path.    

So we finally found the answer. When we set the LOAD_WITH_ALTERED_SEARCH_PATH parameter, the Alternate Search Order for Desktop Applications will be used, and the set full path will be used first to load the dll library.

Guess you like

Origin blog.csdn.net/chenlycly/article/details/124360104