I've got simple C++ Windows program that prints stack trace. Tried different codes I found on internet and still getting same results. When optimizations are off, things get displayed correctly. Once I turn them on(or switch from Debug build to Release build in VS), specifically I use /O2(but doesn't work with other optimization flags too), only main function gets printed on screen even though there should be more functions on stack. I thought that maybe that function gets inlined but I think that this isn't the case, I can turn any optimization setting on, like force inline anywhere possible etc. and just works fine, once I turn on /O2, /O1 etc. it shows just main. PDB files are generated so that shouldn't cause any problems.
I'd appreciate any help, or if anyone knows some other way/library to show stack trace.
Output with optimizations off, you can see func2 and func3 displayed correctly:
Line: 78 | Function name: func2 | Module name: D:\ConsoleApplication3\Debug\ConsoleApplication3.exe
Line: 83 | Function name: func3 | Module name: D:\ConsoleApplication3\Debug\ConsoleApplication3.exe
Line: 88 | Function name: main | Module name: D:\ConsoleApplication3\Debug\ConsoleApplication3.exe
Line: 78 | Function name: invoke_main | Module name: D:\ConsoleApplication3\Debug\ConsoleApplication3.exe
Line: 288 | Function name: __scrt_common_main_seh | Module name: D:\ConsoleApplication3\Debug\ConsoleApplication3.exe
Line: 331 | Function name: __scrt_common_main | Module name: D:\ConsoleApplication3\Debug\ConsoleApplication3.exe
Line: 17 | Function name: mainCRTStartup | Module name: D:\ConsoleApplication3\Debug\ConsoleApplication3.exe
Line: 0 | Function name: BaseThreadInitThunk | Module name: C:\WINDOWS\System32\KERNEL32.DLL
Line: 0 | Function name: RtlGetFullPathName_UEx | Module name: C:\WINDOWS\SYSTEM32\ntdll.dll
L
Output with /O2 flag, func2 and func3 are missing:
Line: 88 | Function name: main | Module name: D:\ConsoleApplication3\Release\ConsoleApplication3.exe
Line: 288 | Function name: __scrt_common_main_seh | Module name: D:\ConsoleApplication3\Release\ConsoleApplication3.exe
Line: 0 | Function name: BaseThreadInitThunk | Module name: C:\WINDOWS\System32\KERNEL32.DLL
Line: 0 | Function name: RtlGetFullPathName_UEx | Module name: C:\WINDOWS\SYSTEM32\ntdll.dll
Line: 0 | Function name: RtlGetFullPathName_UEx | Module name: C:\WINDOWS\SYSTEM32\ntdll.dll
This is code I am currently using, this runs only on x86:
#include <windows.h>
#include <iostream>
#include <dbghelp.h>
void stacktrace()
{
DWORD machine = IMAGE_FILE_MACHINE_I386;
HANDLE process = GetCurrentProcess();
HANDLE thread = GetCurrentThread();
CONTEXT context = {};
context.ContextFlags = CONTEXT_FULL;
RtlCaptureContext(&context);
SymInitialize(process, NULL, TRUE);
SymSetOptions(SYMOPT_LOAD_LINES);
STACKFRAME frame = {};
frame.AddrPC.Offset = context.Eip;
frame.AddrPC.Mode = AddrModeFlat;
frame.AddrFrame.Offset = context.Ebp;
frame.AddrFrame.Mode = AddrModeFlat;
frame.AddrStack.Offset = context.Esp;
frame.AddrStack.Mode = AddrModeFlat;
while (StackWalk(machine, process, thread, &frame, &context, NULL, SymFunctionTableAccess, SymGetModuleBase, NULL))
{
DWORD64 functionAddress;
std::string moduleName;
std::string functioName;
std::string file;
unsigned int _line = 0;
functionAddress = frame.AddrPC.Offset;
DWORD moduleBase = SymGetModuleBase(process, frame.AddrPC.Offset);
char moduleBuff[MAX_PATH];
if (moduleBase && GetModuleFileNameA((HINSTANCE)moduleBase, moduleBuff, MAX_PATH))
{
moduleName = moduleBuff;
}
char symbolBuffer[sizeof(IMAGEHLP_SYMBOL) + 255];
PIMAGEHLP_SYMBOL symbol = (PIMAGEHLP_SYMBOL)symbolBuffer;
symbol->SizeOfStruct = (sizeof IMAGEHLP_SYMBOL) + 255;
symbol->MaxNameLength = 254;
if (SymGetSymFromAddr(process, frame.AddrPC.Offset, NULL, symbol))
{
functioName = symbol->Name;
}
DWORD offset = 0;
IMAGEHLP_LINE line;
line.SizeOfStruct = sizeof(IMAGEHLP_LINE);
if (SymGetLineFromAddr(process, frame.AddrPC.Offset, &offset, &line))
{
file = line.FileName;
_line = line.LineNumber;
}
std::cout
<< "Line: " << _line
<< " | Function name: " << functioName
<< " | Module name: " << moduleName
<< std::endl;
}
SymCleanup(process);
}
void func2()
{
stacktrace();
}
void func3()
{
func2();
}
int main()
{
func3();
system("pause");
return 0;
}
Related
I developed an app to push live stream with ffmpeg. When I checked the app with leaks --atExit -- <the app> (I'm on mac), I found some memory leak with AVFormatContext.
The minimized code are provided below:
#include <iostream>
extern "C" {
#include <libavcodec/avcodec.h>
#include <libavformat/avformat.h>
#include <libavdevice/avdevice.h>
}
void foo() {
avdevice_register_all();
AVFormatContext *avInputFormatContext = avformat_alloc_context();
AVInputFormat *avInputFormat = av_find_input_format("avfoundation");
std::cout << "open input" << std::endl;
int ret = avformat_open_input(&avInputFormatContext, "Capture screen 0", avInputFormat, nullptr);
if (ret < 0) { std::cout << "open input failed: " << ret << std::endl; return;}
avformat_close_input(&avInputFormatContext);
}
int main() {
foo();
return 0;
}
The output is
Process: ffmpegtest [87726]
Path: /Users/USER/*/ffmpegtest
Load Address: 0x10a752000
Identifier: ffmpegtest
Version: ???
Code Type: X86-64
Platform: macOS
Parent Process: leaks [87725]
Date/Time: 2021-01-20 15:44:57.533 +0800
Launch Time: 2021-01-20 15:44:55.760 +0800
OS Version: macOS 11.1 (20C69)
Report Version: 7
Analysis Tool: /Applications/Xcode.app/Contents/Developer/usr/bin/leaks
Analysis Tool Version: Xcode 12.3 (12C33)
Physical footprint: 9.9M
Physical footprint (peak): 10.6M
----
leaks Report Version: 4.0
Process 87726: 14143 nodes malloced for 2638 KB
Process 87726: 1 leak for 32 total leaked bytes.
1 (32 bytes) ROOT LEAK: 0x7f8c61e1b040 [32] length: 16 "Capture screen 0"
Did I miss something?
Hello I'm trying to implement simple client/server CORBA app with docker. Here is Print.idl code :
module Test
{
interface Printer
{
void print();
};
};
Here is the client code:
#include <iostream>
#include "PrintC.h"
int main(int argc, char** argv) {
try {
CORBA::ORB_var orb = CORBA::ORB_init(argc, argv);
CORBA::Object_var po = orb->string_to_object("corbaname::nameservice/NameService#test/Printer");
Test::Printer_var p = Test::Printer::_narrow(po.in());
p->print();
orb->destroy();
} catch (CORBA::Exception const& e) {
std::cerr << "CORBA exception raised: " << e._name() << ": " << e._info().c_str() << '\n';
}
return 0;
}
Here is the server code:
#include <iostream>
#include <orbsvcs/CosNamingC.h>
#include "PrintS.h"
class Implement_Printer : public POA_Test::Printer {
public:
void print() {
std:: cout << "Hello World\n";
}
};
int main(int argc, char** argv) {
try {
CORBA::ORB_var orb = CORBA::ORB_init(argc, argv);
CORBA::Object_var object = orb->resolve_initial_references("RootPOA");
PortableServer::POA_var poa = PortableServer::POA::_narrow(object.in());
PortableServer::POAManager_var poa_manager = poa->the_POAManager();
poa_manager->activate();
Implement_Printer p;
Test::Printer_var printer_object = p._this();
object = orb->string_to_object("corbaloc::nameservice/NameService");
CosNaming::NamingContextExt_var naming_context =
CosNaming::NamingContextExt::_narrow(object.in());
CosNaming::Name_var name;
name = naming_context->to_name("test/Printer");
naming_context->rebind(name.in(), printer_object.in());
orb->run();
poa->destroy(1, 1);
orb->destroy();
} catch (CORBA::Exception const& e) {
std::cerr << "CORBA exception raised: " << e;
}
return 0;
}
And here is the docker-compose.yml :
version: '3.2'
services:
serveur:
image: serveur
networks:
- corba
depends_on:
- nameservice
client:
image: client
networks:
- corba
depends_on:
- nameservice
- serveur
nameservice:
image: omninames
networks:
- corba
networks:
corba:
driver: bridge
Here is the log of docker-compose up :
nameservice_1 | omniNames: (0) 2020-06-10 15:47:16.221353: Data file: '/var/lib/omniorb/omninames-13afbf6c0191.dat'.
nameservice_1 | omniNames: (0) 2020-06-10 15:47:16.221588: Starting omniNames for the first time.
nameservice_1 | omniNames: (0) 2020-06-10 15:47:16.222368: Wrote initial data file '/var/lib/omniorb/omninames-13afbf6c0191.dat'.
nameservice_1 | omniNames: (0) 2020-06-10 15:47:16.222446: Read data file '/var/lib/omniorb/omninames-13afbf6c0191.dat' successfully.
nameservice_1 | omniNames: (0) 2020-06-10 15:47:16.222496: Root context is IOR:010000002b00000049444c3a6f6d672e6f72672f436f734e616d696e672f4e616d696e67436f6e746578744578743a312e300000010000000000000070000000010102000e0000003139322e3136382e3230382e3200f90a0b0000004e616d6553657276696365000300000000000000080000000100000000545441010000001c0000000100000001000100010000000100010509010100010000000901010003545441080000008400e15e01000001
nameservice_1 | omniNames: (0) 2020-06-10 15:47:16.222546: Checkpointing Phase 1: Prepare.
nameservice_1 | omniNames: (0) 2020-06-10 15:47:16.222634: Checkpointing Phase 2: Commit.
nameservice_1 | omniNames: (0) 2020-06-10 15:47:16.222783: Checkpointing completed.
serveur_1 | CORBA exception raised: NotFound (IDL:omg.org/CosNaming/NamingContext/NotFound:1.0)
corba_docker_serveur_1 exited with code 139
corba_docker_client_1 exited with code 139
According to the doc the error is due to "The Name or one of its components, could not be found. If this exception is raised because the binding already exists or the binding is of the wrong type, the rest_of_name member of the exception has a length of 1."
This code is inspired of https://github.com/cromo/multicontainer-corba/
Thanks to Wireshark, I have obtained more info about the error.
wireshark
Thus it seems to replace :
name = naming_context->to_name("test/Printer")
by
name = naming_context->to_name("Printer")
works. (Same thing for the client code)
I get a BSOD issue (PAGE_FAULT_IN_NONPAGED_AREA) it only started happening when I added my UNICODE_STRING
The system crash happens after the UNICODE_STRING is set and working after like 10 minutes or so system crashes out of nowhere. Maybe because I overwrite the UNICODE_STRING many times?
The WinDBG says I need to use a probe() so this error doesn't happen.
do I need to use something like? in the callback before the if statement?
ProbeForRead(ProcessName.Buffer, ProcessName.MaximumLength, sizeof(UCHAR));
Here is my MEMORY.DMP
Microsoft (R) Windows Debugger Version 6.12.0002.633 AMD64
Copyright (c) Microsoft Corporation. All rights reserved.
Loading Dump File [C:\Windows\MEMORY.DMP]
Kernel Summary Dump File: Only kernel address space is available
Symbol search path is: *** Invalid ***
****************************************************************************
* Symbol loading may be unreliable without a symbol search path. *
* Use .symfix to have the debugger choose a symbol path. *
* After setting your symbol path, use .reload to refresh symbol locations. *
****************************************************************************
Executable search path is:
*********************************************************************
* Symbols can not be loaded because symbol path is not initialized. *
* *
* The Symbol Path can be set by: *
* using the _NT_SYMBOL_PATH environment variable. *
* using the -y <symbol_path> argument when starting the debugger. *
* using .sympath and .sympath+ *
*********************************************************************
*** ERROR: Symbol file could not be found. Defaulted to export symbols for ntkrnlmp.exe -
Windows 7 Kernel Version 7601 (Service Pack 1) MP (12 procs) Free x64
Product: WinNt, suite: TerminalServer SingleUserTS
Built by: 7601.24545.amd64fre.win7sp1_ldr_escrow.200102-1707
Machine Name:
Kernel base = 0xfffff800`0340a000 PsLoadedModuleList = 0xfffff800`03643c90
Debug session time: Fri Mar 27 07:18:32.627 2020 (UTC - 4:00)
System Uptime: 0 days 1:14:27.811
*********************************************************************
* Symbols can not be loaded because symbol path is not initialized. *
* *
* The Symbol Path can be set by: *
* using the _NT_SYMBOL_PATH environment variable. *
* using the -y <symbol_path> argument when starting the debugger. *
* using .sympath and .sympath+ *
*********************************************************************
*** ERROR: Symbol file could not be found. Defaulted to export symbols for ntkrnlmp.exe -
Loading Kernel Symbols
...............................................................
................................................................
................................................
Loading User Symbols
PEB is paged out (Peb.Ldr = 00000000`fffdf018). Type ".hh dbgerr001" for details
Loading unloaded module list
...........................
ERROR: FindPlugIns 8007007b
*******************************************************************************
* *
* Bugcheck Analysis *
* *
*******************************************************************************
Use !analyze -v to get detailed debugging information.
BugCheck 50, {fffff8a037f2d000, 0, fffff8000348e46a, 0}
***** Kernel symbols are WRONG. Please fix symbols to do analysis.
Probably caused by : Driver.sys ( Driver!ImageLoadCallback+38 )
Followup: MachineOwner
---------
10: kd> !analyze -v
ERROR: FindPlugIns 8007007b
*******************************************************************************
* *
* Bugcheck Analysis *
* *
*******************************************************************************
PAGE_FAULT_IN_NONPAGED_AREA (50)
Invalid system memory was referenced. This cannot be protected by try-except,
it must be protected by a Probe. Typically the address is just plain bad or it
is pointing at freed memory.
Arguments:
Arg1: fffff8a037f2d000, memory referenced.
Arg2: 0000000000000000, value 0 = read operation, 1 = write operation.
Arg3: fffff8000348e46a, If non-zero, the instruction address which referenced the bad memory
address.
Arg4: 0000000000000000, (reserved)
Debugging Details:
------------------
***** Kernel symbols are WRONG. Please fix symbols to do analysis.
ADDITIONAL_DEBUG_TEXT:
Use '!findthebuild' command to search for the target build information.
If the build information is available, run '!findthebuild -s ; .reload' to set symbol path and load symbols.
MODULE_NAME: Driver
FAULTING_MODULE: fffff8000340a000 nt
DEBUG_FLR_IMAGE_TIMESTAMP: 5e7ddfd8
READ_ADDRESS: unable to get nt!MmSpecialPoolStart
unable to get nt!MmSpecialPoolEnd
unable to get nt!MmPoolCodeStart
unable to get nt!MmPoolCodeEnd
fffff8a037f2d000
FAULTING_IP:
nt!wcsstr+56
fffff800`0348e46a 66418b00 mov ax,word ptr [r8]
MM_INTERNAL_CODE: 0
DEFAULT_BUCKET_ID: VISTA_DRIVER_FAULT
BUGCHECK_STR: 0x50
CURRENT_IRQL: 0
LAST_CONTROL_TRANSFER: from fffff800035779b2 to fffff8000349dea0
STACK_TEXT:
fffff880`0a6abf38 fffff800`035779b2 : 00000000`00000050 fffff8a0`37f2d000 00000000`00000000 fffff880`0a6ac090 : nt!KeBugCheckEx
fffff880`0a6abf40 fffff800`034a9fdc : 00000000`00000000 fffff8a0`37f2d000 fffff880`0a6ac000 fffffa80`232cfe28 : nt!PoCallDriver+0x4f52
fffff880`0a6ac090 fffff800`0348e46a : fffff880`0aeaf498 00000000`00000001 00000000`00001810 00000000`0000003d : nt!longjmp+0x3c7c
fffff880`0a6ac228 fffff880`0aeaf498 : 00000000`00000001 00000000`00001810 00000000`0000003d fffff8a0`0e903c00 : nt!wcsstr+0x56
fffff880`0a6ac230 fffff800`0370f3e4 : 00000000`00000001 fffff800`036250d8 fffff800`036250d8 00000000`00000000 : Driver!ImageLoadCallback+0x38 [c:\users\igor\desktop\driver memory editor\driver\driver.c # 499]
fffff880`0a6ac260 fffff800`03839c92 : fffffa80`232cfdd0 fffffa80`1a26b278 fffffa80`20cc59c0 00000000`00000000 : nt!ObDereferenceSecurityDescriptor+0x204
fffff880`0a6ac2c0 fffff800`036fe317 : fffffa80`20cc5980 fffffa80`1a26b060 fffff880`0a6ac570 fffff880`0a6ac568 : nt!IoCreateController+0x2af2
fffff880`0a6ac410 fffff800`036f5aed : ffff845f`00000018 fffffa80`1a26b060 fffff880`0a6ac570 00000000`00000020 : nt!NtOpenThreadTokenEx+0x14b7
fffff880`0a6ac500 fffff800`034abf53 : 00000000`00002760 fffffa80`1efbfb50 00000000`0021ace8 00000000`00000001 : nt!NtMapViewOfSection+0x2bd
fffff880`0a6ac5d0 00000000`779a9a2a : 00000000`00000000 00000000`00000000 00000000`00000000 00000000`00000000 : nt!longjmp+0x5bf3
00000000`0021acc8 fffff800`034a0cc0 : 00000000`00000000 00000000`00000000 00000000`00000000 00000000`00000000 : 0x779a9a2a
fffff880`0a6ac820 00000000`00000000 : 00000000`01190b90 fffff880`0a6acd18 fffff900`c085eee0 00000000`0043e0a0 : nt!KiCpuId+0xa10
STACK_COMMAND: kb
FOLLOWUP_IP:
Driver!ImageLoadCallback+38 [c:\users\igor\desktop\driver memory editor\driver\driver.c # 499]
fffff880`0aeaf498 4885c0 test rax,rax
FAULTING_SOURCE_CODE:
495: //DbgPrintEx(0, 0, "Loaded Name: %ls \n", FullImageName->Buffer);
496: //DbgPrintEx(0, 0, "Loaded To Process: %d \n", ProcessId);
497:
498: // Compare our string to input
> 499: if (ProcessName.Length != 0 && wcsstr(FullImageName->Buffer, ProcessName.Buffer)) {
500: // if it matches
501: DbgPrintEx(0, 0, "Loaded Name: %ls \n", FullImageName->Buffer);
502: DbgPrintEx(0, 0, "Loaded To Process: %d \n", ProcessId);
503:
504: GameBaseAddress = ImageInfo->ImageBase;
SYMBOL_STACK_INDEX: 4
SYMBOL_NAME: Driver!ImageLoadCallback+38
FOLLOWUP_NAME: MachineOwner
IMAGE_NAME: Driver.sys
BUCKET_ID: WRONG_SYMBOLS
Followup: MachineOwner
---------
Source code:
// Request to retrieve the process id of game process, from kernel space
#define IO_SET_PROCESS_NAME_REQUEST CTL_CODE(FILE_DEVICE_UNKNOWN, 0x0703 /* Our Custom Code */, METHOD_BUFFERED, FILE_SPECIAL_ACCESS)
ULONG GameProcessId, GameBaseAddress;
UNICODE_STRING ProcessName;
// set a callback for every PE image loaded to user memory
// then find the base address & game.exe process id using the callback
PLOAD_IMAGE_NOTIFY_ROUTINE ImageLoadCallback(PUNICODE_STRING FullImageName,
HANDLE ProcessId, PIMAGE_INFO ImageInfo)
{
//DbgPrintEx(0, 0, "Loaded Name: %ls \n", FullImageName->Buffer);
//DbgPrintEx(0, 0, "Loaded To Process: %d \n", ProcessId);
// Compare our string to input
if (ProcessName.Length != 0 && wcsstr(FullImageName->Buffer, ProcessName.Buffer)) {
// if it matches
DbgPrintEx(0, 0, "Loaded Name: %ls \n", FullImageName->Buffer);
DbgPrintEx(0, 0, "Loaded To Process: %d \n", ProcessId);
GameBaseAddress = ImageInfo->ImageBase;
GameProcessId = ProcessId;
}
}
//Here is my IOCTL Call Handler
// IOCTL Call Handler function
NTSTATUS IoControl(PDEVICE_OBJECT DeviceObject, PIRP Irp)
{
NTSTATUS Status;
ULONG BytesIO = 0;
PIO_STACK_LOCATION stack = IoGetCurrentIrpStackLocation(Irp);
// Code received from user space
ULONG ControlCode = stack->Parameters.DeviceIoControl.IoControlCode;
if (ControlCode == IO_SET_PROCESS_NAME_REQUEST)
{
ULONG inBufLength = stack->Parameters.DeviceIoControl.InputBufferLength; // Input buffer length
ULONG outBufLength = stack->Parameters.DeviceIoControl.OutputBufferLength; // Output buffer length
if (inBufLength == 0) {
DbgPrint("Invalid Process name size detected\n");
Status = STATUS_INVALID_PARAMETER;
BytesIO = 0;
goto finish;
}
PWSTR processBuffer;
// Allocate the buffer that will contain the string
processBuffer = ExAllocatePoolWithTag(NonPagedPool, stack->Parameters.DeviceIoControl.InputBufferLength+2, '5PWA');
if(processBuffer == NULL){
DbgPrint("Unable to allocate the Process Buffer: not enough memory.\n");
Status = STATUS_INSUFFICIENT_RESOURCES;
BytesIO = 0;
goto finish;
}
// Copy the buffer
RtlCopyBytes((PVOID)processBuffer, Irp->AssociatedIrp.SystemBuffer, stack->Parameters.DeviceIoControl.InputBufferLength);
//RtlMoveMemory((PVOID)processBuffer, Irp->AssociatedIrp.SystemBuffer, stack->Parameters.DeviceIoControl.InputBufferLength);
// Force a \0 at the end of the filename to avoid that malformed strings cause RtlInitUnicodeString to crash the system
((PSHORT)processBuffer)[(stack->Parameters.DeviceIoControl.InputBufferLength+2)/2-1]=0;
// Create the Unicode string
BOOLEAN success = RtlCreateUnicodeString(&ProcessName, processBuffer);
ExFreePool(processBuffer);
if (success) {
DbgPrint("Set New Process to %ws, len=%d\n", ProcessName.Buffer, stack->Parameters.DeviceIoControl.InputBufferLength);
Status = STATUS_SUCCESS;
BytesIO = 0;
} else {
DbgPrint("Failed to allocate Unicode String for Process\n");
Status = STATUS_INSUFFICIENT_RESOURCES;
BytesIO = 0;
}
}
else
{
// if the code is unknown
Status = STATUS_INVALID_PARAMETER;
BytesIO = 0;
}
finish:
// Complete the request
Irp->IoStatus.Status = Status;
Irp->IoStatus.Information = BytesIO;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
return Status;
}
// Driver Entrypoint
NTSTATUS DriverEntry(PDRIVER_OBJECT pDriverObject,
PUNICODE_STRING pRegistryPath)
{
DbgPrintEx(0, 0, "Driver Loaded\n");
PsSetLoadImageNotifyRoutine(ImageLoadCallback);
RtlInitUnicodeString(&dev, deviceNameBuffer);
RtlInitUnicodeString(&dos, deviceSymLinkBuffer);
IoCreateDevice(pDriverObject, 0, &dev, FILE_DEVICE_UNKNOWN, FILE_DEVICE_SECURE_OPEN, FALSE, &pDeviceObject);
IoCreateSymbolicLink(&dos, &dev);
pDriverObject->MajorFunction[IRP_MJ_CREATE] = CreateCall;
pDriverObject->MajorFunction[IRP_MJ_CLOSE] = CloseCall;
pDriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = IoControl;
pDriverObject->DriverUnload = UnloadDriver;
pDeviceObject->Flags |= DO_DIRECT_IO;
pDeviceObject->Flags &= ~DO_DEVICE_INITIALIZING;
return STATUS_SUCCESS;
}
NTSTATUS UnloadDriver(PDRIVER_OBJECT pDriverObject)
{
DbgPrintEx(0, 0, "Unload routine called.\n");
PsRemoveLoadImageNotifyRoutine(ImageLoadCallback);
IoDeleteSymbolicLink(&dos);
IoDeleteDevice(pDriverObject->DeviceObject);
}
NTSTATUS CreateCall(PDEVICE_OBJECT DeviceObject, PIRP irp)
{
irp->IoStatus.Status = STATUS_SUCCESS;
irp->IoStatus.Information = 0;
IoCompleteRequest(irp, IO_NO_INCREMENT);
return STATUS_SUCCESS;
}
NTSTATUS CloseCall(PDEVICE_OBJECT DeviceObject, PIRP irp)
{
irp->IoStatus.Status = STATUS_SUCCESS;
irp->IoStatus.Information = 0;
IoCompleteRequest(irp, IO_NO_INCREMENT);
return STATUS_SUCCESS;
}
I'm trying to create a C++ DLL for use in a VBA program. I'm following this example and had success compiling the example code and using the resulting DLL. However, I needed to add some additional functionality to the DLL so I created a few more functions in the example code and recompiled it. I then made a test program to test my new functions. When I try to call some of the DLL functions from my test project I get linker errors similar to this:
error LNK2019: unresolved external symbol "int __stdcall PWCreateDocument(long,char *,char *)" (?PWCreateDocument##YGHJPAD0#Z) referenced in function _wmain
This error occurs when I call the functions to initialize ProjectWise, CVbaHelperApp::InitInstance(), and my custom function PWCreateDocument.
This error DOES NOT OCCUR when I call PWGetLastErrorMessage(). I am able to access this function from my test program, but not any other functions in the DLL.
I've ruled out any common linker errors such as, misspellings/incorrect types between function header and definition.
I find it strange that I can successfully call PWGetLastErrorMesssage but not any other functions.
Here is the code for my test program vbaHelperTest3.cpp:
#include "stdafx.h"
typedef long LONG;
typedef int BOOL;
int _tmain(int argc, _TCHAR* argv[])
{
char* filePath = "C:\\pwworking\\cemvn\\b2edsjga\\d0572507\\";
char* fileName = "BUMP Imagery 2009.xwms";
LONG projID = 572507;
char* errorMsg;
std::cout << "Hello World" << std::endl;
CVbaHelperApp myApp;
BOOL isInit = myApp.InitInstance();
std::cout << "Is Initialized? " << isInit << std::endl;
errorMsg = PWGetLastErrorMessage();
std::cout << "Error Message: " << errorMsg << std::endl;
BOOL results = PWCreateDocument(projID, filePath, fileName);
std::cout << "PWCreateDocument Result: " << results << std::endl;
return 0;
}
The header stdafx.h includes the header for my DLL, vbaHelper.h. This is the code for vbaHelper.h:
// vbaHelper.h : main header file for the VBAHELPER DLL
//
#include "stdafx.h"
#if !defined(AFX_VBAHELPER_H__3FBDA9E4_EE8B_4AA1_8FD0_21A0A8B6C590__INCLUDED_)
#define AFX_VBAHELPER_H__3FBDA9E4_EE8B_4AA1_8FD0_21A0A8B6C590__INCLUDED_
#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000
#ifndef __AFXWIN_H__
#error include 'stdafx.h' before including this file for PCH
#endif
#include "resource.h" // main symbols
/////////////////////////////////////////////////////////////////////////////
// CVbaHelperApp
// See vbaHelper.cpp for the implementation of this class
//
class CVbaHelperApp : public CWinApp
{
public:
CVbaHelperApp();
// Overrides
// ClassWizard generated virtual function overrides
//{{AFX_VIRTUAL(CVbaHelperApp)
public:
virtual BOOL InitInstance();
virtual int ExitInstance();
//}}AFX_VIRTUAL
//{{AFX_MSG(CVbaHelperApp)
// NOTE - the ClassWizard will add and remove member functions here.
// DO NOT EDIT what you see in these blocks of generated code !
//}}AFX_MSG
DECLARE_MESSAGE_MAP()
};
/////////////////////////////////////////////////////////////////////////////
//{{AFX_INSERT_LOCATION}}
// Microsoft Visual C++ will insert additional declarations immediately before the previous line.
//Function definitions added by me
typedef int BOOL;
typedef long LONG;
LONG __stdcall PWGetDocumentName( LONG , LONG , VOID **);
LONG __stdcall PWGetDocumentIDs( TCHAR **, LONG *, LONG *);
BOOL __stdcall PWCreateDocument( LONG, char*, char*);
char * __stdcall PWGetLastErrorMessage(void);
#endif // !defined(AFX_VBAHELPER_H__3FBDA9E4_EE8B_4AA1_8FD0_21A0A8B6C590__INCLUDED_)
Finaly, here is the code for vbaHelper.cpp, the DLL:
/****************************************************************************
*
* ProjectWise(TM) Software Development Kit
* Sample Application
* Copyright (C) 2003 Bentley Systems, Incorporated
* All Rights Reserved
*
****************************************************************************/
/****************************************************************************
*
* Project Name: VbaHelper
*
* Project Description: This example is used in conjunction with MicroStation's
* VBA to extract a Design file's attributes.
*
* File name: VbaHelper.cpp
*
* File description: Custom Module implementation
*
****************************************************************************/
/*---------------------------------------------------------------------------
Copyright (C) 2003 Bentley Systems, Incorporated
All Rights Reserved
THIS IS AN OPEN SOURCE CODE OF BENTLEY SYSTEMS, INCORPORATED
You have a royalty-free right to use, modify, reproduce and distribute
the Sample Applications (and/or any modified version) in any way you find
useful, provided that you agree that Bentley Systems, Incorporated has no
warranty obligations or liability for any Sample Application files which
are modified.
No guarantees of performance accompany Sample Application, nor is any
responsibility assumed on the part of the author(s). The software has
been tested extensively and every effort has been made to insure its
reliability.
---------------------------------------------------------------------------*/
/****************************************************************************
*
* Include Files
*
****************************************************************************/
#include "stdafx.h"
#include "vbaHelper.h"
#include "aaatypes.h"
#include "aadmsdef.h"
#include "aawddef.h"
#include "aawindef.h"
#include "aaodsdef.h"
#include "stdtypes.h"
#include "aadmsapi.fdf"
#include "aawinapi.fdf"
#include "aawindms.fdf"
#include "aaodsapi.fdf"
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
#define DLLEXPORT __declspec( dllexport )
#define WINAPI __stdcall
//
// Note!
//
// If this DLL is dynamically linked against the MFC
// DLLs, any functions exported from this DLL which
// call into MFC must have the AFX_MANAGE_STATE macro
// added at the very beginning of the function.
//
// For example:
//
// extern "C" BOOL PASCAL EXPORT ExportedFunction()
// {
// AFX_MANAGE_STATE(AfxGetStaticModuleState());
// // normal function body here
// }
//
// It is very important that this macro appear in each
// function, prior to any calls into MFC. This means that
// it must appear as the first statement within the
// function, even before any object variable declarations
// as their constructors may generate calls into the MFC
// DLL.
//
// Please see MFC Technical Notes 33 and 58 for additional
// details.
//
/////////////////////////////////////////////////////////////////////////////
// CVbaHelperApp
BEGIN_MESSAGE_MAP(CVbaHelperApp, CWinApp)
//{{AFX_MSG_MAP(CVbaHelperApp)
// NOTE - the ClassWizard will add and remove mapping macros here.
// DO NOT EDIT what you see in these blocks of generated code!
//}}AFX_MSG_MAP
END_MESSAGE_MAP()
/////////////////////////////////////////////////////////////////////////////
// CVbaHelperApp construction
CVbaHelperApp::CVbaHelperApp()
{
// TODO: add construction code here,
// Place all significant initialization in InitInstance
}
/////////////////////////////////////////////////////////////////////////////
// The one and only CVbaHelperApp object
CVbaHelperApp theApp;
/*----------------------------------------------------------------------+
|
| name mcmMain_GetDocumentIdByFilePath
|
| author BSI 04/2003
|
| Description This function finds document and project
| numbers of the document specified by its path.
|
+----------------------------------------------------------------------*/
extern "C" int mcmMain_GetDocumentIdByFilePath
(
LPWSTR pchFilePath, /* i full file path to search */
long *plProNo, /* o project id */
long *plDocNo /* o document id */
);
/*----------------------------------------------------------------------+
|
| name HooksInitialize
|
| author BSI 04/2003
|
| Description Dll entry function for ProjectWise.
|
+----------------------------------------------------------------------*/
extern "C" LONG HooksInitialize
(
ULONG ulMask, // i Application Mask
LPVOID lpReserved // i Reserved (must be NULL)
)
{
AFX_MANAGE_STATE(AfxGetStaticModuleState());
return IDOK;
}
/*----------------------------------------------------------------------+
|
| name PWGetDocumentName
|
| author BSI 04/2003
|
| Description A function that will populate documentName for the given
| DOCUMENT_ID.
|
| Return SUCCESS - The path and file name of the specified document
| were built successfully.
|
| -1 - Failed to build the path and file name of the
| specified document.
|
+----------------------------------------------------------------------*/
LONG WINAPI PWGetDocumentName
(
LONG PROJECT_ID, /* i Project ID*/
LONG DOCUMENT_ID, /* i Document ID */
VOID **documentName /* o Document Name*/
)
{
BOOL status = FALSE;
TCHAR tempDocName[MAX_STRING];
// Extract the document's name
status = aaApi_GetDocumentFileName (PROJECT_ID, DOCUMENT_ID, tempDocName, MAX_STRING);
_tcscpy ((TCHAR*)(*documentName), tempDocName);
return (status == TRUE ? SUCCESS : -1);
}
/*----------------------------------------------------------------------+
|
| name PWGetDocumentIDs
|
| author BSI 04/2003
|
| Description A function that will return the document's
| Project and Document IDs.
|
| Return SUCCESS or error number
|
+----------------------------------------------------------------------*/
LONG WINAPI PWGetDocumentIDs
(
TCHAR **fileName, /* i Desgin File Name */
LONG *ProjectID, /* o Project ID */
LONG *DocumentID /* o Document ID */
)
{
return mcmMain_GetDocumentIdByFilePath (*fileName, ProjectID, DocumentID);
}
/*----------------------------------------------------------------------+
|
| name convertCharArrayToLPCWSTR
|
| author MY CUSTOM FUNCTION 10/2015
|
| Description Converts regular string to LPCWSTR, which
| is required by projectwise.
|
| Return The converted string.
|
+----------------------------------------------------------------------*/
wchar_t *convertCharArrayToLPCWSTR(const char* charArray)
{
wchar_t * wString=new wchar_t[4096];
MultiByteToWideChar(CP_ACP, 0, charArray, -1, wString, 4096);
return wString;
}
/*----------------------------------------------------------------------+
|
| name PWCreateDocument
|
| author MY CUSTOM FUNCTION 10/2015
|
| Description A function that will create a new document in the
| specified PW project.
|
| Return SUCCESS or error number
|
+----------------------------------------------------------------------*/
BOOL WINAPI PWCreateDocument
(
LONG PROJECT_ID, /* i Project ID*/
char* PATH_NAME, /* path of document */
char* FILE_NAME /* name of document */
)
{
LONG docID = 0L;
//LONG lngAppID = aaApi_GetFExtensionApplication(L"xwms");
LONG lngAppID = aaApi_GetFExtensionApplication(L"pdf");
LONG lngWorkSpaceID = aaApi_GetWorkspaceProfileId(PROJECT_ID, 0);
LPCWSTR _path_name = convertCharArrayToLPCWSTR(PATH_NAME);
LPCWSTR _file_name = convertCharArrayToLPCWSTR(FILE_NAME);
WCHAR strWorkingDir[_MAX_PATH]; // for checked out file locationmemset (strWorkingDir, '\0', _MAX_PATH);
BOOL status = aaApi_CreateDocument(
&docID, //new document's ID
PROJECT_ID, //Passed in project ID
0, //default
0, //default
0, //default
lngAppID, //Applicaiton ID
0, //no department
lngWorkSpaceID, //workspace profile
_path_name, //source file
_file_name, //Name of file in PW, must be the same as Document Name
_file_name, //Document Name
NULL, //Document description
NULL, //Document Version
FALSE, //Specifies that this document is checked out to the user after it is create in PW.
AADMSDOCCREF_DEFAULT, //Checks documentaiton for flags
//_path_name, //location of the file if checked out
strWorkingDir,
_MAX_PATH - 1, //make sure the buffer is large enough
0 //New attribute ID in environment if created
);
//???
//long errorID=aaApi_GetLastErrorID();
//LPCWSTR errorStr = aaApi_GetLastErrorDetail();
return status;
}
/*----------------------------------------------------------------------+
|
| name PWGetLastErrorMessage
|
| author BSI 04/2003
|
| Description A function that will return the last ProjectWise Error
| message.
|
| Return Last Error message.
|
+----------------------------------------------------------------------*/
char * WINAPI PWGetLastErrorMessage
(
void
)
{
char *errorMsg;
TCHAR TerrorMsg [MAX_STRING];
errorMsg = (char *)malloc (sizeof (char) *MAX_STRING);
_tcscpy (TerrorMsg, aaApi_GetLastErrorMessage());
aaApi_UnicodeToAnsiStr (TerrorMsg, errorMsg,MAX_STRING);
return errorMsg;
}
/*----------------------------------------------------------------------+
|
| name PWGetDocumentAttributes
|
| author BSI 04/2003
|
| Description A function that will return the documents attributes.
|
| Return SUCCESS or -1 if error.
|
+----------------------------------------------------------------------*/
LONG WINAPI PWGetDocumentAttributes
(
LONG ProjectID, /* i Project ID */
LONG DocumentID, /* i Document ID */
void **AttributeData /* o Document attributes */
)
{
CString message;
LONG status = SUCCESS;
LONG lEnvId = aaApi_GetEnvId (0);
LONG lTabNo = aaApi_GetEnvNumericProperty (ENV_PROP_TABLEID, 0);
LONG count = -1;
int rowCount = -1;
/* Select environment for given project */
status = aaApi_SelectEnvByProjectId (ProjectID);
if (status == -1 || status == 0)
{
return -1;
}
else
{
// Select the documents Attribute Data
rowCount = aaApi_SelectLinkDataByObject (
lTabNo, /* i Table identifier (required) */
AADMSLDT_DOCUMENT, /* i Reference Item type */
ProjectID, /* i First item identifier */
DocumentID, /* i Second item identifier */
NULL, /* i Where statement (optional) */
&count, /* io Column count in lplColumnIds */
NULL, /* i Columns to fetch (NULL - all) */
0 /* i Flags (AADMSLDSF_XXX) */
);
if (rowCount <= 0)
return -1;
for (int colIndex= 0; colIndex<count; colIndex++)
{
message += aaApi_GetLinkDataColumnStringProperty (LINKDATA_PROP_COLUMN_NAME, colIndex);
message += ": ";
message += aaApi_GetLinkDataColumnValue (0, colIndex);
message +="\n";
}// end for
_tcscpy ((TCHAR*)(*AttributeData), message);
}
return SUCCESS;
}
/*----------------------------------------------------------------------+
|
| name InitInstance
|
| author BSI 04/2003
|
| Description Initialize the PW API
|
| Return Nonzero if initialization is successful; otherwise 0.
|
+----------------------------------------------------------------------*/
BOOL CVbaHelperApp::InitInstance()
{
// Initialize PW
aaApi_Initialize (AAMODULE_ALL);
return CWinApp::InitInstance();
}
/*----------------------------------------------------------------------+
|
| name ExitInstance
|
| author BSI 04/2003
|
| Description Remove the hook function on exit.
|
| Return 0 for success or > 0 for error.
|
+----------------------------------------------------------------------*/
int CVbaHelperApp::ExitInstance()
{
return CWinApp::ExitInstance();
}
Edit Update
I realized that my header file does not need function definitioins. The project uses a vbaHelper.def file to define the functions. I removed the definitions from the header and now have different errors:
error C3861: 'PWGetLastErrorMessage': identifier not found
error C3861: 'PWCreateDocument': identifier not found
Edit Number 2
I do not believe this should qualify as a duplicate of other Unresolved external symbol questions as I have vetted all the common reasons for this error. Also, I have now resolved the linker error and I'm looking for reason why I would be receiving "identifier not found" errors.
You need to append your function definitions with extern "C" if you want to be able to call them from c. You already have such an example in the code that you've posted.
extern "C" LONG HooksInitialize
BOOL WINAPI PWCreateDocument
is should be
BOOL DLLEXPORT PWCreateDocument
I'm following these tutorials on modern OpenGL. I've done them up to number 15 "Camera Control - Part 2". The tutorial suggests using glutWarpPointer(). The problem is, my program crashes at that call. This is my code:
c_camera::c_camera(int width, int height, const c_vector3f& Pos, const c_vector3f& Target, const c_vector3f& Up){
m_windowWidth = width;
m_windowHeight = height;
m_pos = Pos;
m_target = Target;
m_target.Normalize();
m_up = Up;
m_up.Normalize();
Init();
}
void c_camera::Init(){
c_vector3f HTarget(m_target.x, 0.0, m_target.z);
HTarget.Normalize();
if (HTarget.z >= 0.0f){
if (HTarget.x >= 0.0f){
m_AngleH = 360.0f - (asin(HTarget.z) TO_DEG);
} else {
m_AngleH = 180.0f + (asin(HTarget.z) TO_DEG);
}
} else {
if (HTarget.x >= 0.0f){
m_AngleH = (asin(-HTarget.z) TO_DEG);
} else {
m_AngleH = 90.0f + (asin(-HTarget.z) TO_DEG);
}
}
m_AngleV = -(asin(m_target.y) TO_DEG);
m_OnUpperEdge = false;
m_OnLowerEdge = false;
m_OnLeftEdge = false;
m_OnRightEdge = false;
m_mousePos.x = m_windowWidth / 2;
m_mousePos.y = m_windowHeight / 2;
cout << "this gets printed just fine" << endl;
glutWarpPointer(500,400); //program crashes
cout << "this doesn't get printed" << endl;
}
I'm not sure if I'm doing something weird here, or if I just have a bad glut version (seems unlikely to me) or if the tutorial is just wrong... Do I need to set up something glut specific before I can call glutWarpPointer()? I am new to glut, and new to modern OpenGL (I learned immediate mode first).
A quick google search didn't help me much. Any help would be appreciated.
Edit: I am on windows, and I'm using mingw 4.5
Edit2: These are the details windows gives me about the crash:
Problem Event Name: APPCRASH
Application Name: modern_opengl.exe
Application Version: 0.0.0.0
Application Timestamp: 51044575
Fault Module Name: glut32.dll
Fault Module Version: 0.0.0.0
Fault Module Timestamp: 3bea4ff3
Exception Code: c0000005
Exception Offset: 0000a879
OS Version: 6.2.9200.2.0.0.256.48
Locale ID: 1043
Additional Information 1: 5861
Additional Information 2: 5861822e1919d7c014bbb064c64908b2
Additional Information 3: f3d5
Additional Information 4: f3d5be0cad2787556264647dc02181c3
Edit3: This is my call stack:
0 1000A879 glutWarpPointer() (C:\Windows\system\glut32.dll:??)
1 004033FB c_camera::Init(this=0x4aa0e0) (C:\CodeBlocks\projects\modern_opengl\c_camera.cpp:50)
2 00403164 c_camera::c_camera(this=0x4aa0e0, width=800, height=600, Pos=..., Target=..., Up=...) (C:\CodeBlocks\projects\modern_opengl\c_camera.cpp:18)
3 00402F4B __static_initialization_and_destruction_0(__initialize_p=1, __priority=65535) (C:\CodeBlocks\projects\modern_opengl\main.cpp:55)
4 00403004 GLOBAL_sub_I_vertices() (C:\CodeBlocks\projects\modern_opengl\main.cpp:177)
5 0043595B __do_global_ctors() (../mingw/gccmain.c:59)
6 00401098 __mingw_CRTStartup() (../mingw/crt1.c:236)
7 00401284 mainCRTStartup() (../mingw/crt1.c:264)
Your function seems to be in c_camera::Init, which seems to be called before main probably due to it being instantiated as a global object (globals are constructed before main is entered). You should delay glut calls till after you enter main and called glutInit is called.